Skip to content

Commit 325f3fb

Browse files
Zheng Yejianmhiramat
authored andcommitted
kprobes: Fix possible use-after-free issue on kprobe registration
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]>
1 parent fec50db commit 325f3fb

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
@@ -1567,10 +1567,17 @@ static int check_kprobe_address_safe(struct kprobe *p,
15671567
jump_label_lock();
15681568
preempt_disable();
15691569

1570-
/* Ensure it is not in reserved area nor out of text */
1571-
if (!(core_kernel_text((unsigned long) p->addr) ||
1572-
is_module_text_address((unsigned long) p->addr)) ||
1573-
in_gate_area_no_mm((unsigned long) p->addr) ||
1570+
/* Ensure the address is in a text area, and find a module if exists. */
1571+
*probed_mod = NULL;
1572+
if (!core_kernel_text((unsigned long) p->addr)) {
1573+
*probed_mod = __module_text_address((unsigned long) p->addr);
1574+
if (!(*probed_mod)) {
1575+
ret = -EINVAL;
1576+
goto out;
1577+
}
1578+
}
1579+
/* Ensure it is not in reserved area. */
1580+
if (in_gate_area_no_mm((unsigned long) p->addr) ||
15741581
within_kprobe_blacklist((unsigned long) p->addr) ||
15751582
jump_label_text_reserved(p->addr, p->addr) ||
15761583
static_call_text_reserved(p->addr, p->addr) ||
@@ -1580,8 +1587,7 @@ static int check_kprobe_address_safe(struct kprobe *p,
15801587
goto out;
15811588
}
15821589

1583-
/* Check if 'p' is probing a module. */
1584-
*probed_mod = __module_text_address((unsigned long) p->addr);
1590+
/* Get module refcount and reject __init functions for loaded modules. */
15851591
if (*probed_mod) {
15861592
/*
15871593
* We must hold a refcount of the probed module while updating

0 commit comments

Comments
 (0)