From b210535222a9f49cc33b4db53d13bca40a12e0f7 Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Mon, 20 Jun 2016 21:11:01 +0300 Subject: [PATCH] [FIX] rcu_nmi_enter/exit() inconsistentence (for x86) Add rcu_nmi_enter() call to exceptions_handler(), because we change US context to KS context as a result rcu_nmi_exit() will be called on exiting exception and rcu_nmi_enter() and rcu_nmi_exit() calls must be consistent. Change-Id: Idbf5a7d6be1284ba841c4b43b565aaf18197ab28 Signed-off-by: Vyacheslav Cherkashin --- uprobe/arch/x86/swap-asm/swap_uprobes.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/uprobe/arch/x86/swap-asm/swap_uprobes.c b/uprobe/arch/x86/swap-asm/swap_uprobes.c index 97daf85..99308bc 100644 --- a/uprobe/arch/x86/swap-asm/swap_uprobes.c +++ b/uprobe/arch/x86/swap-asm/swap_uprobes.c @@ -468,6 +468,14 @@ static void prepare_ss(struct pt_regs *regs) static unsigned long resume_userspace_addr; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0) +static void __rcu_nmi_enter(void) {} +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) +#error "This kernel is not support" +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */ +static void (*__rcu_nmi_enter)(void); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0) */ + static void __used __up_handler(void) { struct pt_regs *regs = current_ctx()->ptr_regs; @@ -517,6 +525,14 @@ static int exceptions_handler(struct pt_regs *regs, regs->gs = 0; regs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED; + /* + * Here rcu_nmi_enter() call is needed, because we change + * US context to KS context as a result rcu_nmi_exit() will + * be called on exiting exception and rcu_nmi_enter() and + * rcu_nmi_exit() calls must be consistent + */ + __rcu_nmi_enter(); + return 1; } @@ -711,6 +727,13 @@ int swap_arch_init_uprobes(void) if (kp_do_exit.addr == 0) goto not_found; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) + sym = "rcu_nmi_enter"; + __rcu_nmi_enter = (void *)swap_ksyms(sym); + if (__rcu_nmi_enter == NULL) + goto not_found; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0) */ + ret = swap_td_raw_reg(&td_raw, sizeof(struct uprobe_ctlblk)); if (ret) return ret; -- 2.7.4