aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-04-10 19:48:05 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-04-10 19:48:05 -0700
commite8c39d0f57f358950356a8e44ee5159f57f86ec5 (patch)
tree05e9af52843ce3f26e45c2db94a8e29f5a629182
parent03a55b63919f4b52b9c323d9a43ccccdc1cdb33b (diff)
parent325f3fb551f8cd672dbbfc4cf58b14f9ee3fc9e8 (diff)
downloadlinux-e8c39d0f57f358950356a8e44ee5159f57f86ec5.tar.gz
Merge tag 'probes-fixes-v6.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull probes fixes from Masami Hiramatsu: "Fix possible use-after-free issue on kprobe registration. check_kprobe_address_safe() uses `is_module_text_address()` and `__module_text_address()` separately. As a result, if the probed address is in a module that is being unloaded, the first `is_module_text_address()` might return true but then the `__module_text_address()` call might return NULL if the module has been unloaded between the two. The result is that kprobe believes the probe is on the kernel text, and skips getting a module reference. In this case, when it arms a breakpoint on the probe address, it may cause a use-after-free. To fix this issue, only use `__module_text_address()` once and get a reference to the module then. If it fails, reject the probe" * tag 'probes-fixes-v6.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: kprobes: Fix possible use-after-free issue on kprobe registration
-rw-r--r--kernel/kprobes.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 9d9095e8179286..65adc815fc6e63 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1567,10 +1567,17 @@ static int check_kprobe_address_safe(struct kprobe *p,
jump_label_lock();
preempt_disable();
- /* Ensure it is not in reserved area nor out of text */
- if (!(core_kernel_text((unsigned long) p->addr) ||
- is_module_text_address((unsigned long) p->addr)) ||
- in_gate_area_no_mm((unsigned long) p->addr) ||
+ /* Ensure the address is in a text area, and find a module if exists. */
+ *probed_mod = NULL;
+ if (!core_kernel_text((unsigned long) p->addr)) {
+ *probed_mod = __module_text_address((unsigned long) p->addr);
+ if (!(*probed_mod)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ /* Ensure it is not in reserved area. */
+ if (in_gate_area_no_mm((unsigned long) p->addr) ||
within_kprobe_blacklist((unsigned long) p->addr) ||
jump_label_text_reserved(p->addr, p->addr) ||
static_call_text_reserved(p->addr, p->addr) ||
@@ -1580,8 +1587,7 @@ static int check_kprobe_address_safe(struct kprobe *p,
goto out;
}
- /* Check if 'p' is probing a module. */
- *probed_mod = __module_text_address((unsigned long) p->addr);
+ /* Get module refcount and reject __init functions for loaded modules. */
if (*probed_mod) {
/*
* We must hold a refcount of the probed module while updating