Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bpf-retire-the-unsupported_ops-usage-in-struct_ops'

Martin KaFai Lau says:

====================
bpf: Retire the unsupported_ops usage in struct_ops

From: Martin KaFai Lau <martin.lau@kernel.org>

This series retires the unsupported_ops usage and depends on the
null-ness check on the cfi_stubs instead.

Please see individual patches for details.

v2:
- Fixed a gcc compiler warning on Patch 1.
====================

Link: https://lore.kernel.org/r/20240722183049.2254692-1-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

authored by

Alexei Starovoitov and committed by
Andrii Nakryiko
e2854bc3 0d7c0612

+60 -27
+5
include/linux/bpf.h
··· 1795 1795 #define BPF_MODULE_OWNER ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA)) 1796 1796 bool bpf_struct_ops_get(const void *kdata); 1797 1797 void bpf_struct_ops_put(const void *kdata); 1798 + int bpf_struct_ops_supported(const struct bpf_struct_ops *st_ops, u32 moff); 1798 1799 int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, void *key, 1799 1800 void *value); 1800 1801 int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks, ··· 1851 1850 static inline void bpf_module_put(const void *data, struct module *owner) 1852 1851 { 1853 1852 module_put(owner); 1853 + } 1854 + static inline int bpf_struct_ops_supported(const struct bpf_struct_ops *st_ops, u32 moff) 1855 + { 1856 + return -ENOTSUPP; 1854 1857 } 1855 1858 static inline int bpf_struct_ops_map_sys_lookup_elem(struct bpf_map *map, 1856 1859 void *key,
+7
kernel/bpf/bpf_struct_ops.c
··· 1040 1040 bpf_map_put(&st_map->map); 1041 1041 } 1042 1042 1043 + int bpf_struct_ops_supported(const struct bpf_struct_ops *st_ops, u32 moff) 1044 + { 1045 + void *func_ptr = *(void **)(st_ops->cfi_stubs + moff); 1046 + 1047 + return func_ptr ? 0 : -ENOTSUPP; 1048 + } 1049 + 1043 1050 static bool bpf_struct_ops_valid_to_reg(struct bpf_map *map) 1044 1051 { 1045 1052 struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map *)map;
+9 -1
kernel/bpf/verifier.c
··· 21132 21132 u32 btf_id, member_idx; 21133 21133 struct btf *btf; 21134 21134 const char *mname; 21135 + int err; 21135 21136 21136 21137 if (!prog->gpl_compatible) { 21137 21138 verbose(env, "struct ops programs must have a GPL compatible license\n"); ··· 21180 21179 return -EINVAL; 21181 21180 } 21182 21181 21182 + err = bpf_struct_ops_supported(st_ops, __btf_member_bit_offset(t, member) / 8); 21183 + if (err) { 21184 + verbose(env, "attach to unsupported member %s of struct %s\n", 21185 + mname, st_ops->name); 21186 + return err; 21187 + } 21188 + 21183 21189 if (st_ops->check_member) { 21184 - int err = st_ops->check_member(t, member, prog); 21190 + err = st_ops->check_member(t, member, prog); 21185 21191 21186 21192 if (err) { 21187 21193 verbose(env, "attach to unsupported member %s of struct %s\n",
-26
net/ipv4/bpf_tcp_ca.c
··· 14 14 /* "extern" is to avoid sparse warning. It is only used in bpf_struct_ops.c. */ 15 15 static struct bpf_struct_ops bpf_tcp_congestion_ops; 16 16 17 - static u32 unsupported_ops[] = { 18 - offsetof(struct tcp_congestion_ops, get_info), 19 - }; 20 - 21 17 static const struct btf_type *tcp_sock_type; 22 18 static u32 tcp_sock_id, sock_id; 23 19 static const struct btf_type *tcp_congestion_ops_type; ··· 39 43 tcp_congestion_ops_type = btf_type_by_id(btf, type_id); 40 44 41 45 return 0; 42 - } 43 - 44 - static bool is_unsupported(u32 member_offset) 45 - { 46 - unsigned int i; 47 - 48 - for (i = 0; i < ARRAY_SIZE(unsupported_ops); i++) { 49 - if (member_offset == unsupported_ops[i]) 50 - return true; 51 - } 52 - 53 - return false; 54 46 } 55 47 56 48 static bool bpf_tcp_ca_is_valid_access(int off, int size, ··· 235 251 return 0; 236 252 } 237 253 238 - static int bpf_tcp_ca_check_member(const struct btf_type *t, 239 - const struct btf_member *member, 240 - const struct bpf_prog *prog) 241 - { 242 - if (is_unsupported(__btf_member_bit_offset(t, member) / 8)) 243 - return -ENOTSUPP; 244 - return 0; 245 - } 246 - 247 254 static int bpf_tcp_ca_reg(void *kdata, struct bpf_link *link) 248 255 { 249 256 return tcp_register_congestion_control(kdata); ··· 329 354 .reg = bpf_tcp_ca_reg, 330 355 .unreg = bpf_tcp_ca_unreg, 331 356 .update = bpf_tcp_ca_update, 332 - .check_member = bpf_tcp_ca_check_member, 333 357 .init_member = bpf_tcp_ca_init_member, 334 358 .init = bpf_tcp_ca_init, 335 359 .validate = bpf_tcp_ca_validate,
+14
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
··· 1024 1024 { 1025 1025 } 1026 1026 1027 + static int bpf_testmod_tramp(int value) 1028 + { 1029 + return 0; 1030 + } 1031 + 1027 1032 static int bpf_testmod_ops__test_maybe_null(int dummy, 1028 1033 struct task_struct *task__nullable) 1029 1034 { ··· 1085 1080 .kfunc_btf_id = bpf_testmod_dtor_ids[1] 1086 1081 }, 1087 1082 }; 1083 + void **tramp; 1088 1084 int ret; 1089 1085 1090 1086 ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &bpf_testmod_common_kfunc_set); ··· 1109 1103 ret = register_bpf_testmod_uprobe(); 1110 1104 if (ret < 0) 1111 1105 return ret; 1106 + 1107 + /* Ensure nothing is between tramp_1..tramp_40 */ 1108 + BUILD_BUG_ON(offsetof(struct bpf_testmod_ops, tramp_1) + 40 * sizeof(long) != 1109 + offsetofend(struct bpf_testmod_ops, tramp_40)); 1110 + tramp = (void **)&__bpf_testmod_ops.tramp_1; 1111 + while (tramp <= (void **)&__bpf_testmod_ops.tramp_40) 1112 + *tramp++ = bpf_testmod_tramp; 1113 + 1112 1114 return 0; 1113 1115 } 1114 1116
+1
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.h
··· 35 35 void (*test_2)(int a, int b); 36 36 /* Used to test nullable arguments. */ 37 37 int (*test_maybe_null)(int dummy, struct task_struct *task); 38 + int (*unsupported_ops)(void); 38 39 39 40 /* The following fields are used to test shadow copies. */ 40 41 char onebyte;
+2
tools/testing/selftests/bpf/prog_tests/test_struct_ops_module.c
··· 9 9 #include "struct_ops_nulled_out_cb.skel.h" 10 10 #include "struct_ops_forgotten_cb.skel.h" 11 11 #include "struct_ops_detach.skel.h" 12 + #include "unsupported_ops.skel.h" 12 13 13 14 static void check_map_info(struct bpf_map_info *info) 14 15 { ··· 312 311 test_struct_ops_forgotten_cb(); 313 312 if (test__start_subtest("test_detach_link")) 314 313 test_detach_link(); 314 + RUN_TESTS(unsupported_ops); 315 315 } 316 316
+22
tools/testing/selftests/bpf/progs/unsupported_ops.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <vmlinux.h> 5 + #include <bpf/bpf_tracing.h> 6 + #include "bpf_misc.h" 7 + #include "../bpf_testmod/bpf_testmod.h" 8 + 9 + char _license[] SEC("license") = "GPL"; 10 + 11 + SEC("struct_ops/unsupported_ops") 12 + __failure 13 + __msg("attach to unsupported member unsupported_ops of struct bpf_testmod_ops") 14 + int BPF_PROG(unsupported_ops) 15 + { 16 + return 0; 17 + } 18 + 19 + SEC(".struct_ops.link") 20 + struct bpf_testmod_ops testmod = { 21 + .unsupported_ops = (void *)unsupported_ops, 22 + };