3

I am getting a crash on insmod of WIFI Marvell pcie drivers. i am running WIFI drivers on ARCH=arc OS=linux and little endian. crash back-trace says misaligned address access lead to crash. I have done some investigation and found the place of crash, below is the code snippet.

case NullPktPeriod_i:
        /** keep alive null data pkt interval in full power mode */
        psnmp_mib->oid = wlan_cpu_to_le16((t_u16)NullPktPeriod_i);
        if (cmd_action == HostCmd_ACT_GEN_SET) {
            psnmp_mib->query_type =
                wlan_cpu_to_le16(HostCmd_ACT_GEN_SET);
            psnmp_mib->buf_size = wlan_cpu_to_le16(sizeof(t_u32));
            ul_temp = *((t_u32 *)pdata_buf);
            *((t_u32 *)(psnmp_mib->value)) =
                wlan_cpu_to_le32((t_u32)ul_temp);
            cmd->size += sizeof(t_u32);
        }
        break;

crash is at line *((t_u32 *)(psnmp_mib->value)) = wlan_cpu_to_le32((t_u32)ul_temp); because psnmp_mib->value is unsigned char and typecast'd to unsigned long int. But the value we are assigning from pdata_buf is 1 byte value only ul_temp = *((t_u32 *)pdata_buf);.

The strange behavior is, if I initialize the ul_temp (unsigned long int variable) to zero (any value) and if I run, crash is not seen. but PCI command timeout happens for getting the get_hardware_spec command and kernel hangs.

I have no clue to fix this issue. Please provide some inputs to move further.

Blow is my crash logs,

[   29.920000] Path: (null)
[   29.930000] CPU: 0 PID: 1047 Comm: kworker/u3:1 Tainted: P           O 3.12.0 #103
[   29.930000] Workqueue: MOAL_WORK_QUEUE woal_main_work_queue [pcie8xxx]
[   29.940000] task: 9f0e02c0 ti: 9d192000 task.ti: 9d192000
[   29.940000]
[ECR   ]: 0x00230400 => Misaligned r/w from 0x9d451072
[   29.950000] [EFA   ]: 0x9d451072
[   29.950000] [BLINK ]: wlan_prepare_cmd+0x1be/0x478 [mlan]
[   29.950000] [ERET  ]: wlan_ops_sta_prepare_cmd+0x1fe0/0x37dc [mlan]
[   29.950000] [STAT32]: 0x00000a06 :          E2 E1
[   29.970000] BTA: 0x78571ccc   SP: 0x9d193c34  FP: 0x00000000
[   29.980000] LPS: 0x982de26c  LPE: 0x982de270 LPC: 0x00000000
[   29.980000] r00: 0x00000000  r01: 0x00000016 r02: 0x00000012
r03: 0x0000001e r04: 0x00000000 r05: 0x9d193cb4
r06: 0x9d451064 r07: 0x7857129c r08: 0xfffffffe
r09: 0x00000000 r10: 0x000004cf r11: 0x00000002
r12: 0x00000000
[   29.990000]
[   29.990000] Stack Trace:

Please help.

jww
  • 97,681
  • 90
  • 411
  • 885
shiva
  • 85
  • 7
  • *"I have no clue to fix this issue..."* - You are probably going to have to take this to a kernel mailing list to get it fixed. [Linux Kernel Newbies](https://kernelnewbies.org/) is a great place because kernel devs hang there and are relatively gentle. The site also has a section on [Found a Bug](https://kernelnewbies.org/FoundBug). Your next step is probably to report it on the proper mailing list. – jww Oct 19 '17 at 07:22

1 Answers1

3

Simple. Just do the right thing. In general case, one would use memcpy:

t_u32 value = wlan_cpu_to_le32((t_u32)ul_temp);
memcpy(psnmp_mib->value, &value, sizeof (t_u32));

As pointed out by 0andriy, the put_unaligned could be used here:

put_unaligned(wlan_cpu_to_le32((t_u32)ul_temp), (t_u32*)psnmp_mib->value);

However this is very worrisome because the C standard does state that the behaviour is undefined when:

Conversion between two pointer types produces a result that is incorrectly aligned (6.3.2.3).

Thus even the mere presence of the cast (t_u32*) can lead to the compiler to "realize" that the pointer psnmp_mib->value is aligned to the alignment requirement of t_u32 anyway.


Unaligned access - or even casting pointers to unaligned structures - has undefined behaviour even on platforms that "supposedly" allow unaligned access "everywhere".