Skip to content

Commit c5707b2

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
bpf: support symbolic BPF FS delegation mount options
Besides already supported special "any" value and hex bit mask, support string-based parsing of delegation masks based on exact enumerator names. Utilize BTF information of `enum bpf_cmd`, `enum bpf_map_type`, `enum bpf_prog_type`, and `enum bpf_attach_type` types to find supported symbolic names (ignoring __MAX_xxx guard values and stripping repetitive prefixes like BPF_ for cmd and attach types, BPF_MAP_TYPE_ for maps, and BPF_PROG_TYPE_ for prog types). The case doesn't matter, but it is normalized to lower case in mount option output. So "PROG_LOAD", "prog_load", and "MAP_create" are all valid values to specify for delegate_cmds options, "array" is among supported for map types, etc. Besides supporting string values, we also support multiple values specified at the same time, using colon (':') separator. There are corresponding changes on bpf_show_options side to use known values to print them in human-readable format, falling back to hex mask printing, if there are any unrecognized bits. This shouldn't be necessary when enum BTF information is present, but in general we should always be able to fall back to this even if kernel was built without BTF. As mentioned, emitted symbolic names are normalized to be all lower case. Example below shows various ways to specify delegate_cmds options through mount command and how mount options are printed back: 12/14 14:39:07.604 vmuser@archvm:~/local/linux/tools/testing/selftests/bpf $ mount | rg token $ sudo mkdir -p /sys/fs/bpf/token $ sudo mount -t bpf bpffs /sys/fs/bpf/token \ -o delegate_cmds=prog_load:MAP_CREATE \ -o delegate_progs=kprobe \ -o delegate_attachs=xdp $ mount | grep token bpffs on /sys/fs/bpf/token type bpf (rw,relatime,delegate_cmds=map_create:prog_load,delegate_progs=kprobe,delegate_attachs=xdp) Acked-by: John Fastabend <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 403f3e8 commit c5707b2

File tree

1 file changed

+211
-38
lines changed

1 file changed

+211
-38
lines changed

kernel/bpf/inode.c

Lines changed: 211 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,136 @@ struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type typ
595595
}
596596
EXPORT_SYMBOL(bpf_prog_get_type_path);
597597

598+
struct bpffs_btf_enums {
599+
const struct btf *btf;
600+
const struct btf_type *cmd_t;
601+
const struct btf_type *map_t;
602+
const struct btf_type *prog_t;
603+
const struct btf_type *attach_t;
604+
};
605+
606+
static int find_bpffs_btf_enums(struct bpffs_btf_enums *info)
607+
{
608+
const struct btf *btf;
609+
const struct btf_type *t;
610+
const char *name;
611+
int i, n;
612+
613+
memset(info, 0, sizeof(*info));
614+
615+
btf = bpf_get_btf_vmlinux();
616+
if (IS_ERR(btf))
617+
return PTR_ERR(btf);
618+
if (!btf)
619+
return -ENOENT;
620+
621+
info->btf = btf;
622+
623+
for (i = 1, n = btf_nr_types(btf); i < n; i++) {
624+
t = btf_type_by_id(btf, i);
625+
if (!btf_type_is_enum(t))
626+
continue;
627+
628+
name = btf_name_by_offset(btf, t->name_off);
629+
if (!name)
630+
continue;
631+
632+
if (strcmp(name, "bpf_cmd") == 0)
633+
info->cmd_t = t;
634+
else if (strcmp(name, "bpf_map_type") == 0)
635+
info->map_t = t;
636+
else if (strcmp(name, "bpf_prog_type") == 0)
637+
info->prog_t = t;
638+
else if (strcmp(name, "bpf_attach_type") == 0)
639+
info->attach_t = t;
640+
else
641+
continue;
642+
643+
if (info->cmd_t && info->map_t && info->prog_t && info->attach_t)
644+
return 0;
645+
}
646+
647+
return -ESRCH;
648+
}
649+
650+
static bool find_btf_enum_const(const struct btf *btf, const struct btf_type *enum_t,
651+
const char *prefix, const char *str, int *value)
652+
{
653+
const struct btf_enum *e;
654+
const char *name;
655+
int i, n, pfx_len = strlen(prefix);
656+
657+
*value = 0;
658+
659+
if (!btf || !enum_t)
660+
return false;
661+
662+
for (i = 0, n = btf_vlen(enum_t); i < n; i++) {
663+
e = &btf_enum(enum_t)[i];
664+
665+
name = btf_name_by_offset(btf, e->name_off);
666+
if (!name || strncasecmp(name, prefix, pfx_len) != 0)
667+
continue;
668+
669+
/* match symbolic name case insensitive and ignoring prefix */
670+
if (strcasecmp(name + pfx_len, str) == 0) {
671+
*value = e->val;
672+
return true;
673+
}
674+
}
675+
676+
return false;
677+
}
678+
679+
static void seq_print_delegate_opts(struct seq_file *m,
680+
const char *opt_name,
681+
const struct btf *btf,
682+
const struct btf_type *enum_t,
683+
const char *prefix,
684+
u64 delegate_msk, u64 any_msk)
685+
{
686+
const struct btf_enum *e;
687+
bool first = true;
688+
const char *name;
689+
u64 msk;
690+
int i, n, pfx_len = strlen(prefix);
691+
692+
delegate_msk &= any_msk; /* clear unknown bits */
693+
694+
if (delegate_msk == 0)
695+
return;
696+
697+
seq_printf(m, ",%s", opt_name);
698+
if (delegate_msk == any_msk) {
699+
seq_printf(m, "=any");
700+
return;
701+
}
702+
703+
if (btf && enum_t) {
704+
for (i = 0, n = btf_vlen(enum_t); i < n; i++) {
705+
e = &btf_enum(enum_t)[i];
706+
name = btf_name_by_offset(btf, e->name_off);
707+
if (!name || strncasecmp(name, prefix, pfx_len) != 0)
708+
continue;
709+
msk = 1ULL << e->val;
710+
if (delegate_msk & msk) {
711+
/* emit lower-case name without prefix */
712+
seq_printf(m, "%c", first ? '=' : ':');
713+
name += pfx_len;
714+
while (*name) {
715+
seq_printf(m, "%c", tolower(*name));
716+
name++;
717+
}
718+
719+
delegate_msk &= ~msk;
720+
first = false;
721+
}
722+
}
723+
}
724+
if (delegate_msk)
725+
seq_printf(m, "%c0x%llx", first ? '=' : ':', delegate_msk);
726+
}
727+
598728
/*
599729
* Display the mount options in /proc/mounts.
600730
*/
@@ -614,29 +744,34 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root)
614744
if (mode != S_IRWXUGO)
615745
seq_printf(m, ",mode=%o", mode);
616746

617-
mask = (1ULL << __MAX_BPF_CMD) - 1;
618-
if ((opts->delegate_cmds & mask) == mask)
619-
seq_printf(m, ",delegate_cmds=any");
620-
else if (opts->delegate_cmds)
621-
seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds);
622-
623-
mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
624-
if ((opts->delegate_maps & mask) == mask)
625-
seq_printf(m, ",delegate_maps=any");
626-
else if (opts->delegate_maps)
627-
seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps);
628-
629-
mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
630-
if ((opts->delegate_progs & mask) == mask)
631-
seq_printf(m, ",delegate_progs=any");
632-
else if (opts->delegate_progs)
633-
seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs);
634-
635-
mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
636-
if ((opts->delegate_attachs & mask) == mask)
637-
seq_printf(m, ",delegate_attachs=any");
638-
else if (opts->delegate_attachs)
639-
seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs);
747+
if (opts->delegate_cmds || opts->delegate_maps ||
748+
opts->delegate_progs || opts->delegate_attachs) {
749+
struct bpffs_btf_enums info;
750+
751+
/* ignore errors, fallback to hex */
752+
(void)find_bpffs_btf_enums(&info);
753+
754+
mask = (1ULL << __MAX_BPF_CMD) - 1;
755+
seq_print_delegate_opts(m, "delegate_cmds",
756+
info.btf, info.cmd_t, "BPF_",
757+
opts->delegate_cmds, mask);
758+
759+
mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
760+
seq_print_delegate_opts(m, "delegate_maps",
761+
info.btf, info.map_t, "BPF_MAP_TYPE_",
762+
opts->delegate_maps, mask);
763+
764+
mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
765+
seq_print_delegate_opts(m, "delegate_progs",
766+
info.btf, info.prog_t, "BPF_PROG_TYPE_",
767+
opts->delegate_progs, mask);
768+
769+
mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
770+
seq_print_delegate_opts(m, "delegate_attachs",
771+
info.btf, info.attach_t, "BPF_",
772+
opts->delegate_attachs, mask);
773+
}
774+
640775
return 0;
641776
}
642777

@@ -686,7 +821,6 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
686821
kuid_t uid;
687822
kgid_t gid;
688823
int opt, err;
689-
u64 msk;
690824

691825
opt = fs_parse(fc, bpf_fs_parameters, param, &result);
692826
if (opt < 0) {
@@ -741,24 +875,63 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
741875
case OPT_DELEGATE_CMDS:
742876
case OPT_DELEGATE_MAPS:
743877
case OPT_DELEGATE_PROGS:
744-
case OPT_DELEGATE_ATTACHS:
745-
if (strcmp(param->string, "any") == 0) {
746-
msk = ~0ULL;
747-
} else {
748-
err = kstrtou64(param->string, 0, &msk);
749-
if (err)
750-
return err;
878+
case OPT_DELEGATE_ATTACHS: {
879+
struct bpffs_btf_enums info;
880+
const struct btf_type *enum_t;
881+
const char *enum_pfx;
882+
u64 *delegate_msk, msk = 0;
883+
char *p;
884+
int val;
885+
886+
/* ignore errors, fallback to hex */
887+
(void)find_bpffs_btf_enums(&info);
888+
889+
switch (opt) {
890+
case OPT_DELEGATE_CMDS:
891+
delegate_msk = &opts->delegate_cmds;
892+
enum_t = info.cmd_t;
893+
enum_pfx = "BPF_";
894+
break;
895+
case OPT_DELEGATE_MAPS:
896+
delegate_msk = &opts->delegate_maps;
897+
enum_t = info.map_t;
898+
enum_pfx = "BPF_MAP_TYPE_";
899+
break;
900+
case OPT_DELEGATE_PROGS:
901+
delegate_msk = &opts->delegate_progs;
902+
enum_t = info.prog_t;
903+
enum_pfx = "BPF_PROG_TYPE_";
904+
break;
905+
case OPT_DELEGATE_ATTACHS:
906+
delegate_msk = &opts->delegate_attachs;
907+
enum_t = info.attach_t;
908+
enum_pfx = "BPF_";
909+
break;
910+
default:
911+
return -EINVAL;
751912
}
913+
914+
while ((p = strsep(&param->string, ":"))) {
915+
if (strcmp(p, "any") == 0) {
916+
msk |= ~0ULL;
917+
} else if (find_btf_enum_const(info.btf, enum_t, enum_pfx, p, &val)) {
918+
msk |= 1ULL << val;
919+
} else {
920+
err = kstrtou64(p, 0, &msk);
921+
if (err)
922+
return err;
923+
}
924+
}
925+
752926
/* Setting delegation mount options requires privileges */
753927
if (msk && !capable(CAP_SYS_ADMIN))
754928
return -EPERM;
755-
switch (opt) {
756-
case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break;
757-
case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break;
758-
case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break;
759-
case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break;
760-
default: return -EINVAL;
761-
}
929+
930+
*delegate_msk |= msk;
931+
break;
932+
}
933+
default:
934+
/* ignore unknown mount options */
762935
break;
763936
}
764937

0 commit comments

Comments
 (0)