Skip to content

Commit 274e91b

Browse files
author
Russell King
committed
ARM: alignment: fix alignment handling for uaccess changes
Jonathan Liu reports that the recent addition of CPU_SW_DOMAIN_PAN causes wpa_supplicant to die due to the following kernel oops: Unhandled fault: page domain fault (0x81b) at 0x001017a2 pgd = ee1b8000 [001017a2] *pgd=6ebee831, *pte=6c35475f, *ppte=6c354c7f Internal error: : 81b [#1] SMP ARM Modules linked in: rt2800usb rt2x00usb rt2800librt2x00lib crc_ccitt mac80211 CPU: 1 PID: 202 Comm: wpa_supplicant Not tainted 4.3.0-rc2 #1 Hardware name: Allwinner sun7i (A20) Family task: ec872f80 ti: ee364000 task.ti: ee364000 PC is at do_alignment_ldmstm+0x1d4/0x238 LR is at 0x0 pc : [<c001d1d8>] lr : [<00000000>] psr: 600c0113 sp : ee365e18 ip : 00000000 fp : 00000002 r10: 001017a2 r9 : 00000002 r8 : 001017aa r7 : ee365fb0 r6 : e8820018 r5 : 001017a2 r4 : 00000003 r3 : d49e30e0 r2 : 00000000 r1 : ee365fbc r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none[ 34.393106] Control: 10c5387d Table: 6e1b806a DAC: 00000051 Process wpa_supplicant (pid: 202, stack limit = 0xee364210) Stack: (0xee365e18 to 0xee366000) ... [<c001d1d8>] (do_alignment_ldmstm) from [<c001d510>] (do_alignment+0x1f0/0x904) [<c001d510>] (do_alignment) from [<c00092a0>] (do_DataAbort+0x38/0xb4) [<c00092a0>] (do_DataAbort) from [<c0013d7c>] (__dabt_usr+0x3c/0x40) Exception stack(0xee365fb0 to 0xee365ff8) 5fa0: 00000000 56c728c0 001017a2 d49e30e0 5fc0: 775448d2 597d4e74 00200800 7a9e1625 00802001 00000021 b6deec84 00000100 5fe0: 08020200 be9f4f20 0c0b0d0a b6d9b3e0 600c0010 ffffffff Code: e1a0a005 e1a0000c 1affffe8 e5913000 (e4ea3001) ---[ end trace 0acd3882fcfdf9dd ]--- This is caused by the alignment handler not being fixed up for the uaccess changes, and userspace issuing an unaligned LDM instruction. So, fix the problem by adding the necessary fixups. Reported-by: Jonathan Liu <[email protected]> Tested-by: Jonathan Liu <[email protected]> Signed-off-by: Russell King <[email protected]>
1 parent 208473c commit 274e91b

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

arch/arm/mm/alignment.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,21 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
365365
user:
366366
if (LDST_L_BIT(instr)) {
367367
unsigned long val;
368+
unsigned int __ua_flags = uaccess_save_and_enable();
369+
368370
get16t_unaligned_check(val, addr);
371+
uaccess_restore(__ua_flags);
369372

370373
/* signed half-word? */
371374
if (instr & 0x40)
372375
val = (signed long)((signed short) val);
373376

374377
regs->uregs[rd] = val;
375-
} else
378+
} else {
379+
unsigned int __ua_flags = uaccess_save_and_enable();
376380
put16t_unaligned_check(regs->uregs[rd], addr);
381+
uaccess_restore(__ua_flags);
382+
}
377383

378384
return TYPE_LDST;
379385

@@ -420,14 +426,21 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
420426

421427
user:
422428
if (load) {
423-
unsigned long val;
429+
unsigned long val, val2;
430+
unsigned int __ua_flags = uaccess_save_and_enable();
431+
424432
get32t_unaligned_check(val, addr);
433+
get32t_unaligned_check(val2, addr + 4);
434+
435+
uaccess_restore(__ua_flags);
436+
425437
regs->uregs[rd] = val;
426-
get32t_unaligned_check(val, addr + 4);
427-
regs->uregs[rd2] = val;
438+
regs->uregs[rd2] = val2;
428439
} else {
440+
unsigned int __ua_flags = uaccess_save_and_enable();
429441
put32t_unaligned_check(regs->uregs[rd], addr);
430442
put32t_unaligned_check(regs->uregs[rd2], addr + 4);
443+
uaccess_restore(__ua_flags);
431444
}
432445

433446
return TYPE_LDST;
@@ -458,10 +471,15 @@ do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *reg
458471
trans:
459472
if (LDST_L_BIT(instr)) {
460473
unsigned int val;
474+
unsigned int __ua_flags = uaccess_save_and_enable();
461475
get32t_unaligned_check(val, addr);
476+
uaccess_restore(__ua_flags);
462477
regs->uregs[rd] = val;
463-
} else
478+
} else {
479+
unsigned int __ua_flags = uaccess_save_and_enable();
464480
put32t_unaligned_check(regs->uregs[rd], addr);
481+
uaccess_restore(__ua_flags);
482+
}
465483
return TYPE_LDST;
466484

467485
fault:
@@ -531,6 +549,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
531549
#endif
532550

533551
if (user_mode(regs)) {
552+
unsigned int __ua_flags = uaccess_save_and_enable();
534553
for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
535554
regbits >>= 1, rd += 1)
536555
if (regbits & 1) {
@@ -542,6 +561,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
542561
put32t_unaligned_check(regs->uregs[rd], eaddr);
543562
eaddr += 4;
544563
}
564+
uaccess_restore(__ua_flags);
545565
} else {
546566
for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
547567
regbits >>= 1, rd += 1)

0 commit comments

Comments
 (0)