aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2015-09-23 06:06:30 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-09-24 06:07:00 -0400
commit274e91b81ed22957b510ad2988359584eea95dae (patch)
treec49fc7443c419eb89925db93503db21f8d09a2b7
parent208473c1f3ac3eccec097021eec3890f5e20fcc7 (diff)
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 <net147@gmail.com> Tested-by: Jonathan Liu <net147@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mm/alignment.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 9769f1eefe3b..00b7f7de28a1 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -365,15 +365,21 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
365 user: 365 user:
366 if (LDST_L_BIT(instr)) { 366 if (LDST_L_BIT(instr)) {
367 unsigned long val; 367 unsigned long val;
368 unsigned int __ua_flags = uaccess_save_and_enable();
369
368 get16t_unaligned_check(val, addr); 370 get16t_unaligned_check(val, addr);
371 uaccess_restore(__ua_flags);
369 372
370 /* signed half-word? */ 373 /* signed half-word? */
371 if (instr & 0x40) 374 if (instr & 0x40)
372 val = (signed long)((signed short) val); 375 val = (signed long)((signed short) val);
373 376
374 regs->uregs[rd] = val; 377 regs->uregs[rd] = val;
375 } else 378 } else {
379 unsigned int __ua_flags = uaccess_save_and_enable();
376 put16t_unaligned_check(regs->uregs[rd], addr); 380 put16t_unaligned_check(regs->uregs[rd], addr);
381 uaccess_restore(__ua_flags);
382 }
377 383
378 return TYPE_LDST; 384 return TYPE_LDST;
379 385
@@ -420,14 +426,21 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
420 426
421 user: 427 user:
422 if (load) { 428 if (load) {
423 unsigned long val; 429 unsigned long val, val2;
430 unsigned int __ua_flags = uaccess_save_and_enable();
431
424 get32t_unaligned_check(val, addr); 432 get32t_unaligned_check(val, addr);
433 get32t_unaligned_check(val2, addr + 4);
434
435 uaccess_restore(__ua_flags);
436
425 regs->uregs[rd] = val; 437 regs->uregs[rd] = val;
426 get32t_unaligned_check(val, addr + 4); 438 regs->uregs[rd2] = val2;
427 regs->uregs[rd2] = val;
428 } else { 439 } else {
440 unsigned int __ua_flags = uaccess_save_and_enable();
429 put32t_unaligned_check(regs->uregs[rd], addr); 441 put32t_unaligned_check(regs->uregs[rd], addr);
430 put32t_unaligned_check(regs->uregs[rd2], addr + 4); 442 put32t_unaligned_check(regs->uregs[rd2], addr + 4);
443 uaccess_restore(__ua_flags);
431 } 444 }
432 445
433 return TYPE_LDST; 446 return TYPE_LDST;
@@ -458,10 +471,15 @@ do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *reg
458 trans: 471 trans:
459 if (LDST_L_BIT(instr)) { 472 if (LDST_L_BIT(instr)) {
460 unsigned int val; 473 unsigned int val;
474 unsigned int __ua_flags = uaccess_save_and_enable();
461 get32t_unaligned_check(val, addr); 475 get32t_unaligned_check(val, addr);
476 uaccess_restore(__ua_flags);
462 regs->uregs[rd] = val; 477 regs->uregs[rd] = val;
463 } else 478 } else {
479 unsigned int __ua_flags = uaccess_save_and_enable();
464 put32t_unaligned_check(regs->uregs[rd], addr); 480 put32t_unaligned_check(regs->uregs[rd], addr);
481 uaccess_restore(__ua_flags);
482 }
465 return TYPE_LDST; 483 return TYPE_LDST;
466 484
467 fault: 485 fault:
@@ -531,6 +549,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
531#endif 549#endif
532 550
533 if (user_mode(regs)) { 551 if (user_mode(regs)) {
552 unsigned int __ua_flags = uaccess_save_and_enable();
534 for (regbits = REGMASK_BITS(instr), rd = 0; regbits; 553 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
535 regbits >>= 1, rd += 1) 554 regbits >>= 1, rd += 1)
536 if (regbits & 1) { 555 if (regbits & 1) {
@@ -542,6 +561,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg
542 put32t_unaligned_check(regs->uregs[rd], eaddr); 561 put32t_unaligned_check(regs->uregs[rd], eaddr);
543 eaddr += 4; 562 eaddr += 4;
544 } 563 }
564 uaccess_restore(__ua_flags);
545 } else { 565 } else {
546 for (regbits = REGMASK_BITS(instr), rd = 0; regbits; 566 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
547 regbits >>= 1, rd += 1) 567 regbits >>= 1, rd += 1)