Skip to content

Commit 93eb31e

Browse files
Zheng Yejiangregkh
authored andcommitted
kprobes: Fix possible use-after-free issue on kprobe registration
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/20240410015802.265220-1-zhengyejian1@huawei.com/ Fixes: 28f6c37 ("kprobes: Forbid probing on trampoline and BPF code areas") Cc: stable@vger.kernel.org Signed-off-by: Zheng Yejian <zhengyejian1@huawei.com> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> [Fix conflict due to lack dependency commit 223a76b ("kprobes: Fix coding style issues")] Signed-off-by: Zheng Yejian <zhengyejian1@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 49cacd3 commit 93eb31e

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
@@ -1593,19 +1593,25 @@ static int check_kprobe_address_safe(struct kprobe *p,
15931593
jump_label_lock();
15941594
preempt_disable();
15951595

1596-
/* Ensure it is not in reserved area nor out of text */
1597-
if (!(core_kernel_text((unsigned long) p->addr) ||
1598-
is_module_text_address((unsigned long) p->addr)) ||
1599-
in_gate_area_no_mm((unsigned long) p->addr) ||
1596+
/* Ensure the address is in a text area, and find a module if exists. */
1597+
*probed_mod = NULL;
1598+
if (!core_kernel_text((unsigned long) p->addr)) {
1599+
*probed_mod = __module_text_address((unsigned long) p->addr);
1600+
if (!(*probed_mod)) {
1601+
ret = -EINVAL;
1602+
goto out;
1603+
}
1604+
}
1605+
/* Ensure it is not in reserved area. */
1606+
if (in_gate_area_no_mm((unsigned long) p->addr) ||
16001607
within_kprobe_blacklist((unsigned long) p->addr) ||
16011608
jump_label_text_reserved(p->addr, p->addr) ||
16021609
find_bug((unsigned long)p->addr)) {
16031610
ret = -EINVAL;
16041611
goto out;
16051612
}
16061613

1607-
/* Check if are we probing a module */
1608-
*probed_mod = __module_text_address((unsigned long) p->addr);
1614+
/* Get module refcount and reject __init functions for loaded modules. */
16091615
if (*probed_mod) {
16101616
/*
16111617
* We must hold a refcount of the probed module while updating

0 commit comments

Comments
 (0)