Re: git: f29942229d24 - main - Read the arm64 far early in el0 exceptions
- In reply to: Jessica Clarke : "Re: git: f29942229d24 - main - Read the arm64 far early in el0 exceptions"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 14 Feb 2023 02:57:53 UTC
On 2 Feb 2023, at 21:00, Jessica Clarke <jrtc27@FreeBSD.org> wrote:
>
> On 2 Feb 2023, at 16:48, Andrew Turner <andrew@FreeBSD.org> wrote:
>>
>> The branch main has been updated by andrew:
>>
>> URL: https://cgit.FreeBSD.org/src/commit/?id=f29942229d24ebb8b98f8c5d02f3c8632648007e
>>
>> commit f29942229d24ebb8b98f8c5d02f3c8632648007e
>> Author: Andrew Turner <andrew@FreeBSD.org>
>> AuthorDate: 2023-01-25 17:47:39 +0000
>> Commit: Andrew Turner <andrew@FreeBSD.org>
>> CommitDate: 2023-02-02 16:43:15 +0000
>>
>> Read the arm64 far early in el0 exceptions
>>
>> When handling userspace exceptions on arm64 we need to dereference the
>> current thread pointer. If this is being promoted/demoted there is a
>> small window where it will cause another exception to be hit. As this
>> second exception will set the fault address register we will read the
>> incorrect value in the userspace exception handler.
>>
>> Fix this be always reading the fault address before dereferencing the
>> current thread pointer.
>>
>> Reported by: olivier@
>> Reviewed by: markj
>> Sponsored by: Arm Ltd
>> Differential Revision: https://reviews.freebsd.org/D38196
>> ---
>> sys/arm64/arm64/exception.S | 15 +++++++++++++++
>> sys/arm64/arm64/trap.c | 26 +++++++-------------------
>> 2 files changed, 22 insertions(+), 19 deletions(-)
>>
>> diff --git a/sys/arm64/arm64/exception.S b/sys/arm64/arm64/exception.S
>> index 4a74358afeb9..55bac5e5228a 100644
>> --- a/sys/arm64/arm64/exception.S
>> +++ b/sys/arm64/arm64/exception.S
>> @@ -212,10 +212,25 @@ ENTRY(handle_el1h_irq)
>> END(handle_el1h_irq)
>>
>> ENTRY(handle_el0_sync)
>> + /*
>> + * Read the fault address early. The current thread structure may
>> + * be transiently unmapped if it is part of a memory range being
>> + * promoted or demoted to/from a superpage. As this involves a
>> + * break-before-make sequence there is a short period of time where
>> + * an access will raise an exception. If this happens the fault
>> + * address will be changed to the kernel address so a later read of
>> + * far_el1 will give the wrong value.
>> + *
>> + * The earliest memory access that could trigger a fault is in a
>> + * function called by the save_registers macro so this is the latest
>> + * we can read the userspace value.
>> + */
>> + mrs x19, far_el1
>> save_registers 0
>> ldr x0, [x18, #PC_CURTHREAD]
>> mov x1, sp
>> str x1, [x0, #TD_FRAME]
>> + mov x2, x19
>> bl do_el0_sync
>> do_ast
>> restore_registers 0
>> diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c
>> index 4e54a06548cc..1b33d7aa60c4 100644
>> --- a/sys/arm64/arm64/trap.c
>> +++ b/sys/arm64/arm64/trap.c
>> @@ -76,7 +76,7 @@ __FBSDID("$FreeBSD$");
>>
>> /* Called from exception.S */
>> void do_el1h_sync(struct thread *, struct trapframe *);
>
> This did not address my feedback regarding EL1 debug exceptions also
> clobbering FAR.
Ping, now after this has been MFC’ed without so much as a reply to my
feedback here nor on the Phabricator review.
Jess
>> -void do_el0_sync(struct thread *, struct trapframe *);
>> +void do_el0_sync(struct thread *, struct trapframe *, uint64_t far);
>> void do_el0_error(struct trapframe *);
>> void do_serror(struct trapframe *);
>> void unhandled_exception(struct trapframe *);
>> @@ -559,11 +559,11 @@ do_el1h_sync(struct thread *td, struct trapframe *frame)
>> }
>>
>> void
>> -do_el0_sync(struct thread *td, struct trapframe *frame)
>> +do_el0_sync(struct thread *td, struct trapframe *frame, uint64_t far)
>> {
>> pcpu_bp_harden bp_harden;
>> uint32_t exception;
>> - uint64_t esr, far;
>> + uint64_t esr;
>> int dfsc;
>>
>> /* Check we have a sane environment when entering from userland */
>> @@ -573,27 +573,15 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
>>
>> esr = frame->tf_esr;
>> exception = ESR_ELx_EXCEPTION(esr);
>> - switch (exception) {
>> - case EXCP_INSN_ABORT_L:
>> - far = READ_SPECIALREG(far_el1);
>> -
>> + if (exception == EXCP_INSN_ABORT_L && far > VM_MAXUSER_ADDRESS) {
>> /*
>> * Userspace may be trying to train the branch predictor to
>> * attack the kernel. If we are on a CPU affected by this
>> * call the handler to clear the branch predictor state.
>> */
>> - if (far > VM_MAXUSER_ADDRESS) {
>> - bp_harden = PCPU_GET(bp_harden);
>> - if (bp_harden != NULL)
>> - bp_harden();
>> - }
>> - break;
>> - case EXCP_UNKNOWN:
>> - case EXCP_DATA_ABORT_L:
>> - case EXCP_DATA_ABORT:
>> - case EXCP_WATCHPT_EL0:
>> - far = READ_SPECIALREG(far_el1);
>> - break;
>> + bp_harden = PCPU_GET(bp_harden);
>> + if (bp_harden != NULL)
>> + bp_harden();
>> }
>> intr_enable();