Skip to content

Commit 579a81f

Browse files
Zheng Yejiansmb49
authored andcommitted
kprobes: Fix possible use-after-free issue on kprobe registration
BugLink: https://bugs.launchpad.net/bugs/2067959 commit 325f3fb upstream. When unloading a module, its state is changing MODULE_STATE_LIVE -> MODULE_STATE_GOING -> MODULE_STATE_UNFORMED. Each change will take a time. `is_module_text_address()` and `__module_text_address()` works with MODULE_STATE_LIVE and MODULE_STATE_GOING. If we use `is_module_text_address()` and `__module_text_address()` separately, there is a chance that the first one is succeeded but the next one is failed because module->state becomes MODULE_STATE_UNFORMED between those operations. In `check_kprobe_address_safe()`, if the second `__module_text_address()` is failed, that is ignored because it expected a kernel_text address. But it may have failed simply because module->state has been changed to MODULE_STATE_UNFORMED. In this case, arm_kprobe() will try to modify non-exist module text address (use-after-free). To fix this problem, we should not use separated `is_module_text_address()` and `__module_text_address()`, but use only `__module_text_address()` once and do `try_module_get(module)` which is only available with MODULE_STATE_LIVE. Link: https://lore.kernel.org/all/[email protected]/ Fixes: 28f6c37 ("kprobes: Forbid probing on trampoline and BPF code areas") Cc: [email protected] Signed-off-by: Zheng Yejian <[email protected]> Signed-off-by: Masami Hiramatsu (Google) <[email protected]> [Fix conflict due to lack dependency commit 223a76b ("kprobes: Fix coding style issues")] Signed-off-by: Zheng Yejian <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Portia Stephens <[email protected]> Signed-off-by: Stefan Bader <[email protected]>
1 parent 9225587 commit 579a81f

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

kernel/kprobes.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,10 +1564,17 @@ static int check_kprobe_address_safe(struct kprobe *p,
15641564
jump_label_lock();
15651565
preempt_disable();
15661566

1567-
/* Ensure it is not in reserved area nor out of text */
1568-
if (!(core_kernel_text((unsigned long) p->addr) ||
1569-
is_module_text_address((unsigned long) p->addr)) ||
1570-
in_gate_area_no_mm((unsigned long) p->addr) ||
1567+
/* Ensure the address is in a text area, and find a module if exists. */
1568+
*probed_mod = NULL;
1569+
if (!core_kernel_text((unsigned long) p->addr)) {
1570+
*probed_mod = __module_text_address((unsigned long) p->addr);
1571+
if (!(*probed_mod)) {
1572+
ret = -EINVAL;
1573+
goto out;
1574+
}
1575+
}
1576+
/* Ensure it is not in reserved area. */
1577+
if (in_gate_area_no_mm((unsigned long) p->addr) ||
15711578
within_kprobe_blacklist((unsigned long) p->addr) ||
15721579
jump_label_text_reserved(p->addr, p->addr) ||
15731580
static_call_text_reserved(p->addr, p->addr) ||
@@ -1577,8 +1584,7 @@ static int check_kprobe_address_safe(struct kprobe *p,
15771584
goto out;
15781585
}
15791586

1580-
/* Check if are we probing a module */
1581-
*probed_mod = __module_text_address((unsigned long) p->addr);
1587+
/* Get module refcount and reject __init functions for loaded modules. */
15821588
if (*probed_mod) {
15831589
/*
15841590
* We must hold a refcount of the probed module while updating

0 commit comments

Comments
 (0)