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-token-support-in-libbpf-s-bpf-object'

Andrii Nakryiko says:

====================
BPF token support in libbpf's BPF object

Add fuller support for BPF token in high-level BPF object APIs. This is the
most frequently used way to work with BPF using libbpf, so supporting BPF
token there is critical.

Patch #1 is improving kernel-side BPF_TOKEN_CREATE behavior by rejecting to
create "empty" BPF token with no delegation. This seems like saner behavior
which also makes libbpf's caching better overall. If we ever want to create
BPF token with no delegate_xxx options set on BPF FS, we can use a new flag to
enable that.

Patches #2-#5 refactor libbpf internals, mostly feature detection code, to
prepare it from BPF token FD.

Patch #6 adds options to pass BPF token into BPF object open options. It also
adds implicit BPF token creation logic to BPF object load step, even without
any explicit involvement of the user. If the environment is setup properly,
BPF token will be created transparently and used implicitly. This allows for
all existing application to gain BPF token support by just linking with
latest version of libbpf library. No source code modifications are required.
All that under assumption that privileged container management agent properly
set up default BPF FS instance at /sys/bpf/fs to allow BPF token creation.

Patches #7-#8 adds more selftests, validating BPF object APIs work as expected
under unprivileged user namespaced conditions in the presence of BPF token.

Patch #9 extends libbpf with LIBBPF_BPF_TOKEN_PATH envvar knowledge, which can
be used to override custom BPF FS location used for implicit BPF token
creation logic without needing to adjust application code. This allows admins
or container managers to mount BPF token-enabled BPF FS at non-standard
location without the need to coordinate with applications.
LIBBPF_BPF_TOKEN_PATH can also be used to disable BPF token implicit creation
by setting it to an empty value. Patch #10 tests this new envvar functionality.

v2->v3:
- move some stray feature cache refactorings into patch #4 (Alexei);
- add LIBBPF_BPF_TOKEN_PATH envvar support (Alexei);
v1->v2:
- remove minor code redundancies (Eduard, John);
- add acks and rebase.
====================

Link: https://lore.kernel.org/r/20231213190842.3844987-1-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+1065 -473
+9 -1
kernel/bpf/token.c
··· 152 152 goto out_path; 153 153 } 154 154 155 + mnt_opts = path.dentry->d_sb->s_fs_info; 156 + if (mnt_opts->delegate_cmds == 0 && 157 + mnt_opts->delegate_maps == 0 && 158 + mnt_opts->delegate_progs == 0 && 159 + mnt_opts->delegate_attachs == 0) { 160 + err = -ENOENT; /* no BPF token delegation is set up */ 161 + goto out_path; 162 + } 163 + 155 164 mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask()); 156 165 inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode); 157 166 if (IS_ERR(inode)) { ··· 190 181 /* remember bpffs owning userns for future ns_capable() checks */ 191 182 token->userns = get_user_ns(userns); 192 183 193 - mnt_opts = path.dentry->d_sb->s_fs_info; 194 184 token->allowed_cmds = mnt_opts->delegate_cmds; 195 185 token->allowed_maps = mnt_opts->delegate_maps; 196 186 token->allowed_progs = mnt_opts->delegate_progs;
+1 -1
tools/lib/bpf/Build
··· 1 1 libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o \ 2 2 netlink.o bpf_prog_linfo.o libbpf_probes.o hashmap.o \ 3 3 btf_dump.o ringbuf.o strset.o linker.o gen_loader.o relo_core.o \ 4 - usdt.o zip.o elf.o 4 + usdt.o zip.o elf.o features.o
+5 -4
tools/lib/bpf/bpf.c
··· 103 103 * [0] https://lore.kernel.org/bpf/20201201215900.3569844-1-guro@fb.com/ 104 104 * [1] d05512618056 ("bpf: Add bpf_ktime_get_coarse_ns helper") 105 105 */ 106 - int probe_memcg_account(void) 106 + int probe_memcg_account(int token_fd) 107 107 { 108 108 const size_t attr_sz = offsetofend(union bpf_attr, attach_btf_obj_fd); 109 109 struct bpf_insn insns[] = { ··· 120 120 attr.insns = ptr_to_u64(insns); 121 121 attr.insn_cnt = insn_cnt; 122 122 attr.license = ptr_to_u64("GPL"); 123 + attr.prog_token_fd = token_fd; 123 124 124 125 prog_fd = sys_bpf_fd(BPF_PROG_LOAD, &attr, attr_sz); 125 126 if (prog_fd >= 0) { ··· 147 146 struct rlimit rlim; 148 147 149 148 /* if kernel supports memcg-based accounting, skip bumping RLIMIT_MEMLOCK */ 150 - if (memlock_bumped || kernel_supports(NULL, FEAT_MEMCG_ACCOUNT)) 149 + if (memlock_bumped || feat_supported(NULL, FEAT_MEMCG_ACCOUNT)) 151 150 return 0; 152 151 153 152 memlock_bumped = true; ··· 182 181 return libbpf_err(-EINVAL); 183 182 184 183 attr.map_type = map_type; 185 - if (map_name && kernel_supports(NULL, FEAT_PROG_NAME)) 184 + if (map_name && feat_supported(NULL, FEAT_PROG_NAME)) 186 185 libbpf_strlcpy(attr.map_name, map_name, sizeof(attr.map_name)); 187 186 attr.key_size = key_size; 188 187 attr.value_size = value_size; ··· 266 265 attr.kern_version = OPTS_GET(opts, kern_version, 0); 267 266 attr.prog_token_fd = OPTS_GET(opts, token_fd, 0); 268 267 269 - if (prog_name && kernel_supports(NULL, FEAT_PROG_NAME)) 268 + if (prog_name && feat_supported(NULL, FEAT_PROG_NAME)) 270 269 libbpf_strlcpy(attr.prog_name, prog_name, sizeof(attr.prog_name)); 271 270 attr.license = ptr_to_u64(license); 272 271
+5 -2
tools/lib/bpf/btf.c
··· 1317 1317 1318 1318 static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endian); 1319 1319 1320 - int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level) 1320 + int btf_load_into_kernel(struct btf *btf, 1321 + char *log_buf, size_t log_sz, __u32 log_level, 1322 + int token_fd) 1321 1323 { 1322 1324 LIBBPF_OPTS(bpf_btf_load_opts, opts); 1323 1325 __u32 buf_sz = 0, raw_size; ··· 1369 1367 opts.log_level = log_level; 1370 1368 } 1371 1369 1370 + opts.token_fd = token_fd; 1372 1371 btf->fd = bpf_btf_load(raw_data, raw_size, &opts); 1373 1372 if (btf->fd < 0) { 1374 1373 /* time to turn on verbose mode and try again */ ··· 1397 1394 1398 1395 int btf__load_into_kernel(struct btf *btf) 1399 1396 { 1400 - return btf_load_into_kernel(btf, NULL, 0, 0); 1397 + return btf_load_into_kernel(btf, NULL, 0, 0, 0); 1401 1398 } 1402 1399 1403 1400 int btf__fd(const struct btf *btf)
-2
tools/lib/bpf/elf.c
··· 11 11 #include "libbpf_internal.h" 12 12 #include "str_error.h" 13 13 14 - #define STRERR_BUFSIZE 128 15 - 16 14 /* A SHT_GNU_versym section holds 16-bit words. This bit is set if 17 15 * the symbol is hidden and can only be seen when referenced using an 18 16 * explicit version number. This is a GNU extension.
+478
tools/lib/bpf/features.c
··· 1 + // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 + /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 + #include <linux/kernel.h> 4 + #include <linux/filter.h> 5 + #include "bpf.h" 6 + #include "libbpf.h" 7 + #include "libbpf_common.h" 8 + #include "libbpf_internal.h" 9 + #include "str_error.h" 10 + 11 + static inline __u64 ptr_to_u64(const void *ptr) 12 + { 13 + return (__u64)(unsigned long)ptr; 14 + } 15 + 16 + static int probe_fd(int fd) 17 + { 18 + if (fd >= 0) 19 + close(fd); 20 + return fd >= 0; 21 + } 22 + 23 + static int probe_kern_prog_name(int token_fd) 24 + { 25 + const size_t attr_sz = offsetofend(union bpf_attr, prog_name); 26 + struct bpf_insn insns[] = { 27 + BPF_MOV64_IMM(BPF_REG_0, 0), 28 + BPF_EXIT_INSN(), 29 + }; 30 + union bpf_attr attr; 31 + int ret; 32 + 33 + memset(&attr, 0, attr_sz); 34 + attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; 35 + attr.license = ptr_to_u64("GPL"); 36 + attr.insns = ptr_to_u64(insns); 37 + attr.insn_cnt = (__u32)ARRAY_SIZE(insns); 38 + attr.prog_token_fd = token_fd; 39 + libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name)); 40 + 41 + /* make sure loading with name works */ 42 + ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS); 43 + return probe_fd(ret); 44 + } 45 + 46 + static int probe_kern_global_data(int token_fd) 47 + { 48 + char *cp, errmsg[STRERR_BUFSIZE]; 49 + struct bpf_insn insns[] = { 50 + BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), 51 + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), 52 + BPF_MOV64_IMM(BPF_REG_0, 0), 53 + BPF_EXIT_INSN(), 54 + }; 55 + LIBBPF_OPTS(bpf_map_create_opts, map_opts, .token_fd = token_fd); 56 + LIBBPF_OPTS(bpf_prog_load_opts, prog_opts, .token_fd = token_fd); 57 + int ret, map, insn_cnt = ARRAY_SIZE(insns); 58 + 59 + map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, &map_opts); 60 + if (map < 0) { 61 + ret = -errno; 62 + cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); 63 + pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", 64 + __func__, cp, -ret); 65 + return ret; 66 + } 67 + 68 + insns[0].imm = map; 69 + 70 + ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts); 71 + close(map); 72 + return probe_fd(ret); 73 + } 74 + 75 + static int probe_kern_btf(int token_fd) 76 + { 77 + static const char strs[] = "\0int"; 78 + __u32 types[] = { 79 + /* int */ 80 + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), 81 + }; 82 + 83 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 84 + strs, sizeof(strs), token_fd)); 85 + } 86 + 87 + static int probe_kern_btf_func(int token_fd) 88 + { 89 + static const char strs[] = "\0int\0x\0a"; 90 + /* void x(int a) {} */ 91 + __u32 types[] = { 92 + /* int */ 93 + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 94 + /* FUNC_PROTO */ /* [2] */ 95 + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), 96 + BTF_PARAM_ENC(7, 1), 97 + /* FUNC x */ /* [3] */ 98 + BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2), 99 + }; 100 + 101 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 102 + strs, sizeof(strs), token_fd)); 103 + } 104 + 105 + static int probe_kern_btf_func_global(int token_fd) 106 + { 107 + static const char strs[] = "\0int\0x\0a"; 108 + /* static void x(int a) {} */ 109 + __u32 types[] = { 110 + /* int */ 111 + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 112 + /* FUNC_PROTO */ /* [2] */ 113 + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), 114 + BTF_PARAM_ENC(7, 1), 115 + /* FUNC x BTF_FUNC_GLOBAL */ /* [3] */ 116 + BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2), 117 + }; 118 + 119 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 120 + strs, sizeof(strs), token_fd)); 121 + } 122 + 123 + static int probe_kern_btf_datasec(int token_fd) 124 + { 125 + static const char strs[] = "\0x\0.data"; 126 + /* static int a; */ 127 + __u32 types[] = { 128 + /* int */ 129 + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 130 + /* VAR x */ /* [2] */ 131 + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), 132 + BTF_VAR_STATIC, 133 + /* DATASEC val */ /* [3] */ 134 + BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4), 135 + BTF_VAR_SECINFO_ENC(2, 0, 4), 136 + }; 137 + 138 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 139 + strs, sizeof(strs), token_fd)); 140 + } 141 + 142 + static int probe_kern_btf_float(int token_fd) 143 + { 144 + static const char strs[] = "\0float"; 145 + __u32 types[] = { 146 + /* float */ 147 + BTF_TYPE_FLOAT_ENC(1, 4), 148 + }; 149 + 150 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 151 + strs, sizeof(strs), token_fd)); 152 + } 153 + 154 + static int probe_kern_btf_decl_tag(int token_fd) 155 + { 156 + static const char strs[] = "\0tag"; 157 + __u32 types[] = { 158 + /* int */ 159 + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 160 + /* VAR x */ /* [2] */ 161 + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), 162 + BTF_VAR_STATIC, 163 + /* attr */ 164 + BTF_TYPE_DECL_TAG_ENC(1, 2, -1), 165 + }; 166 + 167 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 168 + strs, sizeof(strs), token_fd)); 169 + } 170 + 171 + static int probe_kern_btf_type_tag(int token_fd) 172 + { 173 + static const char strs[] = "\0tag"; 174 + __u32 types[] = { 175 + /* int */ 176 + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 177 + /* attr */ 178 + BTF_TYPE_TYPE_TAG_ENC(1, 1), /* [2] */ 179 + /* ptr */ 180 + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */ 181 + }; 182 + 183 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 184 + strs, sizeof(strs), token_fd)); 185 + } 186 + 187 + static int probe_kern_array_mmap(int token_fd) 188 + { 189 + LIBBPF_OPTS(bpf_map_create_opts, opts, 190 + .map_flags = BPF_F_MMAPABLE, 191 + .token_fd = token_fd, 192 + ); 193 + int fd; 194 + 195 + fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts); 196 + return probe_fd(fd); 197 + } 198 + 199 + static int probe_kern_exp_attach_type(int token_fd) 200 + { 201 + LIBBPF_OPTS(bpf_prog_load_opts, opts, 202 + .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE, 203 + .token_fd = token_fd, 204 + ); 205 + struct bpf_insn insns[] = { 206 + BPF_MOV64_IMM(BPF_REG_0, 0), 207 + BPF_EXIT_INSN(), 208 + }; 209 + int fd, insn_cnt = ARRAY_SIZE(insns); 210 + 211 + /* use any valid combination of program type and (optional) 212 + * non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS) 213 + * to see if kernel supports expected_attach_type field for 214 + * BPF_PROG_LOAD command 215 + */ 216 + fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts); 217 + return probe_fd(fd); 218 + } 219 + 220 + static int probe_kern_probe_read_kernel(int token_fd) 221 + { 222 + LIBBPF_OPTS(bpf_prog_load_opts, opts, .token_fd = token_fd); 223 + struct bpf_insn insns[] = { 224 + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */ 225 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */ 226 + BPF_MOV64_IMM(BPF_REG_2, 8), /* r2 = 8 */ 227 + BPF_MOV64_IMM(BPF_REG_3, 0), /* r3 = 0 */ 228 + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel), 229 + BPF_EXIT_INSN(), 230 + }; 231 + int fd, insn_cnt = ARRAY_SIZE(insns); 232 + 233 + fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); 234 + return probe_fd(fd); 235 + } 236 + 237 + static int probe_prog_bind_map(int token_fd) 238 + { 239 + char *cp, errmsg[STRERR_BUFSIZE]; 240 + struct bpf_insn insns[] = { 241 + BPF_MOV64_IMM(BPF_REG_0, 0), 242 + BPF_EXIT_INSN(), 243 + }; 244 + LIBBPF_OPTS(bpf_map_create_opts, map_opts, .token_fd = token_fd); 245 + LIBBPF_OPTS(bpf_prog_load_opts, prog_opts, .token_fd = token_fd); 246 + int ret, map, prog, insn_cnt = ARRAY_SIZE(insns); 247 + 248 + map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, &map_opts); 249 + if (map < 0) { 250 + ret = -errno; 251 + cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); 252 + pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", 253 + __func__, cp, -ret); 254 + return ret; 255 + } 256 + 257 + prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &prog_opts); 258 + if (prog < 0) { 259 + close(map); 260 + return 0; 261 + } 262 + 263 + ret = bpf_prog_bind_map(prog, map, NULL); 264 + 265 + close(map); 266 + close(prog); 267 + 268 + return ret >= 0; 269 + } 270 + 271 + static int probe_module_btf(int token_fd) 272 + { 273 + static const char strs[] = "\0int"; 274 + __u32 types[] = { 275 + /* int */ 276 + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), 277 + }; 278 + struct bpf_btf_info info; 279 + __u32 len = sizeof(info); 280 + char name[16]; 281 + int fd, err; 282 + 283 + fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs), token_fd); 284 + if (fd < 0) 285 + return 0; /* BTF not supported at all */ 286 + 287 + memset(&info, 0, sizeof(info)); 288 + info.name = ptr_to_u64(name); 289 + info.name_len = sizeof(name); 290 + 291 + /* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer; 292 + * kernel's module BTF support coincides with support for 293 + * name/name_len fields in struct bpf_btf_info. 294 + */ 295 + err = bpf_btf_get_info_by_fd(fd, &info, &len); 296 + close(fd); 297 + return !err; 298 + } 299 + 300 + static int probe_perf_link(int token_fd) 301 + { 302 + struct bpf_insn insns[] = { 303 + BPF_MOV64_IMM(BPF_REG_0, 0), 304 + BPF_EXIT_INSN(), 305 + }; 306 + LIBBPF_OPTS(bpf_prog_load_opts, opts, .token_fd = token_fd); 307 + int prog_fd, link_fd, err; 308 + 309 + prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", 310 + insns, ARRAY_SIZE(insns), &opts); 311 + if (prog_fd < 0) 312 + return -errno; 313 + 314 + /* use invalid perf_event FD to get EBADF, if link is supported; 315 + * otherwise EINVAL should be returned 316 + */ 317 + link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL); 318 + err = -errno; /* close() can clobber errno */ 319 + 320 + if (link_fd >= 0) 321 + close(link_fd); 322 + close(prog_fd); 323 + 324 + return link_fd < 0 && err == -EBADF; 325 + } 326 + 327 + static int probe_uprobe_multi_link(int token_fd) 328 + { 329 + LIBBPF_OPTS(bpf_prog_load_opts, load_opts, 330 + .expected_attach_type = BPF_TRACE_UPROBE_MULTI, 331 + .token_fd = token_fd, 332 + ); 333 + LIBBPF_OPTS(bpf_link_create_opts, link_opts); 334 + struct bpf_insn insns[] = { 335 + BPF_MOV64_IMM(BPF_REG_0, 0), 336 + BPF_EXIT_INSN(), 337 + }; 338 + int prog_fd, link_fd, err; 339 + unsigned long offset = 0; 340 + 341 + prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", 342 + insns, ARRAY_SIZE(insns), &load_opts); 343 + if (prog_fd < 0) 344 + return -errno; 345 + 346 + /* Creating uprobe in '/' binary should fail with -EBADF. */ 347 + link_opts.uprobe_multi.path = "/"; 348 + link_opts.uprobe_multi.offsets = &offset; 349 + link_opts.uprobe_multi.cnt = 1; 350 + 351 + link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts); 352 + err = -errno; /* close() can clobber errno */ 353 + 354 + if (link_fd >= 0) 355 + close(link_fd); 356 + close(prog_fd); 357 + 358 + return link_fd < 0 && err == -EBADF; 359 + } 360 + 361 + static int probe_kern_bpf_cookie(int token_fd) 362 + { 363 + struct bpf_insn insns[] = { 364 + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie), 365 + BPF_EXIT_INSN(), 366 + }; 367 + LIBBPF_OPTS(bpf_prog_load_opts, opts, .token_fd = token_fd); 368 + int ret, insn_cnt = ARRAY_SIZE(insns); 369 + 370 + ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); 371 + return probe_fd(ret); 372 + } 373 + 374 + static int probe_kern_btf_enum64(int token_fd) 375 + { 376 + static const char strs[] = "\0enum64"; 377 + __u32 types[] = { 378 + BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8), 379 + }; 380 + 381 + return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 382 + strs, sizeof(strs), token_fd)); 383 + } 384 + 385 + typedef int (*feature_probe_fn)(int /* token_fd */); 386 + 387 + static struct kern_feature_cache feature_cache; 388 + 389 + static struct kern_feature_desc { 390 + const char *desc; 391 + feature_probe_fn probe; 392 + } feature_probes[__FEAT_CNT] = { 393 + [FEAT_PROG_NAME] = { 394 + "BPF program name", probe_kern_prog_name, 395 + }, 396 + [FEAT_GLOBAL_DATA] = { 397 + "global variables", probe_kern_global_data, 398 + }, 399 + [FEAT_BTF] = { 400 + "minimal BTF", probe_kern_btf, 401 + }, 402 + [FEAT_BTF_FUNC] = { 403 + "BTF functions", probe_kern_btf_func, 404 + }, 405 + [FEAT_BTF_GLOBAL_FUNC] = { 406 + "BTF global function", probe_kern_btf_func_global, 407 + }, 408 + [FEAT_BTF_DATASEC] = { 409 + "BTF data section and variable", probe_kern_btf_datasec, 410 + }, 411 + [FEAT_ARRAY_MMAP] = { 412 + "ARRAY map mmap()", probe_kern_array_mmap, 413 + }, 414 + [FEAT_EXP_ATTACH_TYPE] = { 415 + "BPF_PROG_LOAD expected_attach_type attribute", 416 + probe_kern_exp_attach_type, 417 + }, 418 + [FEAT_PROBE_READ_KERN] = { 419 + "bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel, 420 + }, 421 + [FEAT_PROG_BIND_MAP] = { 422 + "BPF_PROG_BIND_MAP support", probe_prog_bind_map, 423 + }, 424 + [FEAT_MODULE_BTF] = { 425 + "module BTF support", probe_module_btf, 426 + }, 427 + [FEAT_BTF_FLOAT] = { 428 + "BTF_KIND_FLOAT support", probe_kern_btf_float, 429 + }, 430 + [FEAT_PERF_LINK] = { 431 + "BPF perf link support", probe_perf_link, 432 + }, 433 + [FEAT_BTF_DECL_TAG] = { 434 + "BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag, 435 + }, 436 + [FEAT_BTF_TYPE_TAG] = { 437 + "BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag, 438 + }, 439 + [FEAT_MEMCG_ACCOUNT] = { 440 + "memcg-based memory accounting", probe_memcg_account, 441 + }, 442 + [FEAT_BPF_COOKIE] = { 443 + "BPF cookie support", probe_kern_bpf_cookie, 444 + }, 445 + [FEAT_BTF_ENUM64] = { 446 + "BTF_KIND_ENUM64 support", probe_kern_btf_enum64, 447 + }, 448 + [FEAT_SYSCALL_WRAPPER] = { 449 + "Kernel using syscall wrapper", probe_kern_syscall_wrapper, 450 + }, 451 + [FEAT_UPROBE_MULTI_LINK] = { 452 + "BPF multi-uprobe link support", probe_uprobe_multi_link, 453 + }, 454 + }; 455 + 456 + bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id) 457 + { 458 + struct kern_feature_desc *feat = &feature_probes[feat_id]; 459 + int ret; 460 + 461 + /* assume global feature cache, unless custom one is provided */ 462 + if (!cache) 463 + cache = &feature_cache; 464 + 465 + if (READ_ONCE(cache->res[feat_id]) == FEAT_UNKNOWN) { 466 + ret = feat->probe(cache->token_fd); 467 + if (ret > 0) { 468 + WRITE_ONCE(cache->res[feat_id], FEAT_SUPPORTED); 469 + } else if (ret == 0) { 470 + WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); 471 + } else { 472 + pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret); 473 + WRITE_ONCE(cache->res[feat_id], FEAT_MISSING); 474 + } 475 + } 476 + 477 + return READ_ONCE(cache->res[feat_id]) == FEAT_SUPPORTED; 478 + }
+118 -455
tools/lib/bpf/libbpf.c
··· 59 59 #define BPF_FS_MAGIC 0xcafe4a11 60 60 #endif 61 61 62 + #define BPF_FS_DEFAULT_PATH "/sys/fs/bpf" 63 + 62 64 #define BPF_INSN_SZ (sizeof(struct bpf_insn)) 63 65 64 66 /* vsprintf() in __base_pr() uses nonliteral format string. It may break ··· 694 692 size_t fd_array_cnt; 695 693 696 694 struct usdt_manager *usdt_man; 695 + 696 + struct kern_feature_cache *feat_cache; 697 + char *token_path; 698 + int token_fd; 697 699 698 700 char path[]; 699 701 }; ··· 2198 2192 int err; 2199 2193 2200 2194 if (!path) 2201 - path = "/sys/fs/bpf"; 2195 + path = BPF_FS_DEFAULT_PATH; 2202 2196 2203 2197 err = pathname_concat(buf, sizeof(buf), path, bpf_map__name(map)); 2204 2198 if (err) ··· 3285 3279 } else { 3286 3280 /* currently BPF_BTF_LOAD only supports log_level 1 */ 3287 3281 err = btf_load_into_kernel(kern_btf, obj->log_buf, obj->log_size, 3288 - obj->log_level ? 1 : 0); 3282 + obj->log_level ? 1 : 0, obj->token_fd); 3289 3283 } 3290 3284 if (sanitize) { 3291 3285 if (!err) { ··· 4608 4602 return 0; 4609 4603 } 4610 4604 4605 + static int bpf_object_prepare_token(struct bpf_object *obj) 4606 + { 4607 + const char *bpffs_path; 4608 + int bpffs_fd = -1, token_fd, err; 4609 + bool mandatory; 4610 + enum libbpf_print_level level; 4611 + 4612 + /* token is already set up */ 4613 + if (obj->token_fd > 0) 4614 + return 0; 4615 + /* token is explicitly prevented */ 4616 + if (obj->token_fd < 0) { 4617 + pr_debug("object '%s': token is prevented, skipping...\n", obj->name); 4618 + /* reset to zero to avoid extra checks during map_create and prog_load steps */ 4619 + obj->token_fd = 0; 4620 + return 0; 4621 + } 4622 + 4623 + mandatory = obj->token_path != NULL; 4624 + level = mandatory ? LIBBPF_WARN : LIBBPF_DEBUG; 4625 + 4626 + bpffs_path = obj->token_path ?: BPF_FS_DEFAULT_PATH; 4627 + bpffs_fd = open(bpffs_path, O_DIRECTORY, O_RDWR); 4628 + if (bpffs_fd < 0) { 4629 + err = -errno; 4630 + __pr(level, "object '%s': failed (%d) to open BPF FS mount at '%s'%s\n", 4631 + obj->name, err, bpffs_path, 4632 + mandatory ? "" : ", skipping optional step..."); 4633 + return mandatory ? err : 0; 4634 + } 4635 + 4636 + token_fd = bpf_token_create(bpffs_fd, 0); 4637 + close(bpffs_fd); 4638 + if (token_fd < 0) { 4639 + if (!mandatory && token_fd == -ENOENT) { 4640 + pr_debug("object '%s': BPF FS at '%s' doesn't have BPF token delegation set up, skipping...\n", 4641 + obj->name, bpffs_path); 4642 + return 0; 4643 + } 4644 + __pr(level, "object '%s': failed (%d) to create BPF token from '%s'%s\n", 4645 + obj->name, token_fd, bpffs_path, 4646 + mandatory ? "" : ", skipping optional step..."); 4647 + return mandatory ? token_fd : 0; 4648 + } 4649 + 4650 + obj->feat_cache = calloc(1, sizeof(*obj->feat_cache)); 4651 + if (!obj->feat_cache) { 4652 + close(token_fd); 4653 + return -ENOMEM; 4654 + } 4655 + 4656 + obj->token_fd = token_fd; 4657 + obj->feat_cache->token_fd = token_fd; 4658 + 4659 + return 0; 4660 + } 4661 + 4611 4662 static int 4612 4663 bpf_object__probe_loading(struct bpf_object *obj) 4613 4664 { ··· 4674 4611 BPF_EXIT_INSN(), 4675 4612 }; 4676 4613 int ret, insn_cnt = ARRAY_SIZE(insns); 4614 + LIBBPF_OPTS(bpf_prog_load_opts, opts, .token_fd = obj->token_fd); 4677 4615 4678 4616 if (obj->gen_loader) 4679 4617 return 0; ··· 4684 4620 pr_warn("Failed to bump RLIMIT_MEMLOCK (err = %d), you might need to do it explicitly!\n", ret); 4685 4621 4686 4622 /* make sure basic loading works */ 4687 - ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); 4623 + ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, &opts); 4688 4624 if (ret < 0) 4689 - ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL); 4625 + ret = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, &opts); 4690 4626 if (ret < 0) { 4691 4627 ret = errno; 4692 4628 cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); ··· 4701 4637 return 0; 4702 4638 } 4703 4639 4704 - static int probe_fd(int fd) 4705 - { 4706 - if (fd >= 0) 4707 - close(fd); 4708 - return fd >= 0; 4709 - } 4710 - 4711 - static int probe_kern_prog_name(void) 4712 - { 4713 - const size_t attr_sz = offsetofend(union bpf_attr, prog_name); 4714 - struct bpf_insn insns[] = { 4715 - BPF_MOV64_IMM(BPF_REG_0, 0), 4716 - BPF_EXIT_INSN(), 4717 - }; 4718 - union bpf_attr attr; 4719 - int ret; 4720 - 4721 - memset(&attr, 0, attr_sz); 4722 - attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; 4723 - attr.license = ptr_to_u64("GPL"); 4724 - attr.insns = ptr_to_u64(insns); 4725 - attr.insn_cnt = (__u32)ARRAY_SIZE(insns); 4726 - libbpf_strlcpy(attr.prog_name, "libbpf_nametest", sizeof(attr.prog_name)); 4727 - 4728 - /* make sure loading with name works */ 4729 - ret = sys_bpf_prog_load(&attr, attr_sz, PROG_LOAD_ATTEMPTS); 4730 - return probe_fd(ret); 4731 - } 4732 - 4733 - static int probe_kern_global_data(void) 4734 - { 4735 - char *cp, errmsg[STRERR_BUFSIZE]; 4736 - struct bpf_insn insns[] = { 4737 - BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), 4738 - BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), 4739 - BPF_MOV64_IMM(BPF_REG_0, 0), 4740 - BPF_EXIT_INSN(), 4741 - }; 4742 - int ret, map, insn_cnt = ARRAY_SIZE(insns); 4743 - 4744 - map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_global", sizeof(int), 32, 1, NULL); 4745 - if (map < 0) { 4746 - ret = -errno; 4747 - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); 4748 - pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", 4749 - __func__, cp, -ret); 4750 - return ret; 4751 - } 4752 - 4753 - insns[0].imm = map; 4754 - 4755 - ret = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); 4756 - close(map); 4757 - return probe_fd(ret); 4758 - } 4759 - 4760 - static int probe_kern_btf(void) 4761 - { 4762 - static const char strs[] = "\0int"; 4763 - __u32 types[] = { 4764 - /* int */ 4765 - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), 4766 - }; 4767 - 4768 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4769 - strs, sizeof(strs))); 4770 - } 4771 - 4772 - static int probe_kern_btf_func(void) 4773 - { 4774 - static const char strs[] = "\0int\0x\0a"; 4775 - /* void x(int a) {} */ 4776 - __u32 types[] = { 4777 - /* int */ 4778 - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 4779 - /* FUNC_PROTO */ /* [2] */ 4780 - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), 4781 - BTF_PARAM_ENC(7, 1), 4782 - /* FUNC x */ /* [3] */ 4783 - BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 0), 2), 4784 - }; 4785 - 4786 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4787 - strs, sizeof(strs))); 4788 - } 4789 - 4790 - static int probe_kern_btf_func_global(void) 4791 - { 4792 - static const char strs[] = "\0int\0x\0a"; 4793 - /* static void x(int a) {} */ 4794 - __u32 types[] = { 4795 - /* int */ 4796 - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 4797 - /* FUNC_PROTO */ /* [2] */ 4798 - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), 4799 - BTF_PARAM_ENC(7, 1), 4800 - /* FUNC x BTF_FUNC_GLOBAL */ /* [3] */ 4801 - BTF_TYPE_ENC(5, BTF_INFO_ENC(BTF_KIND_FUNC, 0, BTF_FUNC_GLOBAL), 2), 4802 - }; 4803 - 4804 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4805 - strs, sizeof(strs))); 4806 - } 4807 - 4808 - static int probe_kern_btf_datasec(void) 4809 - { 4810 - static const char strs[] = "\0x\0.data"; 4811 - /* static int a; */ 4812 - __u32 types[] = { 4813 - /* int */ 4814 - BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 4815 - /* VAR x */ /* [2] */ 4816 - BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), 4817 - BTF_VAR_STATIC, 4818 - /* DATASEC val */ /* [3] */ 4819 - BTF_TYPE_ENC(3, BTF_INFO_ENC(BTF_KIND_DATASEC, 0, 1), 4), 4820 - BTF_VAR_SECINFO_ENC(2, 0, 4), 4821 - }; 4822 - 4823 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4824 - strs, sizeof(strs))); 4825 - } 4826 - 4827 - static int probe_kern_btf_float(void) 4828 - { 4829 - static const char strs[] = "\0float"; 4830 - __u32 types[] = { 4831 - /* float */ 4832 - BTF_TYPE_FLOAT_ENC(1, 4), 4833 - }; 4834 - 4835 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4836 - strs, sizeof(strs))); 4837 - } 4838 - 4839 - static int probe_kern_btf_decl_tag(void) 4840 - { 4841 - static const char strs[] = "\0tag"; 4842 - __u32 types[] = { 4843 - /* int */ 4844 - BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 4845 - /* VAR x */ /* [2] */ 4846 - BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_VAR, 0, 0), 1), 4847 - BTF_VAR_STATIC, 4848 - /* attr */ 4849 - BTF_TYPE_DECL_TAG_ENC(1, 2, -1), 4850 - }; 4851 - 4852 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4853 - strs, sizeof(strs))); 4854 - } 4855 - 4856 - static int probe_kern_btf_type_tag(void) 4857 - { 4858 - static const char strs[] = "\0tag"; 4859 - __u32 types[] = { 4860 - /* int */ 4861 - BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 4862 - /* attr */ 4863 - BTF_TYPE_TYPE_TAG_ENC(1, 1), /* [2] */ 4864 - /* ptr */ 4865 - BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */ 4866 - }; 4867 - 4868 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 4869 - strs, sizeof(strs))); 4870 - } 4871 - 4872 - static int probe_kern_array_mmap(void) 4873 - { 4874 - LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE); 4875 - int fd; 4876 - 4877 - fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_mmap", sizeof(int), sizeof(int), 1, &opts); 4878 - return probe_fd(fd); 4879 - } 4880 - 4881 - static int probe_kern_exp_attach_type(void) 4882 - { 4883 - LIBBPF_OPTS(bpf_prog_load_opts, opts, .expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE); 4884 - struct bpf_insn insns[] = { 4885 - BPF_MOV64_IMM(BPF_REG_0, 0), 4886 - BPF_EXIT_INSN(), 4887 - }; 4888 - int fd, insn_cnt = ARRAY_SIZE(insns); 4889 - 4890 - /* use any valid combination of program type and (optional) 4891 - * non-zero expected attach type (i.e., not a BPF_CGROUP_INET_INGRESS) 4892 - * to see if kernel supports expected_attach_type field for 4893 - * BPF_PROG_LOAD command 4894 - */ 4895 - fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns, insn_cnt, &opts); 4896 - return probe_fd(fd); 4897 - } 4898 - 4899 - static int probe_kern_probe_read_kernel(void) 4900 - { 4901 - struct bpf_insn insns[] = { 4902 - BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), /* r1 = r10 (fp) */ 4903 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), /* r1 += -8 */ 4904 - BPF_MOV64_IMM(BPF_REG_2, 8), /* r2 = 8 */ 4905 - BPF_MOV64_IMM(BPF_REG_3, 0), /* r3 = 0 */ 4906 - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_kernel), 4907 - BPF_EXIT_INSN(), 4908 - }; 4909 - int fd, insn_cnt = ARRAY_SIZE(insns); 4910 - 4911 - fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", insns, insn_cnt, NULL); 4912 - return probe_fd(fd); 4913 - } 4914 - 4915 - static int probe_prog_bind_map(void) 4916 - { 4917 - char *cp, errmsg[STRERR_BUFSIZE]; 4918 - struct bpf_insn insns[] = { 4919 - BPF_MOV64_IMM(BPF_REG_0, 0), 4920 - BPF_EXIT_INSN(), 4921 - }; 4922 - int ret, map, prog, insn_cnt = ARRAY_SIZE(insns); 4923 - 4924 - map = bpf_map_create(BPF_MAP_TYPE_ARRAY, "libbpf_det_bind", sizeof(int), 32, 1, NULL); 4925 - if (map < 0) { 4926 - ret = -errno; 4927 - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); 4928 - pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", 4929 - __func__, cp, -ret); 4930 - return ret; 4931 - } 4932 - 4933 - prog = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns, insn_cnt, NULL); 4934 - if (prog < 0) { 4935 - close(map); 4936 - return 0; 4937 - } 4938 - 4939 - ret = bpf_prog_bind_map(prog, map, NULL); 4940 - 4941 - close(map); 4942 - close(prog); 4943 - 4944 - return ret >= 0; 4945 - } 4946 - 4947 - static int probe_module_btf(void) 4948 - { 4949 - static const char strs[] = "\0int"; 4950 - __u32 types[] = { 4951 - /* int */ 4952 - BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), 4953 - }; 4954 - struct bpf_btf_info info; 4955 - __u32 len = sizeof(info); 4956 - char name[16]; 4957 - int fd, err; 4958 - 4959 - fd = libbpf__load_raw_btf((char *)types, sizeof(types), strs, sizeof(strs)); 4960 - if (fd < 0) 4961 - return 0; /* BTF not supported at all */ 4962 - 4963 - memset(&info, 0, sizeof(info)); 4964 - info.name = ptr_to_u64(name); 4965 - info.name_len = sizeof(name); 4966 - 4967 - /* check that BPF_OBJ_GET_INFO_BY_FD supports specifying name pointer; 4968 - * kernel's module BTF support coincides with support for 4969 - * name/name_len fields in struct bpf_btf_info. 4970 - */ 4971 - err = bpf_btf_get_info_by_fd(fd, &info, &len); 4972 - close(fd); 4973 - return !err; 4974 - } 4975 - 4976 - static int probe_perf_link(void) 4977 - { 4978 - struct bpf_insn insns[] = { 4979 - BPF_MOV64_IMM(BPF_REG_0, 0), 4980 - BPF_EXIT_INSN(), 4981 - }; 4982 - int prog_fd, link_fd, err; 4983 - 4984 - prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, NULL, "GPL", 4985 - insns, ARRAY_SIZE(insns), NULL); 4986 - if (prog_fd < 0) 4987 - return -errno; 4988 - 4989 - /* use invalid perf_event FD to get EBADF, if link is supported; 4990 - * otherwise EINVAL should be returned 4991 - */ 4992 - link_fd = bpf_link_create(prog_fd, -1, BPF_PERF_EVENT, NULL); 4993 - err = -errno; /* close() can clobber errno */ 4994 - 4995 - if (link_fd >= 0) 4996 - close(link_fd); 4997 - close(prog_fd); 4998 - 4999 - return link_fd < 0 && err == -EBADF; 5000 - } 5001 - 5002 - static int probe_uprobe_multi_link(void) 5003 - { 5004 - LIBBPF_OPTS(bpf_prog_load_opts, load_opts, 5005 - .expected_attach_type = BPF_TRACE_UPROBE_MULTI, 5006 - ); 5007 - LIBBPF_OPTS(bpf_link_create_opts, link_opts); 5008 - struct bpf_insn insns[] = { 5009 - BPF_MOV64_IMM(BPF_REG_0, 0), 5010 - BPF_EXIT_INSN(), 5011 - }; 5012 - int prog_fd, link_fd, err; 5013 - unsigned long offset = 0; 5014 - 5015 - prog_fd = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", 5016 - insns, ARRAY_SIZE(insns), &load_opts); 5017 - if (prog_fd < 0) 5018 - return -errno; 5019 - 5020 - /* Creating uprobe in '/' binary should fail with -EBADF. */ 5021 - link_opts.uprobe_multi.path = "/"; 5022 - link_opts.uprobe_multi.offsets = &offset; 5023 - link_opts.uprobe_multi.cnt = 1; 5024 - 5025 - link_fd = bpf_link_create(prog_fd, -1, BPF_TRACE_UPROBE_MULTI, &link_opts); 5026 - err = -errno; /* close() can clobber errno */ 5027 - 5028 - if (link_fd >= 0) 5029 - close(link_fd); 5030 - close(prog_fd); 5031 - 5032 - return link_fd < 0 && err == -EBADF; 5033 - } 5034 - 5035 - static int probe_kern_bpf_cookie(void) 5036 - { 5037 - struct bpf_insn insns[] = { 5038 - BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_attach_cookie), 5039 - BPF_EXIT_INSN(), 5040 - }; 5041 - int ret, insn_cnt = ARRAY_SIZE(insns); 5042 - 5043 - ret = bpf_prog_load(BPF_PROG_TYPE_KPROBE, NULL, "GPL", insns, insn_cnt, NULL); 5044 - return probe_fd(ret); 5045 - } 5046 - 5047 - static int probe_kern_btf_enum64(void) 5048 - { 5049 - static const char strs[] = "\0enum64"; 5050 - __u32 types[] = { 5051 - BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8), 5052 - }; 5053 - 5054 - return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types), 5055 - strs, sizeof(strs))); 5056 - } 5057 - 5058 - static int probe_kern_syscall_wrapper(void); 5059 - 5060 - enum kern_feature_result { 5061 - FEAT_UNKNOWN = 0, 5062 - FEAT_SUPPORTED = 1, 5063 - FEAT_MISSING = 2, 5064 - }; 5065 - 5066 - typedef int (*feature_probe_fn)(void); 5067 - 5068 - static struct kern_feature_desc { 5069 - const char *desc; 5070 - feature_probe_fn probe; 5071 - enum kern_feature_result res; 5072 - } feature_probes[__FEAT_CNT] = { 5073 - [FEAT_PROG_NAME] = { 5074 - "BPF program name", probe_kern_prog_name, 5075 - }, 5076 - [FEAT_GLOBAL_DATA] = { 5077 - "global variables", probe_kern_global_data, 5078 - }, 5079 - [FEAT_BTF] = { 5080 - "minimal BTF", probe_kern_btf, 5081 - }, 5082 - [FEAT_BTF_FUNC] = { 5083 - "BTF functions", probe_kern_btf_func, 5084 - }, 5085 - [FEAT_BTF_GLOBAL_FUNC] = { 5086 - "BTF global function", probe_kern_btf_func_global, 5087 - }, 5088 - [FEAT_BTF_DATASEC] = { 5089 - "BTF data section and variable", probe_kern_btf_datasec, 5090 - }, 5091 - [FEAT_ARRAY_MMAP] = { 5092 - "ARRAY map mmap()", probe_kern_array_mmap, 5093 - }, 5094 - [FEAT_EXP_ATTACH_TYPE] = { 5095 - "BPF_PROG_LOAD expected_attach_type attribute", 5096 - probe_kern_exp_attach_type, 5097 - }, 5098 - [FEAT_PROBE_READ_KERN] = { 5099 - "bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel, 5100 - }, 5101 - [FEAT_PROG_BIND_MAP] = { 5102 - "BPF_PROG_BIND_MAP support", probe_prog_bind_map, 5103 - }, 5104 - [FEAT_MODULE_BTF] = { 5105 - "module BTF support", probe_module_btf, 5106 - }, 5107 - [FEAT_BTF_FLOAT] = { 5108 - "BTF_KIND_FLOAT support", probe_kern_btf_float, 5109 - }, 5110 - [FEAT_PERF_LINK] = { 5111 - "BPF perf link support", probe_perf_link, 5112 - }, 5113 - [FEAT_BTF_DECL_TAG] = { 5114 - "BTF_KIND_DECL_TAG support", probe_kern_btf_decl_tag, 5115 - }, 5116 - [FEAT_BTF_TYPE_TAG] = { 5117 - "BTF_KIND_TYPE_TAG support", probe_kern_btf_type_tag, 5118 - }, 5119 - [FEAT_MEMCG_ACCOUNT] = { 5120 - "memcg-based memory accounting", probe_memcg_account, 5121 - }, 5122 - [FEAT_BPF_COOKIE] = { 5123 - "BPF cookie support", probe_kern_bpf_cookie, 5124 - }, 5125 - [FEAT_BTF_ENUM64] = { 5126 - "BTF_KIND_ENUM64 support", probe_kern_btf_enum64, 5127 - }, 5128 - [FEAT_SYSCALL_WRAPPER] = { 5129 - "Kernel using syscall wrapper", probe_kern_syscall_wrapper, 5130 - }, 5131 - [FEAT_UPROBE_MULTI_LINK] = { 5132 - "BPF multi-uprobe link support", probe_uprobe_multi_link, 5133 - }, 5134 - }; 5135 - 5136 4640 bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id) 5137 4641 { 5138 - struct kern_feature_desc *feat = &feature_probes[feat_id]; 5139 - int ret; 5140 - 5141 4642 if (obj && obj->gen_loader) 5142 4643 /* To generate loader program assume the latest kernel 5143 4644 * to avoid doing extra prog_load, map_create syscalls. 5144 4645 */ 5145 4646 return true; 5146 4647 5147 - if (READ_ONCE(feat->res) == FEAT_UNKNOWN) { 5148 - ret = feat->probe(); 5149 - if (ret > 0) { 5150 - WRITE_ONCE(feat->res, FEAT_SUPPORTED); 5151 - } else if (ret == 0) { 5152 - WRITE_ONCE(feat->res, FEAT_MISSING); 5153 - } else { 5154 - pr_warn("Detection of kernel %s support failed: %d\n", feat->desc, ret); 5155 - WRITE_ONCE(feat->res, FEAT_MISSING); 5156 - } 5157 - } 4648 + if (obj->token_fd) 4649 + return feat_supported(obj->feat_cache, feat_id); 5158 4650 5159 - return READ_ONCE(feat->res) == FEAT_SUPPORTED; 4651 + return feat_supported(NULL, feat_id); 5160 4652 } 5161 4653 5162 4654 static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd) ··· 4831 5211 create_attr.map_flags = def->map_flags; 4832 5212 create_attr.numa_node = map->numa_node; 4833 5213 create_attr.map_extra = map->map_extra; 5214 + create_attr.token_fd = obj->token_fd; 4834 5215 4835 5216 if (bpf_map__is_struct_ops(map)) 4836 5217 create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id; ··· 6667 7046 load_attr.attach_btf_id = prog->attach_btf_id; 6668 7047 load_attr.kern_version = kern_version; 6669 7048 load_attr.prog_ifindex = prog->prog_ifindex; 7049 + load_attr.token_fd = obj->token_fd; 6670 7050 6671 7051 /* specify func_info/line_info only if kernel supports them */ 6672 7052 btf_fd = bpf_object__btf_fd(obj); ··· 7129 7507 static struct bpf_object *bpf_object_open(const char *path, const void *obj_buf, size_t obj_buf_sz, 7130 7508 const struct bpf_object_open_opts *opts) 7131 7509 { 7132 - const char *obj_name, *kconfig, *btf_tmp_path; 7510 + const char *obj_name, *kconfig, *btf_tmp_path, *token_path; 7133 7511 struct bpf_object *obj; 7134 7512 char tmp_name[64]; 7135 - int err; 7513 + int err, token_fd; 7136 7514 char *log_buf; 7137 7515 size_t log_size; 7138 7516 __u32 log_level; ··· 7166 7544 if (log_size && !log_buf) 7167 7545 return ERR_PTR(-EINVAL); 7168 7546 7547 + token_path = OPTS_GET(opts, bpf_token_path, NULL); 7548 + token_fd = OPTS_GET(opts, bpf_token_fd, -1); 7549 + /* non-empty token path can't be combined with invalid token FD */ 7550 + if (token_path && token_path[0] != '\0' && token_fd < 0) 7551 + return ERR_PTR(-EINVAL); 7552 + /* empty token path can't be combined with valid token FD */ 7553 + if (token_path && token_path[0] == '\0' && token_fd > 0) 7554 + return ERR_PTR(-EINVAL); 7555 + /* if user didn't specify bpf_token_path/bpf_token_fd explicitly, 7556 + * check if LIBBPF_BPF_TOKEN_PATH envvar was set and treat it as 7557 + * bpf_token_path option 7558 + */ 7559 + if (token_fd == 0 && !token_path) 7560 + token_path = getenv("LIBBPF_BPF_TOKEN_PATH"); 7561 + /* empty token_path is equivalent to invalid token_fd */ 7562 + if (token_path && token_path[0] == '\0') { 7563 + token_path = NULL; 7564 + token_fd = -1; 7565 + } 7566 + if (token_path && strlen(token_path) >= PATH_MAX) 7567 + return ERR_PTR(-ENAMETOOLONG); 7568 + 7169 7569 obj = bpf_object__new(path, obj_buf, obj_buf_sz, obj_name); 7170 7570 if (IS_ERR(obj)) 7171 7571 return obj; ··· 7195 7551 obj->log_buf = log_buf; 7196 7552 obj->log_size = log_size; 7197 7553 obj->log_level = log_level; 7554 + 7555 + obj->token_fd = token_fd <= 0 ? token_fd : dup_good_fd(token_fd); 7556 + if (token_fd > 0 && obj->token_fd < 0) { 7557 + err = -errno; 7558 + goto out; 7559 + } 7560 + if (token_path) { 7561 + obj->token_path = strdup(token_path); 7562 + if (!obj->token_path) { 7563 + err = -ENOMEM; 7564 + goto out; 7565 + } 7566 + } 7198 7567 7199 7568 btf_tmp_path = OPTS_GET(opts, btf_custom_path, NULL); 7200 7569 if (btf_tmp_path) { ··· 7719 8062 if (obj->gen_loader) 7720 8063 bpf_gen__init(obj->gen_loader, extra_log_level, obj->nr_programs, obj->nr_maps); 7721 8064 7722 - err = bpf_object__probe_loading(obj); 8065 + err = bpf_object_prepare_token(obj); 8066 + err = err ? : bpf_object__probe_loading(obj); 7723 8067 err = err ? : bpf_object__load_vmlinux_btf(obj, false); 7724 8068 err = err ? : bpf_object__resolve_externs(obj, obj->kconfig); 7725 8069 err = err ? : bpf_object__sanitize_and_load_btf(obj); ··· 8256 8598 bpf_program__exit(&obj->programs[i]); 8257 8599 } 8258 8600 zfree(&obj->programs); 8601 + 8602 + zfree(&obj->feat_cache); 8603 + zfree(&obj->token_path); 8604 + if (obj->token_fd > 0) 8605 + close(obj->token_fd); 8259 8606 8260 8607 free(obj); 8261 8608 } ··· 10275 10612 #endif 10276 10613 } 10277 10614 10278 - static int probe_kern_syscall_wrapper(void) 10615 + int probe_kern_syscall_wrapper(int token_fd) 10279 10616 { 10280 10617 char syscall_name[64]; 10281 10618 const char *ksys_pfx;
+36 -1
tools/lib/bpf/libbpf.h
··· 177 177 * logs through its print callback. 178 178 */ 179 179 __u32 kernel_log_level; 180 + /* FD of a BPF token instantiated by user through bpf_token_create() 181 + * API. BPF object will keep dup()'ed FD internally, so passed token 182 + * FD can be closed after BPF object/skeleton open step. 183 + * 184 + * Setting bpf_token_fd to negative value disables libbpf's automatic 185 + * attempt to create BPF token from default BPF FS mount point 186 + * (/sys/fs/bpf), in case this default behavior is undesirable. 187 + * 188 + * If bpf_token_path and bpf_token_fd are not specified, libbpf will 189 + * consult LIBBPF_BPF_TOKEN_PATH environment variable. If set, it will 190 + * be taken as a value of bpf_token_path option and will force libbpf 191 + * to either create BPF token from provided custom BPF FS path, or 192 + * will disable implicit BPF token creation, if envvar value is an 193 + * empty string. 194 + * 195 + * bpf_token_path and bpf_token_fd are mutually exclusive and only one 196 + * of those options should be set. Either of them overrides 197 + * LIBBPF_BPF_TOKEN_PATH envvar. 198 + */ 199 + int bpf_token_fd; 200 + /* Path to BPF FS mount point to derive BPF token from. 201 + * 202 + * Created BPF token will be used for all bpf() syscall operations 203 + * that accept BPF token (e.g., map creation, BTF and program loads, 204 + * etc) automatically within instantiated BPF object. 205 + * 206 + * Setting bpf_token_path option to empty string disables libbpf's 207 + * automatic attempt to create BPF token from default BPF FS mount 208 + * point (/sys/fs/bpf), in case this default behavior is undesirable. 209 + * 210 + * bpf_token_path and bpf_token_fd are mutually exclusive and only one 211 + * of those options should be set. Either of them overrides 212 + * LIBBPF_BPF_TOKEN_PATH envvar. 213 + */ 214 + const char *bpf_token_path; 180 215 181 216 size_t :0; 182 217 }; 183 - #define bpf_object_open_opts__last_field kernel_log_level 218 + #define bpf_object_open_opts__last_field bpf_token_path 184 219 185 220 /** 186 221 * @brief **bpf_object__open()** creates a bpf_object by opening
+32 -4
tools/lib/bpf/libbpf_internal.h
··· 360 360 __FEAT_CNT, 361 361 }; 362 362 363 - int probe_memcg_account(void); 363 + enum kern_feature_result { 364 + FEAT_UNKNOWN = 0, 365 + FEAT_SUPPORTED = 1, 366 + FEAT_MISSING = 2, 367 + }; 368 + 369 + struct kern_feature_cache { 370 + enum kern_feature_result res[__FEAT_CNT]; 371 + int token_fd; 372 + }; 373 + 374 + bool feat_supported(struct kern_feature_cache *cache, enum kern_feature_id feat_id); 364 375 bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id); 376 + 377 + int probe_kern_syscall_wrapper(int token_fd); 378 + int probe_memcg_account(int token_fd); 365 379 int bump_rlimit_memlock(void); 366 380 367 381 int parse_cpu_mask_str(const char *s, bool **mask, int *mask_sz); 368 382 int parse_cpu_mask_file(const char *fcpu, bool **mask, int *mask_sz); 369 383 int libbpf__load_raw_btf(const char *raw_types, size_t types_len, 370 - const char *str_sec, size_t str_len); 371 - int btf_load_into_kernel(struct btf *btf, char *log_buf, size_t log_sz, __u32 log_level); 384 + const char *str_sec, size_t str_len, 385 + int token_fd); 386 + int btf_load_into_kernel(struct btf *btf, 387 + char *log_buf, size_t log_sz, __u32 log_level, 388 + int token_fd); 372 389 373 390 struct btf *btf_get_from_fd(int btf_fd, struct btf *base_btf); 374 391 void btf_get_kernel_prefix_kind(enum bpf_attach_type attach_type, ··· 549 532 return insn->code == (BPF_LD | BPF_IMM | BPF_DW); 550 533 } 551 534 535 + /* Unconditionally dup FD, ensuring it doesn't use [0, 2] range. 536 + * Original FD is not closed or altered in any other way. 537 + * Preserves original FD value, if it's invalid (negative). 538 + */ 539 + static inline int dup_good_fd(int fd) 540 + { 541 + if (fd < 0) 542 + return fd; 543 + return fcntl(fd, F_DUPFD_CLOEXEC, 3); 544 + } 545 + 552 546 /* if fd is stdin, stdout, or stderr, dup to a fd greater than 2 553 547 * Takes ownership of the fd passed in, and closes it if calling 554 548 * fcntl(fd, F_DUPFD_CLOEXEC, 3). ··· 571 543 if (fd < 0) 572 544 return fd; 573 545 if (fd < 3) { 574 - fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); 546 + fd = dup_good_fd(fd); 575 547 saved_errno = errno; 576 548 close(old_fd); 577 549 errno = saved_errno;
+5 -3
tools/lib/bpf/libbpf_probes.c
··· 219 219 } 220 220 221 221 int libbpf__load_raw_btf(const char *raw_types, size_t types_len, 222 - const char *str_sec, size_t str_len) 222 + const char *str_sec, size_t str_len, 223 + int token_fd) 223 224 { 224 225 struct btf_header hdr = { 225 226 .magic = BTF_MAGIC, ··· 230 229 .str_off = types_len, 231 230 .str_len = str_len, 232 231 }; 232 + LIBBPF_OPTS(bpf_btf_load_opts, opts, .token_fd = token_fd); 233 233 int btf_fd, btf_len; 234 234 __u8 *raw_btf; 235 235 ··· 243 241 memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len); 244 242 memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len); 245 243 246 - btf_fd = bpf_btf_load(raw_btf, btf_len, NULL); 244 + btf_fd = bpf_btf_load(raw_btf, btf_len, &opts); 247 245 248 246 free(raw_btf); 249 247 return btf_fd; ··· 273 271 }; 274 272 275 273 return libbpf__load_raw_btf((char *)types, sizeof(types), 276 - strs, sizeof(strs)); 274 + strs, sizeof(strs), 0); 277 275 } 278 276 279 277 static int probe_map_create(enum bpf_map_type map_type)
+3
tools/lib/bpf/str_error.h
··· 2 2 #ifndef __LIBBPF_STR_ERROR_H 3 3 #define __LIBBPF_STR_ERROR_H 4 4 5 + #define STRERR_BUFSIZE 128 6 + 5 7 char *libbpf_strerror_r(int err, char *dst, int len); 8 + 6 9 #endif /* __LIBBPF_STR_ERROR_H */
+347
tools/testing/selftests/bpf/prog_tests/token.c
··· 12 12 #include <linux/unistd.h> 13 13 #include <linux/mount.h> 14 14 #include <sys/socket.h> 15 + #include <sys/stat.h> 15 16 #include <sys/syscall.h> 16 17 #include <sys/un.h> 18 + #include "priv_map.skel.h" 19 + #include "priv_prog.skel.h" 20 + #include "dummy_st_ops_success.skel.h" 17 21 18 22 static inline int sys_mount(const char *dev_name, const char *dir_name, 19 23 const char *type, unsigned long flags, ··· 44 40 static inline int sys_fsmount(int fs_fd, unsigned flags, unsigned ms_flags) 45 41 { 46 42 return syscall(__NR_fsmount, fs_fd, flags, ms_flags); 43 + } 44 + 45 + static inline int sys_move_mount(int from_dfd, const char *from_path, 46 + int to_dfd, const char *to_path, 47 + unsigned flags) 48 + { 49 + return syscall(__NR_move_mount, from_dfd, from_path, to_dfd, to_path, flags); 47 50 } 48 51 49 52 static int drop_priv_caps(__u64 *old_caps) ··· 654 643 return err; 655 644 } 656 645 646 + static int userns_obj_priv_map(int mnt_fd) 647 + { 648 + LIBBPF_OPTS(bpf_object_open_opts, opts); 649 + char buf[256]; 650 + struct priv_map *skel; 651 + int err, token_fd; 652 + 653 + skel = priv_map__open_and_load(); 654 + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { 655 + priv_map__destroy(skel); 656 + return -EINVAL; 657 + } 658 + 659 + /* use bpf_token_path to provide BPF FS path */ 660 + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); 661 + opts.bpf_token_path = buf; 662 + skel = priv_map__open_opts(&opts); 663 + if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) 664 + return -EINVAL; 665 + 666 + err = priv_map__load(skel); 667 + priv_map__destroy(skel); 668 + if (!ASSERT_OK(err, "obj_token_path_load")) 669 + return -EINVAL; 670 + 671 + /* create token and pass it through bpf_token_fd */ 672 + token_fd = bpf_token_create(mnt_fd, NULL); 673 + if (!ASSERT_GT(token_fd, 0, "create_token")) 674 + return -EINVAL; 675 + 676 + opts.bpf_token_path = NULL; 677 + opts.bpf_token_fd = token_fd; 678 + skel = priv_map__open_opts(&opts); 679 + if (!ASSERT_OK_PTR(skel, "obj_token_fd_open")) 680 + return -EINVAL; 681 + 682 + /* we can close our token FD, bpf_object owns dup()'ed FD now */ 683 + close(token_fd); 684 + 685 + err = priv_map__load(skel); 686 + priv_map__destroy(skel); 687 + if (!ASSERT_OK(err, "obj_token_fd_load")) 688 + return -EINVAL; 689 + 690 + return 0; 691 + } 692 + 693 + static int userns_obj_priv_prog(int mnt_fd) 694 + { 695 + LIBBPF_OPTS(bpf_object_open_opts, opts); 696 + char buf[256]; 697 + struct priv_prog *skel; 698 + int err; 699 + 700 + skel = priv_prog__open_and_load(); 701 + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { 702 + priv_prog__destroy(skel); 703 + return -EINVAL; 704 + } 705 + 706 + /* use bpf_token_path to provide BPF FS path */ 707 + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); 708 + opts.bpf_token_path = buf; 709 + skel = priv_prog__open_opts(&opts); 710 + if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) 711 + return -EINVAL; 712 + 713 + err = priv_prog__load(skel); 714 + priv_prog__destroy(skel); 715 + if (!ASSERT_OK(err, "obj_token_path_load")) 716 + return -EINVAL; 717 + 718 + return 0; 719 + } 720 + 721 + /* this test is called with BPF FS that doesn't delegate BPF_BTF_LOAD command, 722 + * which should cause struct_ops application to fail, as BTF won't be uploaded 723 + * into the kernel, even if STRUCT_OPS programs themselves are allowed 724 + */ 725 + static int validate_struct_ops_load(int mnt_fd, bool expect_success) 726 + { 727 + LIBBPF_OPTS(bpf_object_open_opts, opts); 728 + char buf[256]; 729 + struct dummy_st_ops_success *skel; 730 + int err; 731 + 732 + snprintf(buf, sizeof(buf), "/proc/self/fd/%d", mnt_fd); 733 + opts.bpf_token_path = buf; 734 + skel = dummy_st_ops_success__open_opts(&opts); 735 + if (!ASSERT_OK_PTR(skel, "obj_token_path_open")) 736 + return -EINVAL; 737 + 738 + err = dummy_st_ops_success__load(skel); 739 + dummy_st_ops_success__destroy(skel); 740 + if (expect_success) { 741 + if (!ASSERT_OK(err, "obj_token_path_load")) 742 + return -EINVAL; 743 + } else /* expect failure */ { 744 + if (!ASSERT_ERR(err, "obj_token_path_load")) 745 + return -EINVAL; 746 + } 747 + 748 + return 0; 749 + } 750 + 751 + static int userns_obj_priv_btf_fail(int mnt_fd) 752 + { 753 + return validate_struct_ops_load(mnt_fd, false /* should fail */); 754 + } 755 + 756 + static int userns_obj_priv_btf_success(int mnt_fd) 757 + { 758 + return validate_struct_ops_load(mnt_fd, true /* should succeed */); 759 + } 760 + 761 + #define TOKEN_ENVVAR "LIBBPF_BPF_TOKEN_PATH" 762 + #define TOKEN_BPFFS_CUSTOM "/bpf-token-fs" 763 + 764 + static int userns_obj_priv_implicit_token(int mnt_fd) 765 + { 766 + LIBBPF_OPTS(bpf_object_open_opts, opts); 767 + struct dummy_st_ops_success *skel; 768 + int err; 769 + 770 + /* before we mount BPF FS with token delegation, struct_ops skeleton 771 + * should fail to load 772 + */ 773 + skel = dummy_st_ops_success__open_and_load(); 774 + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { 775 + dummy_st_ops_success__destroy(skel); 776 + return -EINVAL; 777 + } 778 + 779 + /* mount custom BPF FS over /sys/fs/bpf so that libbpf can create BPF 780 + * token automatically and implicitly 781 + */ 782 + err = sys_move_mount(mnt_fd, "", AT_FDCWD, "/sys/fs/bpf", MOVE_MOUNT_F_EMPTY_PATH); 783 + if (!ASSERT_OK(err, "move_mount_bpffs")) 784 + return -EINVAL; 785 + 786 + /* disable implicit BPF token creation by setting 787 + * LIBBPF_BPF_TOKEN_PATH envvar to empty value, load should fail 788 + */ 789 + err = setenv(TOKEN_ENVVAR, "", 1 /*overwrite*/); 790 + if (!ASSERT_OK(err, "setenv_token_path")) 791 + return -EINVAL; 792 + skel = dummy_st_ops_success__open_and_load(); 793 + if (!ASSERT_ERR_PTR(skel, "obj_token_envvar_disabled_load")) { 794 + unsetenv(TOKEN_ENVVAR); 795 + dummy_st_ops_success__destroy(skel); 796 + return -EINVAL; 797 + } 798 + unsetenv(TOKEN_ENVVAR); 799 + 800 + /* now the same struct_ops skeleton should succeed thanks to libppf 801 + * creating BPF token from /sys/fs/bpf mount point 802 + */ 803 + skel = dummy_st_ops_success__open_and_load(); 804 + if (!ASSERT_OK_PTR(skel, "obj_implicit_token_load")) 805 + return -EINVAL; 806 + 807 + dummy_st_ops_success__destroy(skel); 808 + 809 + /* now disable implicit token through empty bpf_token_path, should fail */ 810 + opts.bpf_token_path = ""; 811 + skel = dummy_st_ops_success__open_opts(&opts); 812 + if (!ASSERT_OK_PTR(skel, "obj_empty_token_path_open")) 813 + return -EINVAL; 814 + 815 + err = dummy_st_ops_success__load(skel); 816 + dummy_st_ops_success__destroy(skel); 817 + if (!ASSERT_ERR(err, "obj_empty_token_path_load")) 818 + return -EINVAL; 819 + 820 + /* now disable implicit token through negative bpf_token_fd, should fail */ 821 + opts.bpf_token_path = NULL; 822 + opts.bpf_token_fd = -1; 823 + skel = dummy_st_ops_success__open_opts(&opts); 824 + if (!ASSERT_OK_PTR(skel, "obj_neg_token_fd_open")) 825 + return -EINVAL; 826 + 827 + err = dummy_st_ops_success__load(skel); 828 + dummy_st_ops_success__destroy(skel); 829 + if (!ASSERT_ERR(err, "obj_neg_token_fd_load")) 830 + return -EINVAL; 831 + 832 + return 0; 833 + } 834 + 835 + static int userns_obj_priv_implicit_token_envvar(int mnt_fd) 836 + { 837 + LIBBPF_OPTS(bpf_object_open_opts, opts); 838 + struct dummy_st_ops_success *skel; 839 + int err; 840 + 841 + /* before we mount BPF FS with token delegation, struct_ops skeleton 842 + * should fail to load 843 + */ 844 + skel = dummy_st_ops_success__open_and_load(); 845 + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load")) { 846 + dummy_st_ops_success__destroy(skel); 847 + return -EINVAL; 848 + } 849 + 850 + /* mount custom BPF FS over custom location, so libbpf can't create 851 + * BPF token implicitly, unless pointed to it through 852 + * LIBBPF_BPF_TOKEN_PATH envvar 853 + */ 854 + rmdir(TOKEN_BPFFS_CUSTOM); 855 + if (!ASSERT_OK(mkdir(TOKEN_BPFFS_CUSTOM, 0777), "mkdir_bpffs_custom")) 856 + goto err_out; 857 + err = sys_move_mount(mnt_fd, "", AT_FDCWD, TOKEN_BPFFS_CUSTOM, MOVE_MOUNT_F_EMPTY_PATH); 858 + if (!ASSERT_OK(err, "move_mount_bpffs")) 859 + goto err_out; 860 + 861 + /* even though we have BPF FS with delegation, it's not at default 862 + * /sys/fs/bpf location, so we still fail to load until envvar is set up 863 + */ 864 + skel = dummy_st_ops_success__open_and_load(); 865 + if (!ASSERT_ERR_PTR(skel, "obj_tokenless_load2")) { 866 + dummy_st_ops_success__destroy(skel); 867 + goto err_out; 868 + } 869 + 870 + err = setenv(TOKEN_ENVVAR, TOKEN_BPFFS_CUSTOM, 1 /*overwrite*/); 871 + if (!ASSERT_OK(err, "setenv_token_path")) 872 + goto err_out; 873 + 874 + /* now the same struct_ops skeleton should succeed thanks to libppf 875 + * creating BPF token from custom mount point 876 + */ 877 + skel = dummy_st_ops_success__open_and_load(); 878 + if (!ASSERT_OK_PTR(skel, "obj_implicit_token_load")) 879 + goto err_out; 880 + 881 + dummy_st_ops_success__destroy(skel); 882 + 883 + /* now disable implicit token through empty bpf_token_path, envvar 884 + * will be ignored, should fail 885 + */ 886 + opts.bpf_token_path = ""; 887 + skel = dummy_st_ops_success__open_opts(&opts); 888 + if (!ASSERT_OK_PTR(skel, "obj_empty_token_path_open")) 889 + goto err_out; 890 + 891 + err = dummy_st_ops_success__load(skel); 892 + dummy_st_ops_success__destroy(skel); 893 + if (!ASSERT_ERR(err, "obj_empty_token_path_load")) 894 + goto err_out; 895 + 896 + /* now disable implicit token through negative bpf_token_fd, envvar 897 + * will be ignored, should fail 898 + */ 899 + opts.bpf_token_path = NULL; 900 + opts.bpf_token_fd = -1; 901 + skel = dummy_st_ops_success__open_opts(&opts); 902 + if (!ASSERT_OK_PTR(skel, "obj_neg_token_fd_open")) 903 + goto err_out; 904 + 905 + err = dummy_st_ops_success__load(skel); 906 + dummy_st_ops_success__destroy(skel); 907 + if (!ASSERT_ERR(err, "obj_neg_token_fd_load")) 908 + goto err_out; 909 + 910 + rmdir(TOKEN_BPFFS_CUSTOM); 911 + unsetenv(TOKEN_ENVVAR); 912 + return 0; 913 + err_out: 914 + rmdir(TOKEN_BPFFS_CUSTOM); 915 + unsetenv(TOKEN_ENVVAR); 916 + return -EINVAL; 917 + } 918 + 919 + #define bit(n) (1ULL << (n)) 920 + 657 921 void test_token(void) 658 922 { 659 923 if (test__start_subtest("map_token")) { ··· 954 668 }; 955 669 956 670 subtest_userns(&opts, userns_prog_load); 671 + } 672 + if (test__start_subtest("obj_priv_map")) { 673 + struct bpffs_opts opts = { 674 + .cmds = bit(BPF_MAP_CREATE), 675 + .maps = bit(BPF_MAP_TYPE_QUEUE), 676 + }; 677 + 678 + subtest_userns(&opts, userns_obj_priv_map); 679 + } 680 + if (test__start_subtest("obj_priv_prog")) { 681 + struct bpffs_opts opts = { 682 + .cmds = bit(BPF_PROG_LOAD), 683 + .progs = bit(BPF_PROG_TYPE_KPROBE), 684 + .attachs = ~0ULL, 685 + }; 686 + 687 + subtest_userns(&opts, userns_obj_priv_prog); 688 + } 689 + if (test__start_subtest("obj_priv_btf_fail")) { 690 + struct bpffs_opts opts = { 691 + /* disallow BTF loading */ 692 + .cmds = bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), 693 + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), 694 + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), 695 + .attachs = ~0ULL, 696 + }; 697 + 698 + subtest_userns(&opts, userns_obj_priv_btf_fail); 699 + } 700 + if (test__start_subtest("obj_priv_btf_success")) { 701 + struct bpffs_opts opts = { 702 + /* allow BTF loading */ 703 + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), 704 + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), 705 + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), 706 + .attachs = ~0ULL, 707 + }; 708 + 709 + subtest_userns(&opts, userns_obj_priv_btf_success); 710 + } 711 + if (test__start_subtest("obj_priv_implicit_token")) { 712 + struct bpffs_opts opts = { 713 + /* allow BTF loading */ 714 + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), 715 + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), 716 + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), 717 + .attachs = ~0ULL, 718 + }; 719 + 720 + subtest_userns(&opts, userns_obj_priv_implicit_token); 721 + } 722 + if (test__start_subtest("obj_priv_implicit_token_envvar")) { 723 + struct bpffs_opts opts = { 724 + /* allow BTF loading */ 725 + .cmds = bit(BPF_BTF_LOAD) | bit(BPF_MAP_CREATE) | bit(BPF_PROG_LOAD), 726 + .maps = bit(BPF_MAP_TYPE_STRUCT_OPS), 727 + .progs = bit(BPF_PROG_TYPE_STRUCT_OPS), 728 + .attachs = ~0ULL, 729 + }; 730 + 731 + subtest_userns(&opts, userns_obj_priv_implicit_token_envvar); 957 732 } 958 733 }
+13
tools/testing/selftests/bpf/progs/priv_map.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2023 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 + struct { 10 + __uint(type, BPF_MAP_TYPE_QUEUE); 11 + __uint(max_entries, 1); 12 + __type(value, __u32); 13 + } priv_map SEC(".maps");
+13
tools/testing/selftests/bpf/progs/priv_prog.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2023 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 + SEC("kprobe") 10 + int kprobe_prog(void *ctx) 11 + { 12 + return 1; 13 + }