DORMANTno replies

[PATCH bpf 3/4] bpf_trace: handle compat in kprobe_multi_resolve_syms

From: Eugene Syromiatnikov <hidden>
Date: 2022-05-16 18:28:15
Also in: bpf, linux-kselftest, lkml
Subsystem: bpf [general] (safe dynamic programs and tools), bpf [security & lsm] (security audit and enforcement using bpf), bpf [tracing], the rest, tracing · Maintainers: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi, KP Singh, Matt Bobrowski, Song Liu, Linus Torvalds, Steven Rostedt, Masami Hiramatsu

For compat processes, userspace pointer size is different.  Since the
copied array is iterated anyway, the simplest fix seems to be copy the
user-supplied array as-is and the iterate as an array of native or
compat pointers, depending on the in_compat_syscall() value.

Fixes: 0dcac272540613d4 ("bpf: Add multi kprobe link")
Signed-off-by: Eugene Syromiatnikov <redacted>
---
 kernel/trace/bpf_trace.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index d228440..5b0cf54 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2352,16 +2352,21 @@ static int
 kprobe_multi_resolve_syms(const void __user *usyms, u32 cnt,
 			  unsigned long *addrs)
 {
-	unsigned long addr, size;
+	unsigned long addr;
+	size_t sym_size;
+	u32 size, elem_size;
 	const char __user **syms;
+	compat_uptr_t __user *compat_syms;
 	int err = -ENOMEM;
 	unsigned int i;
 	char *func;
 
-	if (check_mul_overflow(cnt, sizeof(*syms), &size))
+	elem_size = in_compat_syscall() ? sizeof(*compat_syms) : sizeof(*syms);
+	if (check_mul_overflow(cnt, elem_size, &size))
 		return -EOVERFLOW;
-	size = cnt * sizeof(*syms);
+	size = cnt * elem_size;
 	syms = kvzalloc(size, GFP_KERNEL);
+	compat_syms = (void *)syms;
 	if (!syms)
 		return -ENOMEM;
 
@@ -2375,7 +2380,10 @@ kprobe_multi_resolve_syms(const void __user *usyms, u32 cnt,
 	}
 
 	for (i = 0; i < cnt; i++) {
-		err = strncpy_from_user(func, syms[i], KSYM_NAME_LEN);
+		const char __user *ufunc = in_compat_syscall()
+					? (char __user *)(uintptr_t)compat_syms[i]
+					: syms[i];
+		err = strncpy_from_user(func, ufunc, KSYM_NAME_LEN);
 		if (err == KSYM_NAME_LEN)
 			err = -E2BIG;
 		if (err < 0)
@@ -2384,9 +2392,9 @@ kprobe_multi_resolve_syms(const void __user *usyms, u32 cnt,
 		addr = kallsyms_lookup_name(func);
 		if (!addr)
 			goto error;
-		if (!kallsyms_lookup_size_offset(addr, &size, NULL))
+		if (!kallsyms_lookup_size_offset(addr, &sym_size, NULL))
 			goto error;
-		addr = ftrace_location_range(addr, addr + size - 1);
+		addr = ftrace_location_range(addr, addr + sym_size - 1);
 		if (!addr)
 			goto error;
 		addrs[i] = addr;
-- 
2.1.4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help