| @@ -18,6 +18,8 @@ · 17 unmodified lines |
| 18 | 18 | #include <linux/btf_ids.h> |
| 19 | 19 | #include <linux/bpf_lsm.h> |
| 20 | 20 | #include <linux/fprobe.h> |
| 21 | +#include <linux/bsearch.h> |
| 22 | +#include <linux/sort.h> |
| 21 | 23 | |
| 22 | 24 | #include <net/bpf_sk_storage.h> |
| 23 | 25 | |
| @@ -78,6 +80,7 @@ u64 bpf_get_stack(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); · 54 unmodified lines |
| 78 | 80 | static int bpf_btf_printf_prepare(struct btf_ptr *ptr, u32 btf_ptr_size, |
| 79 | 81 | u64 flags, const struct btf **btf, |
| 80 | 82 | s32 *btf_id); |
| 83 | +static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip); |
| 81 | 84 | |
| 82 | 85 | /** |
| 83 | 86 | * trace_call_bpf - invoke BPF program |
| @@ -1050,6 +1053,18 @@ static const struct bpf_func_proto bpf_get_func_ip_proto_kprobe_multi = { · 966 unmodified lines |
| 1050 | 1053 | .arg1_type = ARG_PTR_TO_CTX, |
| 1051 | 1054 | }; |
| 1052 | 1055 | |
| 1056 | +BPF_CALL_1(bpf_get_attach_cookie_kprobe_multi, struct pt_regs *, regs) |
| 1057 | +{ |
| 1058 | + return bpf_kprobe_multi_cookie(current->bpf_ctx, instruction_pointer(regs)); |
| 1059 | +} |
| 1060 | + |
| 1061 | +static const struct bpf_func_proto bpf_get_attach_cookie_proto_kmulti = { |
| 1062 | + .func = bpf_get_attach_cookie_kprobe_multi, |
| 1063 | + .gpl_only = false, |
| 1064 | + .ret_type = RET_INTEGER, |
| 1065 | + .arg1_type = ARG_PTR_TO_CTX, |
| 1066 | +}; |
| 1067 | + |
| 1053 | 1068 | BPF_CALL_1(bpf_get_attach_cookie_trace, void *, ctx) |
| 1054 | 1069 | { |
| 1055 | 1070 | struct bpf_trace_run_ctx *run_ctx; |
| @@ -1297,7 +1312,9 @@ kprobe_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) · 241 unmodified lines |
| 1297 | 1312 | &bpf_get_func_ip_proto_kprobe_multi : |
| 1298 | 1313 | &bpf_get_func_ip_proto_kprobe; |
| 1299 | 1314 | case BPF_FUNC_get_attach_cookie: |
| 1300 | | − return &bpf_get_attach_cookie_proto_trace; |
| 1315 | + return prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI ? |
| 1316 | + &bpf_get_attach_cookie_proto_kmulti : |
| 1317 | + &bpf_get_attach_cookie_proto_trace; |
| 1301 | 1318 | default: |
| 1302 | 1319 | return bpf_tracing_func_proto(func_id, prog); |
| 1303 | 1320 | } |
| @@ -2203,6 +2220,13 @@ struct bpf_kprobe_multi_link { · 899 unmodified lines |
| 2203 | 2220 | struct bpf_link link; |
| 2204 | 2221 | struct fprobe fp; |
| 2205 | 2222 | unsigned long *addrs; |
| 2223 | + /* |
| 2224 | + * The run_ctx here is used to get struct bpf_kprobe_multi_link in |
| 2225 | + * get_attach_cookie helper, so it can't be used to store data. |
| 2226 | + */ |
| 2227 | + struct bpf_run_ctx run_ctx; |
| 2228 | + u64 *cookies; |
| 2229 | + u32 cnt; |
| 2206 | 2230 | }; |
| 2207 | 2231 | |
| 2208 | 2232 | static void bpf_kprobe_multi_link_release(struct bpf_link *link) |
| @@ -2219,6 +2243,7 @@ static void bpf_kprobe_multi_link_dealloc(struct bpf_link *link) · 10 unmodified lines |
| 2219 | 2243 | |
| 2220 | 2244 | kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link); |
| 2221 | 2245 | kvfree(kmulti_link->addrs); |
| 2246 | + kvfree(kmulti_link->cookies); |
| 2222 | 2247 | kfree(kmulti_link); |
| 2223 | 2248 | } |
| 2224 | 2249 | |
| @@ -2227,10 +2252,60 @@ static const struct bpf_link_ops bpf_kprobe_multi_link_lops = { · 2 unmodified lines |
| 2227 | 2252 | .dealloc = bpf_kprobe_multi_link_dealloc, |
| 2228 | 2253 | }; |
| 2229 | 2254 | |
| 2255 | +static void bpf_kprobe_multi_cookie_swap(void *a, void *b, int size, const void *priv) |
| 2256 | +{ |
| 2257 | + const struct bpf_kprobe_multi_link *link = priv; |
| 2258 | + unsigned long *addr_a = a, *addr_b = b; |
| 2259 | + u64 *cookie_a, *cookie_b; |
| 2260 | + unsigned long tmp1; |
| 2261 | + u64 tmp2; |
| 2262 | + |
| 2263 | + cookie_a = link->cookies + (addr_a - link->addrs); |
| 2264 | + cookie_b = link->cookies + (addr_b - link->addrs); |
| 2265 | + |
| 2266 | + /* swap addr_a/addr_b and cookie_a/cookie_b values */ |
| 2267 | + tmp1 = *addr_a; *addr_a = *addr_b; *addr_b = tmp1; |
| 2268 | + tmp2 = *cookie_a; *cookie_a = *cookie_b; *cookie_b = tmp2; |
| 2269 | +} |
| 2270 | + |
| 2271 | +static int __bpf_kprobe_multi_cookie_cmp(const void *a, const void *b) |
| 2272 | +{ |
| 2273 | + const unsigned long *addr_a = a, *addr_b = b; |
| 2274 | + |
| 2275 | + if (*addr_a == *addr_b) |
| 2276 | + return 0; |
| 2277 | + return *addr_a < *addr_b ? -1 : 1; |
| 2278 | +} |
| 2279 | + |
| 2280 | +static int bpf_kprobe_multi_cookie_cmp(const void *a, const void *b, const void *priv) |
| 2281 | +{ |
| 2282 | + return __bpf_kprobe_multi_cookie_cmp(a, b); |
| 2283 | +} |
| 2284 | + |
| 2285 | +static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip) |
| 2286 | +{ |
| 2287 | + struct bpf_kprobe_multi_link *link; |
| 2288 | + unsigned long *addr; |
| 2289 | + u64 *cookie; |
| 2290 | + |
| 2291 | + if (WARN_ON_ONCE(!ctx)) |
| 2292 | + return 0; |
| 2293 | + link = container_of(ctx, struct bpf_kprobe_multi_link, run_ctx); |
| 2294 | + if (!link->cookies) |
| 2295 | + return 0; |
| 2296 | + addr = bsearch(&ip, link->addrs, link->cnt, sizeof(ip), |
| 2297 | + __bpf_kprobe_multi_cookie_cmp); |
| 2298 | + if (!addr) |
| 2299 | + return 0; |
| 2300 | + cookie = link->cookies + (addr - link->addrs); |
| 2301 | + return *cookie; |
| 2302 | +} |
| 2303 | + |
| 2230 | 2304 | static int |
| 2231 | 2305 | kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, |
| 2232 | 2306 | struct pt_regs *regs) |
| 2233 | 2307 | { |
| 2308 | + struct bpf_run_ctx *old_run_ctx; |
| 2234 | 2309 | int err; |
| 2235 | 2310 | |
| 2236 | 2311 | if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1)) { |
| @@ -2240,7 +2315,9 @@ kprobe_multi_link_prog_run(struct bpf_kprobe_multi_link *link, · 3 unmodified lines |
| 2240 | 2315 | |
| 2241 | 2316 | migrate_disable(); |
| 2242 | 2317 | rcu_read_lock(); |
| 2318 | + old_run_ctx = bpf_set_run_ctx(&link->run_ctx); |
| 2243 | 2319 | err = bpf_prog_run(link->link.prog, regs); |
| 2320 | + bpf_reset_run_ctx(old_run_ctx); |
| 2244 | 2321 | rcu_read_unlock(); |
| 2245 | 2322 | migrate_enable(); |
| 2246 | 2323 | |
| @@ -2326,9 +2403,11 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 79 unmodified lines |
| 2326 | 2403 | { |
| 2327 | 2404 | struct bpf_kprobe_multi_link *link = NULL; |
| 2328 | 2405 | struct bpf_link_primer link_primer; |
| 2406 | + void __user *ucookies; |
| 2329 | 2407 | unsigned long *addrs; |
| 2330 | 2408 | u32 flags, cnt, size; |
| 2331 | 2409 | void __user *uaddrs; |
| 2410 | + u64 *cookies = NULL; |
| 2332 | 2411 | void __user *usyms; |
| 2333 | 2412 | int err; |
| 2334 | 2413 | |
| @@ -2368,6 +2447,19 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 33 unmodified lines |
| 2368 | 2447 | goto error; |
| 2369 | 2448 | } |
| 2370 | 2449 | |
| 2450 | + ucookies = u64_to_user_ptr(attr->link_create.kprobe_multi.cookies); |
| 2451 | + if (ucookies) { |
| 2452 | + cookies = kvmalloc(size, GFP_KERNEL); |
| 2453 | + if (!cookies) { |
| 2454 | + err = -ENOMEM; |
| 2455 | + goto error; |
| 2456 | + } |
| 2457 | + if (copy_from_user(cookies, ucookies, size)) { |
| 2458 | + err = -EFAULT; |
| 2459 | + goto error; |
| 2460 | + } |
| 2461 | + } |
| 2462 | + |
| 2371 | 2463 | link = kzalloc(sizeof(*link), GFP_KERNEL); |
| 2372 | 2464 | if (!link) { |
| 2373 | 2465 | err = -ENOMEM; |
| @@ -2387,6 +2479,21 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 13 unmodified lines |
| 2387 | 2479 | link->fp.entry_handler = kprobe_multi_link_handler; |
| 2388 | 2480 | |
| 2389 | 2481 | link->addrs = addrs; |
| 2482 | + link->cookies = cookies; |
| 2483 | + link->cnt = cnt; |
| 2484 | + |
| 2485 | + if (cookies) { |
| 2486 | + /* |
| 2487 | + * Sorting addresses will trigger sorting cookies as well |
| 2488 | + * (check bpf_kprobe_multi_cookie_swap). This way we can |
| 2489 | + * find cookie based on the address in bpf_get_attach_cookie |
| 2490 | + * helper. |
| 2491 | + */ |
| 2492 | + sort_r(addrs, cnt, sizeof(*addrs), |
| 2493 | + bpf_kprobe_multi_cookie_cmp, |
| 2494 | + bpf_kprobe_multi_cookie_swap, |
| 2495 | + link); |
| 2496 | + } |
| 2390 | 2497 | |
| 2391 | 2498 | err = register_fprobe_ips(&link->fp, addrs, cnt); |
| 2392 | 2499 | if (err) { |
| @@ -2399,6 +2506,7 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 6 unmodified lines |
| 2399 | 2506 | error: |
| 2400 | 2507 | kfree(link); |
| 2401 | 2508 | kvfree(addrs); |
| 2509 | + kvfree(cookies); |
| 2402 | 2510 | return err; |
| 2403 | 2511 | } |
| 2404 | 2512 | #else /* !CONFIG_FPROBE */ |
| @@ -2406,4 +2514,8 @@ int bpf_kprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr · 1 unmodified line |
| 2406 | 2514 | { |
| 2407 | 2515 | return -EOPNOTSUPP; |
| 2408 | 2516 | } |
| 2517 | +static u64 bpf_kprobe_multi_cookie(struct bpf_run_ctx *ctx, u64 ip) |
| 2518 | +{ |
| 2519 | + return 0; |
| 2520 | +} |
| 2409 | 2521 | #endif |