History

bpf: introduce BPF token object

Add new kind of BPF kernel object, BPF token. BPF token is meant to allow delegating privileged BPF functionality, like loading a BPF program or creating a BPF map, from privileged process to a *trusted* unprivileged process, all while having a good amount of control over which privileged operations could be performed using provided BPF token. This is achieved through mounting BPF FS instance with extra delegation mount options, which determine what operations are delegatable, and also constraining it to the owning user namespace (as mentioned in the previous patch). BPF token itself is just a derivative from BPF FS and can be created through a new bpf() syscall command, BPF_TOKEN_CREATE, which accepts BPF FS FD, which can be attained through open() API by opening BPF FS mount point. Currently, BPF token "inherits" delegated command, map types, prog type, and attach type bit sets from BPF FS as is. In the future, having an BPF token as a separate object with its own FD, we can allow to further restrict BPF token's allowable set of things either at the creation time or after the fact, allowing the process to guard itself further from unintentionally trying to load undesired kind of BPF programs. But for now we keep things simple and just copy bit sets as is. When BPF token is created from BPF FS mount, we take reference to the BPF super block's owning user namespace, and then use that namespace for checking all the {CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN} capabilities that are normally only checked against init userns (using capable()), but now we check them using ns_capable() instead (if BPF token is provided). See bpf_token_capable() for details. Such setup means that BPF token in itself is not sufficient to grant BPF functionality. User namespaced process has to *also* have necessary combination of capabilities inside that user namespace. So while previously CAP_BPF was useless when granted within user namespace, now it gains a meaning and allows container managers and sys admins to have a flexible control over which processes can and need to use BPF functionality within the user namespace (i.e., container in practice). And BPF FS delegation mount options and derived BPF tokens serve as a per-container "flag" to grant overall ability to use bpf() (plus further restrict on which parts of bpf() syscalls are treated as namespaced). Note also, BPF_TOKEN_CREATE command itself requires ns_capable(CAP_BPF) within the BPF FS owning user namespace, rounding up the ns_capable() story of BPF token.

Andrii Nakryiko committed 2 years ago

Commit 45273581 parent 40bba147 files · +354 −6Browse files

Unified · Split

7 files
  1. include/linux/bpf.h +41 −0
  2. include/uapi/linux/bpf.h +37 −0
  3. kernel/bpf/Makefile +1 −1
  4. kernel/bpf/inode.c +7 −5
  5. kernel/bpf/syscall.c +17 −0
  6. kernel/bpf/token.c +214 −0
  7. tools/include/uapi/linux/bpf.h +37 −0
include/linux/bpf.h+41−0
@@ -51,6 +51,10 @@ struct module; · 50 unmodified lines
51struct bpf_func_state;51struct bpf_func_state;
52struct ftrace_ops;52struct ftrace_ops;
53struct cgroup;53struct cgroup;
54struct bpf_token;
55struct user_namespace;
56struct super_block;
57struct inode;
54 58
55extern struct idr btf_idr;59extern struct idr btf_idr;
56extern spinlock_t btf_idr_lock;60extern spinlock_t btf_idr_lock;
@@ -1591,6 +1595,13 @@ struct bpf_mount_opts { · 1534 unmodified lines
1591 u64 delegate_attachs;1595 u64 delegate_attachs;
1592};1596};
1593 1597
1598struct bpf_token {
1599 struct work_struct work;
1600 atomic64_t refcnt;
1601 struct user_namespace *userns;
1602 u64 allowed_cmds;
1603};
1604
1594struct bpf_struct_ops_value;1605struct bpf_struct_ops_value;
1595struct btf_member;1606struct btf_member;
1596 1607
@@ -2048,6 +2059,7 @@ static inline void bpf_enable_instrumentation(void) · 451 unmodified lines
2048 migrate_enable();2059 migrate_enable();
2049}2060}
2050 2061
2062extern const struct super_operations bpf_super_ops;
2051extern const struct file_operations bpf_map_fops;2063extern const struct file_operations bpf_map_fops;
2052extern const struct file_operations bpf_prog_fops;2064extern const struct file_operations bpf_prog_fops;
2053extern const struct file_operations bpf_iter_fops;2065extern const struct file_operations bpf_iter_fops;
@@ -2182,6 +2194,8 @@ static inline void bpf_map_dec_elem_count(struct bpf_map *map) · 128 unmodified lines
2182 2194
2183extern int sysctl_unprivileged_bpf_disabled;2195extern int sysctl_unprivileged_bpf_disabled;
2184 2196
2197bool bpf_token_capable(const struct bpf_token *token, int cap);
2198
2185static inline bool bpf_allow_ptr_leaks(void)2199static inline bool bpf_allow_ptr_leaks(void)
2186{2200{
2187 return perfmon_capable();2201 return perfmon_capable();
@@ -2216,8 +2230,17 @@ int bpf_link_new_fd(struct bpf_link *link); · 28 unmodified lines
2216struct bpf_link *bpf_link_get_from_fd(u32 ufd);2230struct bpf_link *bpf_link_get_from_fd(u32 ufd);
2217struct bpf_link *bpf_link_get_curr_or_next(u32 *id);2231struct bpf_link *bpf_link_get_curr_or_next(u32 *id);
2218 2232
2233void bpf_token_inc(struct bpf_token *token);
2234void bpf_token_put(struct bpf_token *token);
2235int bpf_token_create(union bpf_attr *attr);
2236struct bpf_token *bpf_token_get_from_fd(u32 ufd);
2237
2238bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd);
2239
2219int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname);2240int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname);
2220int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags);2241int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags);
2242struct inode *bpf_get_inode(struct super_block *sb, const struct inode *dir,
2243 umode_t mode);
2221 2244
2222#define BPF_ITER_FUNC_PREFIX "bpf_iter_"2245#define BPF_ITER_FUNC_PREFIX "bpf_iter_"
2223#define DEFINE_BPF_ITER_FUNC(target, args...) \2246#define DEFINE_BPF_ITER_FUNC(target, args...) \
@@ -2580,6 +2603,24 @@ static inline int bpf_obj_get_user(const char __user *pathname, int flags) · 356 unmodified lines
2580 return -EOPNOTSUPP;2603 return -EOPNOTSUPP;
2581}2604}
2582 2605
2606static inline bool bpf_token_capable(const struct bpf_token *token, int cap)
2607{
2608 return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN));
2609}
2610
2611static inline void bpf_token_inc(struct bpf_token *token)
2612{
2613}
2614
2615static inline void bpf_token_put(struct bpf_token *token)
2616{
2617}
2618
2619static inline struct bpf_token *bpf_token_get_from_fd(u32 ufd)
2620{
2621 return ERR_PTR(-EOPNOTSUPP);
2622}
2623
2583static inline void __dev_flush(void)2624static inline void __dev_flush(void)
2584{2625{
2585}2626}
include/uapi/linux/bpf.h+37−0
@@ -847,6 +847,36 @@ union bpf_iter_link_info { · 846 unmodified lines
847 * Returns zero on success. On error, -1 is returned and *errno*847 * Returns zero on success. On error, -1 is returned and *errno*
848 * is set appropriately.848 * is set appropriately.
849 *849 *
850 * BPF_TOKEN_CREATE
851 * Description
852 * Create BPF token with embedded information about what
853 * BPF-related functionality it allows:
854 * - a set of allowed bpf() syscall commands;
855 * - a set of allowed BPF map types to be created with
856 * BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed;
857 * - a set of allowed BPF program types and BPF program attach
858 * types to be loaded with BPF_PROG_LOAD command, if
859 * BPF_PROG_LOAD itself is allowed.
860 *
861 * BPF token is created (derived) from an instance of BPF FS,
862 * assuming it has necessary delegation mount options specified.
863 * This BPF token can be passed as an extra parameter to various
864 * bpf() syscall commands to grant BPF subsystem functionality to
865 * unprivileged processes.
866 *
867 * When created, BPF token is "associated" with the owning
868 * user namespace of BPF FS instance (super block) that it was
869 * derived from, and subsequent BPF operations performed with
870 * BPF token would be performing capabilities checks (i.e.,
871 * CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within
872 * that user namespace. Without BPF token, such capabilities
873 * have to be granted in init user namespace, making bpf()
874 * syscall incompatible with user namespace, for the most part.
875 *
876 * Return
877 * A new file descriptor (a nonnegative integer), or -1 if an
878 * error occurred (in which case, *errno* is set appropriately).
879 *
850 * NOTES880 * NOTES
851 * eBPF objects (maps and programs) can be shared between processes.881 * eBPF objects (maps and programs) can be shared between processes.
852 *882 *
@@ -901,6 +931,8 @@ enum bpf_cmd { · 48 unmodified lines
901 BPF_ITER_CREATE,931 BPF_ITER_CREATE,
902 BPF_LINK_DETACH,932 BPF_LINK_DETACH,
903 BPF_PROG_BIND_MAP,933 BPF_PROG_BIND_MAP,
934 BPF_TOKEN_CREATE,
935 __MAX_BPF_CMD,
904};936};
905 937
906enum bpf_map_type {938enum bpf_map_type {
@@ -1712,6 +1744,11 @@ union bpf_attr { · 805 unmodified lines
1712 __u32 flags; /* extra flags */1744 __u32 flags; /* extra flags */
1713 } prog_bind_map;1745 } prog_bind_map;
1714 1746
1747 struct { /* struct used by BPF_TOKEN_CREATE command */
1748 __u32 flags;
1749 __u32 bpffs_fd;
1750 } token_create;
1751
1715} __attribute__((aligned(8)));1752} __attribute__((aligned(8)));
1716 1753
1717/* The description below is an attempt at providing documentation to eBPF1754/* The description below is an attempt at providing documentation to eBPF
kernel/bpf/Makefile+1−1
@@ -6,7 +6,7 @@ cflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse · 5 unmodified lines
6endif6endif
7CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy)7CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy)
8 8
9obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o9obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o
10obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o10obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o
11obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o11obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o
12obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o12obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
kernel/bpf/inode.c+7−5
@@ -99,9 +99,9 @@ static const struct inode_operations bpf_prog_iops = { }; · 98 unmodified lines
99static const struct inode_operations bpf_map_iops = { };99static const struct inode_operations bpf_map_iops = { };
100static const struct inode_operations bpf_link_iops = { };100static const struct inode_operations bpf_link_iops = { };
101 101
102static struct inode *bpf_get_inode(struct super_block *sb,102struct inode *bpf_get_inode(struct super_block *sb,
103 const struct inode *dir,103 const struct inode *dir,
104 umode_t mode)104 umode_t mode)
105{105{
106 struct inode *inode;106 struct inode *inode;
107 107
@@ -602,11 +602,13 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root) · 494 unmodified lines
602{602{
603 struct bpf_mount_opts *opts = root->d_sb->s_fs_info;603 struct bpf_mount_opts *opts = root->d_sb->s_fs_info;
604 umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX;604 umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX;
605 u64 mask;
605 606
606 if (mode != S_IRWXUGO)607 if (mode != S_IRWXUGO)
607 seq_printf(m, ",mode=%o", mode);608 seq_printf(m, ",mode=%o", mode);
608 609
609 if (opts->delegate_cmds == ~0ULL)610 mask = (1ULL << __MAX_BPF_CMD) - 1;
611 if ((opts->delegate_cmds & mask) == mask)
610 seq_printf(m, ",delegate_cmds=any");612 seq_printf(m, ",delegate_cmds=any");
611 else if (opts->delegate_cmds)613 else if (opts->delegate_cmds)
612 seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds);614 seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds);
@@ -639,7 +641,7 @@ static void bpf_free_inode(struct inode *inode) · 26 unmodified lines
639 free_inode_nonrcu(inode);641 free_inode_nonrcu(inode);
640}642}
641 643
642static const struct super_operations bpf_super_ops = {644const struct super_operations bpf_super_ops = {
643 .statfs = simple_statfs,645 .statfs = simple_statfs,
644 .drop_inode = generic_delete_inode,646 .drop_inode = generic_delete_inode,
645 .show_options = bpf_show_options,647 .show_options = bpf_show_options,
kernel/bpf/syscall.c+17−0
@@ -5377,6 +5377,20 @@ out_prog_put: · 5376 unmodified lines
5377 return ret;5377 return ret;
5378}5378}
5379 5379
5380#define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd
5381
5382static int token_create(union bpf_attr *attr)
5383{
5384 if (CHECK_ATTR(BPF_TOKEN_CREATE))
5385 return -EINVAL;
5386
5387 /* no flags are supported yet */
5388 if (attr->token_create.flags)
5389 return -EINVAL;
5390
5391 return bpf_token_create(attr);
5392}
5393
5380static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)5394static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
5381{5395{
5382 union bpf_attr attr;5396 union bpf_attr attr;
@@ -5510,6 +5524,9 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size) · 127 unmodified lines
5510 case BPF_PROG_BIND_MAP:5524 case BPF_PROG_BIND_MAP:
5511 err = bpf_prog_bind_map(&attr);5525 err = bpf_prog_bind_map(&attr);
5512 break;5526 break;
5527 case BPF_TOKEN_CREATE:
5528 err = token_create(&attr);
5529 break;
5513 default:5530 default:
5514 err = -EINVAL;5531 err = -EINVAL;
5515 break;5532 break;
kernel/bpf/token.c+214−0
@@ -0,0 +1,214 @@
1#include <linux/bpf.h>
2#include <linux/vmalloc.h>
3#include <linux/fdtable.h>
4#include <linux/file.h>
5#include <linux/fs.h>
6#include <linux/kernel.h>
7#include <linux/idr.h>
8#include <linux/namei.h>
9#include <linux/user_namespace.h>
10
11bool bpf_token_capable(const struct bpf_token *token, int cap)
12{
13 /* BPF token allows ns_capable() level of capabilities, but only if
14 * token's userns is *exactly* the same as current user's userns
15 */
16 if (token && current_user_ns() == token->userns) {
17 if (ns_capable(token->userns, cap))
18 return true;
19 if (cap != CAP_SYS_ADMIN && ns_capable(token->userns, CAP_SYS_ADMIN))
20 return true;
21 }
22 /* otherwise fallback to capable() checks */
23 return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN));
24}
25
26void bpf_token_inc(struct bpf_token *token)
27{
28 atomic64_inc(&token->refcnt);
29}
30
31static void bpf_token_free(struct bpf_token *token)
32{
33 put_user_ns(token->userns);
34 kvfree(token);
35}
36
37static void bpf_token_put_deferred(struct work_struct *work)
38{
39 struct bpf_token *token = container_of(work, struct bpf_token, work);
40
41 bpf_token_free(token);
42}
43
44void bpf_token_put(struct bpf_token *token)
45{
46 if (!token)
47 return;
48
49 if (!atomic64_dec_and_test(&token->refcnt))
50 return;
51
52 INIT_WORK(&token->work, bpf_token_put_deferred);
53 schedule_work(&token->work);
54}
55
56static int bpf_token_release(struct inode *inode, struct file *filp)
57{
58 struct bpf_token *token = filp->private_data;
59
60 bpf_token_put(token);
61 return 0;
62}
63
64static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp)
65{
66 struct bpf_token *token = filp->private_data;
67 u64 mask;
68
69 BUILD_BUG_ON(__MAX_BPF_CMD >= 64);
70 mask = (1ULL << __MAX_BPF_CMD) - 1;
71 if ((token->allowed_cmds & mask) == mask)
72 seq_printf(m, "allowed_cmds:\tany\n");
73 else
74 seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds);
75}
76
77#define BPF_TOKEN_INODE_NAME "bpf-token"
78
79static const struct inode_operations bpf_token_iops = { };
80
81static const struct file_operations bpf_token_fops = {
82 .release = bpf_token_release,
83 .show_fdinfo = bpf_token_show_fdinfo,
84};
85
86int bpf_token_create(union bpf_attr *attr)
87{
88 struct bpf_mount_opts *mnt_opts;
89 struct bpf_token *token = NULL;
90 struct user_namespace *userns;
91 struct inode *inode;
92 struct file *file;
93 struct path path;
94 struct fd f;
95 umode_t mode;
96 int err, fd;
97
98 f = fdget(attr->token_create.bpffs_fd);
99 if (!f.file)
100 return -EBADF;
101
102 path = f.file->f_path;
103 path_get(&path);
104 fdput(f);
105
106 if (path.dentry != path.mnt->mnt_sb->s_root) {
107 err = -EINVAL;
108 goto out_path;
109 }
110 if (path.mnt->mnt_sb->s_op != &bpf_super_ops) {
111 err = -EINVAL;
112 goto out_path;
113 }
114 err = path_permission(&path, MAY_ACCESS);
115 if (err)
116 goto out_path;
117
118 userns = path.dentry->d_sb->s_user_ns;
119 /*
120 * Enforce that creators of BPF tokens are in the same user
121 * namespace as the BPF FS instance. This makes reasoning about
122 * permissions a lot easier and we can always relax this later.
123 */
124 if (current_user_ns() != userns) {
125 err = -EPERM;
126 goto out_path;
127 }
128 if (!ns_capable(userns, CAP_BPF)) {
129 err = -EPERM;
130 goto out_path;
131 }
132
133 mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask());
134 inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode);
135 if (IS_ERR(inode)) {
136 err = PTR_ERR(inode);
137 goto out_path;
138 }
139
140 inode->i_op = &bpf_token_iops;
141 inode->i_fop = &bpf_token_fops;
142 clear_nlink(inode); /* make sure it is unlinked */
143
144 file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops);
145 if (IS_ERR(file)) {
146 iput(inode);
147 err = PTR_ERR(file);
148 goto out_path;
149 }
150
151 token = kvzalloc(sizeof(*token), GFP_USER);
152 if (!token) {
153 err = -ENOMEM;
154 goto out_file;
155 }
156
157 atomic64_set(&token->refcnt, 1);
158
159 /* remember bpffs owning userns for future ns_capable() checks */
160 token->userns = get_user_ns(userns);
161
162 mnt_opts = path.dentry->d_sb->s_fs_info;
163 token->allowed_cmds = mnt_opts->delegate_cmds;
164
165 fd = get_unused_fd_flags(O_CLOEXEC);
166 if (fd < 0) {
167 err = fd;
168 goto out_token;
169 }
170
171 file->private_data = token;
172 fd_install(fd, file);
173
174 path_put(&path);
175 return fd;
176
177out_token:
178 bpf_token_free(token);
179out_file:
180 fput(file);
181out_path:
182 path_put(&path);
183 return err;
184}
185
186struct bpf_token *bpf_token_get_from_fd(u32 ufd)
187{
188 struct fd f = fdget(ufd);
189 struct bpf_token *token;
190
191 if (!f.file)
192 return ERR_PTR(-EBADF);
193 if (f.file->f_op != &bpf_token_fops) {
194 fdput(f);
195 return ERR_PTR(-EINVAL);
196 }
197
198 token = f.file->private_data;
199 bpf_token_inc(token);
200 fdput(f);
201
202 return token;
203}
204
205bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd)
206{
207 /* BPF token can be used only within exactly the same userns in which
208 * it was created
209 */
210 if (!token || current_user_ns() != token->userns)
211 return false;
212
213 return token->allowed_cmds & (1ULL << cmd);
214}
tools/include/uapi/linux/bpf.h+37−0
@@ -847,6 +847,36 @@ union bpf_iter_link_info { · 846 unmodified lines
847 * Returns zero on success. On error, -1 is returned and *errno*847 * Returns zero on success. On error, -1 is returned and *errno*
848 * is set appropriately.848 * is set appropriately.
849 *849 *
850 * BPF_TOKEN_CREATE
851 * Description
852 * Create BPF token with embedded information about what
853 * BPF-related functionality it allows:
854 * - a set of allowed bpf() syscall commands;
855 * - a set of allowed BPF map types to be created with
856 * BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed;
857 * - a set of allowed BPF program types and BPF program attach
858 * types to be loaded with BPF_PROG_LOAD command, if
859 * BPF_PROG_LOAD itself is allowed.
860 *
861 * BPF token is created (derived) from an instance of BPF FS,
862 * assuming it has necessary delegation mount options specified.
863 * This BPF token can be passed as an extra parameter to various
864 * bpf() syscall commands to grant BPF subsystem functionality to
865 * unprivileged processes.
866 *
867 * When created, BPF token is "associated" with the owning
868 * user namespace of BPF FS instance (super block) that it was
869 * derived from, and subsequent BPF operations performed with
870 * BPF token would be performing capabilities checks (i.e.,
871 * CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within
872 * that user namespace. Without BPF token, such capabilities
873 * have to be granted in init user namespace, making bpf()
874 * syscall incompatible with user namespace, for the most part.
875 *
876 * Return
877 * A new file descriptor (a nonnegative integer), or -1 if an
878 * error occurred (in which case, *errno* is set appropriately).
879 *
850 * NOTES880 * NOTES
851 * eBPF objects (maps and programs) can be shared between processes.881 * eBPF objects (maps and programs) can be shared between processes.
852 *882 *
@@ -901,6 +931,8 @@ enum bpf_cmd { · 48 unmodified lines
901 BPF_ITER_CREATE,931 BPF_ITER_CREATE,
902 BPF_LINK_DETACH,932 BPF_LINK_DETACH,
903 BPF_PROG_BIND_MAP,933 BPF_PROG_BIND_MAP,
934 BPF_TOKEN_CREATE,
935 __MAX_BPF_CMD,
904};936};
905 937
906enum bpf_map_type {938enum bpf_map_type {
@@ -1712,6 +1744,11 @@ union bpf_attr { · 805 unmodified lines
1712 __u32 flags; /* extra flags */1744 __u32 flags; /* extra flags */
1713 } prog_bind_map;1745 } prog_bind_map;
1714 1746
1747 struct { /* struct used by BPF_TOKEN_CREATE command */
1748 __u32 flags;
1749 __u32 bpffs_fd;
1750 } token_create;
1751
1715} __attribute__((aligned(8)));1752} __attribute__((aligned(8)));
1716 1753
1717/* The description below is an attempt at providing documentation to eBPF1754/* The description below is an attempt at providing documentation to eBPF