diff options
author | Will Deacon <will.deacon@arm.com> | 2014-09-29 06:44:01 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2014-11-14 05:42:15 -0500 |
commit | d54e81f9af1d106e47ae8594903c43a80dae1a99 (patch) | |
tree | e3084f896a27a4658a718643a589169c51f0aa27 | |
parent | 44b82b7700d05a52cd983799d3ecde1a976b3bed (diff) |
arm64: entry: avoid writing lr explicitly for constructing return paths
Using an explicit adr instruction to set the link register to point at
ret_fast_syscall/ret_to_user can defeat branch and return stack predictors.
Instead, use the standard calling instructions (bl, blr) and have an
unconditional branch as the following instruction.
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm64/kernel/entry.S | 45 |
1 files changed, 25 insertions, 20 deletions
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 726b910fe6ec..2cebe56d650c 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S | |||
@@ -455,8 +455,8 @@ el0_da: | |||
455 | bic x0, x26, #(0xff << 56) | 455 | bic x0, x26, #(0xff << 56) |
456 | mov x1, x25 | 456 | mov x1, x25 |
457 | mov x2, sp | 457 | mov x2, sp |
458 | adr lr, ret_to_user | 458 | bl do_mem_abort |
459 | b do_mem_abort | 459 | b ret_to_user |
460 | el0_ia: | 460 | el0_ia: |
461 | /* | 461 | /* |
462 | * Instruction abort handling | 462 | * Instruction abort handling |
@@ -468,8 +468,8 @@ el0_ia: | |||
468 | mov x0, x26 | 468 | mov x0, x26 |
469 | orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts | 469 | orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts |
470 | mov x2, sp | 470 | mov x2, sp |
471 | adr lr, ret_to_user | 471 | bl do_mem_abort |
472 | b do_mem_abort | 472 | b ret_to_user |
473 | el0_fpsimd_acc: | 473 | el0_fpsimd_acc: |
474 | /* | 474 | /* |
475 | * Floating Point or Advanced SIMD access | 475 | * Floating Point or Advanced SIMD access |
@@ -478,8 +478,8 @@ el0_fpsimd_acc: | |||
478 | ct_user_exit | 478 | ct_user_exit |
479 | mov x0, x25 | 479 | mov x0, x25 |
480 | mov x1, sp | 480 | mov x1, sp |
481 | adr lr, ret_to_user | 481 | bl do_fpsimd_acc |
482 | b do_fpsimd_acc | 482 | b ret_to_user |
483 | el0_fpsimd_exc: | 483 | el0_fpsimd_exc: |
484 | /* | 484 | /* |
485 | * Floating Point or Advanced SIMD exception | 485 | * Floating Point or Advanced SIMD exception |
@@ -488,8 +488,8 @@ el0_fpsimd_exc: | |||
488 | ct_user_exit | 488 | ct_user_exit |
489 | mov x0, x25 | 489 | mov x0, x25 |
490 | mov x1, sp | 490 | mov x1, sp |
491 | adr lr, ret_to_user | 491 | bl do_fpsimd_exc |
492 | b do_fpsimd_exc | 492 | b ret_to_user |
493 | el0_sp_pc: | 493 | el0_sp_pc: |
494 | /* | 494 | /* |
495 | * Stack or PC alignment exception handling | 495 | * Stack or PC alignment exception handling |
@@ -500,8 +500,8 @@ el0_sp_pc: | |||
500 | mov x0, x26 | 500 | mov x0, x26 |
501 | mov x1, x25 | 501 | mov x1, x25 |
502 | mov x2, sp | 502 | mov x2, sp |
503 | adr lr, ret_to_user | 503 | bl do_sp_pc_abort |
504 | b do_sp_pc_abort | 504 | b ret_to_user |
505 | el0_undef: | 505 | el0_undef: |
506 | /* | 506 | /* |
507 | * Undefined instruction | 507 | * Undefined instruction |
@@ -510,8 +510,8 @@ el0_undef: | |||
510 | enable_dbg_and_irq | 510 | enable_dbg_and_irq |
511 | ct_user_exit | 511 | ct_user_exit |
512 | mov x0, sp | 512 | mov x0, sp |
513 | adr lr, ret_to_user | 513 | bl do_undefinstr |
514 | b do_undefinstr | 514 | b ret_to_user |
515 | el0_dbg: | 515 | el0_dbg: |
516 | /* | 516 | /* |
517 | * Debug exception handling | 517 | * Debug exception handling |
@@ -530,8 +530,8 @@ el0_inv: | |||
530 | mov x0, sp | 530 | mov x0, sp |
531 | mov x1, #BAD_SYNC | 531 | mov x1, #BAD_SYNC |
532 | mrs x2, esr_el1 | 532 | mrs x2, esr_el1 |
533 | adr lr, ret_to_user | 533 | bl bad_mode |
534 | b bad_mode | 534 | b ret_to_user |
535 | ENDPROC(el0_sync) | 535 | ENDPROC(el0_sync) |
536 | 536 | ||
537 | .align 6 | 537 | .align 6 |
@@ -653,14 +653,15 @@ el0_svc_naked: // compat entry point | |||
653 | ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks | 653 | ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks |
654 | tst x16, #_TIF_SYSCALL_WORK | 654 | tst x16, #_TIF_SYSCALL_WORK |
655 | b.ne __sys_trace | 655 | b.ne __sys_trace |
656 | adr lr, ret_fast_syscall // return address | ||
657 | cmp scno, sc_nr // check upper syscall limit | 656 | cmp scno, sc_nr // check upper syscall limit |
658 | b.hs ni_sys | 657 | b.hs ni_sys |
659 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table | 658 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table |
660 | br x16 // call sys_* routine | 659 | blr x16 // call sys_* routine |
660 | b ret_fast_syscall | ||
661 | ni_sys: | 661 | ni_sys: |
662 | mov x0, sp | 662 | mov x0, sp |
663 | b do_ni_syscall | 663 | bl do_ni_syscall |
664 | b ret_fast_syscall | ||
664 | ENDPROC(el0_svc) | 665 | ENDPROC(el0_svc) |
665 | 666 | ||
666 | /* | 667 | /* |
@@ -670,17 +671,16 @@ ENDPROC(el0_svc) | |||
670 | __sys_trace: | 671 | __sys_trace: |
671 | mov x0, sp | 672 | mov x0, sp |
672 | bl syscall_trace_enter | 673 | bl syscall_trace_enter |
673 | adr lr, __sys_trace_return // return address | ||
674 | uxtw scno, w0 // syscall number (possibly new) | 674 | uxtw scno, w0 // syscall number (possibly new) |
675 | mov x1, sp // pointer to regs | 675 | mov x1, sp // pointer to regs |
676 | cmp scno, sc_nr // check upper syscall limit | 676 | cmp scno, sc_nr // check upper syscall limit |
677 | b.hs ni_sys | 677 | b.hs __ni_sys_trace |
678 | ldp x0, x1, [sp] // restore the syscall args | 678 | ldp x0, x1, [sp] // restore the syscall args |
679 | ldp x2, x3, [sp, #S_X2] | 679 | ldp x2, x3, [sp, #S_X2] |
680 | ldp x4, x5, [sp, #S_X4] | 680 | ldp x4, x5, [sp, #S_X4] |
681 | ldp x6, x7, [sp, #S_X6] | 681 | ldp x6, x7, [sp, #S_X6] |
682 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table | 682 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table |
683 | br x16 // call sys_* routine | 683 | blr x16 // call sys_* routine |
684 | 684 | ||
685 | __sys_trace_return: | 685 | __sys_trace_return: |
686 | str x0, [sp] // save returned x0 | 686 | str x0, [sp] // save returned x0 |
@@ -688,6 +688,11 @@ __sys_trace_return: | |||
688 | bl syscall_trace_exit | 688 | bl syscall_trace_exit |
689 | b ret_to_user | 689 | b ret_to_user |
690 | 690 | ||
691 | __ni_sys_trace: | ||
692 | mov x0, sp | ||
693 | bl do_ni_syscall | ||
694 | b __sys_trace_return | ||
695 | |||
691 | /* | 696 | /* |
692 | * Special system call wrappers. | 697 | * Special system call wrappers. |
693 | */ | 698 | */ |