sdei_api_event_context(i, ®s->regs[i]);
}
- /*
- * We didn't take an exception to get here, set PAN. UAO will be cleared
- * by sdei_event_handler()s force_uaccess_begin() call.
- */
- __uaccess_enable_hw_pan();
-
err = sdei_event_handler(regs, arg);
if (err)
return SDEI_EV_FAILED;
__sdei_handler(struct pt_regs *regs, struct sdei_registered_event *arg)
{
unsigned long ret;
+ mm_segment_t orig_addr_limit;
+
+ /*
+ * We didn't take an exception to get here, so the HW hasn't set PAN or
+ * cleared UAO, and the exception entry code hasn't reset addr_limit.
+ * Set PAN, then use force_uaccess_begin() to clear UAO and reset
+ * addr_limit.
+ */
+ __uaccess_enable_hw_pan();
+ orig_addr_limit = force_uaccess_begin();
nmi_enter();
nmi_exit();
+ force_uaccess_end(orig_addr_limit);
+
return ret;
}
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/spinlock.h>
-#include <linux/uaccess.h>
/*
* The call to use to reach the firmware.
struct sdei_registered_event *arg)
{
int err;
- mm_segment_t orig_addr_limit;
u32 event_num = arg->event_num;
- /*
- * Save restore 'fs'.
- * The architecture's entry code save/restores 'fs' when taking an
- * exception from the kernel. This ensures addr_limit isn't inherited
- * if you interrupted something that allowed the uaccess routines to
- * access kernel memory.
- * Do the same here because this doesn't come via the same entry code.
- */
- orig_addr_limit = force_uaccess_begin();
-
err = arg->callback(event_num, regs, arg->callback_arg);
if (err)
pr_err_ratelimited("event %u on CPU %u failed with error: %d\n",
event_num, smp_processor_id(), err);
- force_uaccess_end(orig_addr_limit);
-
return err;
}
NOKPROBE_SYMBOL(sdei_event_handler);