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-copy-bpf-token-from-main-program-to-subprograms'

Eduard Zingerman says:

====================
bpf: copy BPF token from main program to subprograms

bpf_jit_subprogs() omits aux->token when it creates a struct
bpf_prog_aux instances for a subprograms.
This means that for programs loaded via BPF token (i.e., from a
non-init user namespace), subprograms fail the bpf_token_capable()
check in bpf_prog_kallsyms_add() and don't appear in /proc/kallsyms.
Which in-turn makes it impossible to freplace such subprograms.

Changelog:
v3 -> v4:
- check sysctl_set calls for errors (sashiko).
v2 -> v3:
- mark selftest as serial (sashiko).
v1 -> v2:
- target bpf-next tree (fixups.c) instead of bpf tree (verifier.c).

v1: https://lore.kernel.org/bpf/20260414-subprog-token-fix-v1-0-5b1a38e01546@gmail.com/T/
v2: https://lore.kernel.org/bpf/20260414-subprog-token-fix-v2-0-59146c31f6f1@gmail.com/T/
v3: https://lore.kernel.org/bpf/20260415-subprog-token-fix-v3-0-6fefe1d51646@gmail.com/T/
====================

Link: https://patch.msgid.link/20260415-subprog-token-fix-v4-0-9bd000e8b068@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+150 -23
+1
kernel/bpf/fixups.c
··· 1110 1110 func[i]->aux->exception_cb = env->subprog_info[i].is_exception_cb; 1111 1111 func[i]->aux->changes_pkt_data = env->subprog_info[i].changes_pkt_data; 1112 1112 func[i]->aux->might_sleep = env->subprog_info[i].might_sleep; 1113 + func[i]->aux->token = prog->aux->token; 1113 1114 if (!i) 1114 1115 func[i]->aux->exception_boundary = env->seen_exception; 1115 1116
+1
tools/testing/selftests/bpf/Makefile
··· 751 751 btf_helpers.c \ 752 752 cap_helpers.c \ 753 753 unpriv_helpers.c \ 754 + sysctl_helpers.c \ 754 755 netlink_helpers.c \ 755 756 jit_disasm_helpers.c \ 756 757 io_helpers.c \
+83 -3
tools/testing/selftests/bpf/prog_tests/token.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 3 #define _GNU_SOURCE 4 - #include <test_progs.h> 5 4 #include <bpf/btf.h> 6 - #include "cap_helpers.h" 7 5 #include <fcntl.h> 8 6 #include <sched.h> 9 7 #include <signal.h> ··· 13 15 #include <sys/stat.h> 14 16 #include <sys/syscall.h> 15 17 #include <sys/un.h> 18 + 19 + #include "bpf_util.h" 20 + #include "cap_helpers.h" 21 + #include "sysctl_helpers.h" 22 + #include "test_progs.h" 23 + #include "trace_helpers.h" 24 + 16 25 #include "priv_map.skel.h" 17 26 #include "priv_prog.skel.h" 18 27 #include "dummy_st_ops_success.skel.h" 28 + #include "token_kallsyms.skel.h" 19 29 #include "token_lsm.skel.h" 20 30 #include "priv_freplace_prog.skel.h" 21 31 ··· 1051 1045 return -EINVAL; 1052 1046 } 1053 1047 1048 + static bool kallsyms_has_bpf_func(struct ksyms *ksyms, const char *func_name) 1049 + { 1050 + char name[256]; 1051 + int i; 1052 + 1053 + for (i = 0; i < ksyms->sym_cnt; i++) { 1054 + if (sscanf(ksyms->syms[i].name, "bpf_prog_%*[^_]_%255s", name) == 1 && 1055 + strcmp(name, func_name) == 0) 1056 + return true; 1057 + } 1058 + return false; 1059 + } 1060 + 1061 + static int userns_obj_priv_prog_kallsyms(int mnt_fd, struct token_lsm *lsm_skel) 1062 + { 1063 + const char *func_names[] = { "xdp_main", "token_ksym_subprog" }; 1064 + LIBBPF_OPTS(bpf_object_open_opts, opts); 1065 + struct token_kallsyms *skel; 1066 + struct ksyms *ksyms = NULL; 1067 + char buf[256]; 1068 + int i, err; 1069 + 1070 + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); 1071 + opts.bpf_token_path = buf; 1072 + skel = token_kallsyms__open_opts(&opts); 1073 + if (!ASSERT_OK_PTR(skel, "token_kallsyms__open_opts")) 1074 + return -EINVAL; 1075 + 1076 + err = token_kallsyms__load(skel); 1077 + if (!ASSERT_OK(err, "token_kallsyms__load")) 1078 + goto cleanup; 1079 + 1080 + ksyms = load_kallsyms_local(); 1081 + if (!ASSERT_OK_PTR(ksyms, "load_kallsyms_local")) { 1082 + err = -EINVAL; 1083 + goto cleanup; 1084 + } 1085 + 1086 + for (i = 0; i < ARRAY_SIZE(func_names); i++) { 1087 + if (!ASSERT_TRUE(kallsyms_has_bpf_func(ksyms, func_names[i]), 1088 + func_names[i])) { 1089 + err = -EINVAL; 1090 + break; 1091 + } 1092 + } 1093 + 1094 + cleanup: 1095 + free_kallsyms_local(ksyms); 1096 + token_kallsyms__destroy(skel); 1097 + return err; 1098 + } 1099 + 1054 1100 #define bit(n) (1ULL << (n)) 1055 1101 1056 1102 static int userns_bpf_token_info(int mnt_fd, struct token_lsm *lsm_skel) ··· 1140 1082 return err; 1141 1083 } 1142 1084 1143 - void test_token(void) 1085 + void serial_test_token(void) 1144 1086 { 1145 1087 if (test__start_subtest("map_token")) { 1146 1088 struct bpffs_opts opts = { ··· 1251 1193 }; 1252 1194 1253 1195 subtest_userns(&opts, userns_bpf_token_info); 1196 + } 1197 + if (test__start_subtest("obj_priv_prog_kallsyms")) { 1198 + char perf_paranoid_orig[32] = {}; 1199 + char kptr_restrict_orig[32] = {}; 1200 + struct bpffs_opts opts = { 1201 + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_PROG_LOAD), 1202 + .progs = bit(BPF_PROG_TYPE_XDP), 1203 + .attachs = ~0ULL, 1204 + }; 1205 + 1206 + if (sysctl_set_or_fail("/proc/sys/kernel/perf_event_paranoid", perf_paranoid_orig, "0")) 1207 + goto cleanup; 1208 + if (sysctl_set_or_fail("/proc/sys/kernel/kptr_restrict", kptr_restrict_orig, "0")) 1209 + goto cleanup; 1210 + 1211 + subtest_userns(&opts, userns_obj_priv_prog_kallsyms); 1212 + 1213 + cleanup: 1214 + if (perf_paranoid_orig[0]) 1215 + sysctl_set_or_fail("/proc/sys/kernel/perf_event_paranoid", NULL, perf_paranoid_orig); 1216 + if (kptr_restrict_orig[0]) 1217 + sysctl_set_or_fail("/proc/sys/kernel/kptr_restrict", NULL, kptr_restrict_orig); 1254 1218 } 1255 1219 }
+1 -20
tools/testing/selftests/bpf/prog_tests/unpriv_bpf_disabled.c
··· 8 8 9 9 #include "cap_helpers.h" 10 10 #include "bpf_util.h" 11 + #include "sysctl_helpers.h" 11 12 12 13 /* Using CAP_LAST_CAP is risky here, since it can get pulled in from 13 14 * an old /usr/include/linux/capability.h and be < CAP_BPF; as a result ··· 35 34 { 36 35 if (ASSERT_EQ(len, sizeof(__u32), "perfbuf_size_valid")) 37 36 got_perfbuf_val = *(__u32 *)data; 38 - } 39 - 40 - static int sysctl_set(const char *sysctl_path, char *old_val, const char *new_val) 41 - { 42 - int ret = 0; 43 - FILE *fp; 44 - 45 - fp = fopen(sysctl_path, "r+"); 46 - if (!fp) 47 - return -errno; 48 - if (old_val && fscanf(fp, "%s", old_val) <= 0) { 49 - ret = -ENOENT; 50 - } else if (!old_val || strcmp(old_val, new_val) != 0) { 51 - fseek(fp, 0, SEEK_SET); 52 - if (fprintf(fp, "%s", new_val) < 0) 53 - ret = -errno; 54 - } 55 - fclose(fp); 56 - 57 - return ret; 58 37 } 59 38 60 39 static void test_unpriv_bpf_disabled_positive(struct test_unpriv_bpf_disabled *skel,
+19
tools/testing/selftests/bpf/progs/token_kallsyms.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include "vmlinux.h" 5 + #include <bpf/bpf_helpers.h> 6 + 7 + char _license[] SEC("license") = "GPL"; 8 + 9 + __weak 10 + int token_ksym_subprog(void) 11 + { 12 + return 0; 13 + } 14 + 15 + SEC("xdp") 16 + int xdp_main(struct xdp_md *xdp) 17 + { 18 + return token_ksym_subprog(); 19 + }
+37
tools/testing/selftests/bpf/sysctl_helpers.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <stdio.h> 3 + #include <errno.h> 4 + #include <string.h> 5 + 6 + #include "sysctl_helpers.h" 7 + #include "test_progs.h" 8 + 9 + int sysctl_set(const char *sysctl_path, char *old_val, const char *new_val) 10 + { 11 + int ret = 0; 12 + FILE *fp; 13 + 14 + fp = fopen(sysctl_path, "r+"); 15 + if (!fp) 16 + return -errno; 17 + if (old_val && fscanf(fp, "%s", old_val) <= 0) { 18 + ret = -ENOENT; 19 + } else if (!old_val || strcmp(old_val, new_val) != 0) { 20 + fseek(fp, 0, SEEK_SET); 21 + if (fprintf(fp, "%s", new_val) < 0) 22 + ret = -errno; 23 + } 24 + fclose(fp); 25 + 26 + return ret; 27 + } 28 + 29 + int sysctl_set_or_fail(const char *sysctl_path, char *old_val, const char *new_val) 30 + { 31 + int err; 32 + 33 + err = sysctl_set(sysctl_path, old_val, new_val); 34 + if (err) 35 + PRINT_FAIL("failed to set %s to %s: %s\n", sysctl_path, new_val, strerror(-err)); 36 + return err; 37 + }
+8
tools/testing/selftests/bpf/sysctl_helpers.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __SYSCTL_HELPERS_H 3 + #define __SYSCTL_HELPERS_H 4 + 5 + int sysctl_set(const char *sysctl_path, char *old_val, const char *new_val); 6 + int sysctl_set_or_fail(const char *sysctl_path, char *old_val, const char *new_val); 7 + 8 + #endif