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-fs-mount-options-parsing-follow-ups'

Andrii Nakryiko says:

====================
BPF FS mount options parsing follow ups

Original BPF token patch set ([0]) added delegate_xxx mount options which
supported only special "any" value and hexadecimal bitmask. This patch set
attempts to make specifying and inspecting these mount options more
human-friendly by supporting string constants matching corresponding bpf_cmd,
bpf_map_type, bpf_prog_type, and bpf_attach_type enumerators.

This implementation relies on BTF information to find all supported symbolic
names. If kernel wasn't built with BTF, BPF FS will still support "any" and
hex-based mask.

[0] https://patchwork.kernel.org/project/netdevbpf/list/?series=805707&state=*

v1->v2:
- strip BPF_, BPF_MAP_TYPE_, and BPF_PROG_TYPE_ prefixes,
do case-insensitive comparison, normalize to lower case (Alexei).
====================

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

+240 -55
+208 -35
kernel/bpf/inode.c
··· 595 595 } 596 596 EXPORT_SYMBOL(bpf_prog_get_type_path); 597 597 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 + 598 728 /* 599 729 * Display the mount options in /proc/mounts. 600 730 */ ··· 744 614 if (mode != S_IRWXUGO) 745 615 seq_printf(m, ",mode=%o", mode); 746 616 747 - mask = (1ULL << __MAX_BPF_CMD) - 1; 748 - if ((opts->delegate_cmds & mask) == mask) 749 - seq_printf(m, ",delegate_cmds=any"); 750 - else if (opts->delegate_cmds) 751 - seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds); 617 + if (opts->delegate_cmds || opts->delegate_maps || 618 + opts->delegate_progs || opts->delegate_attachs) { 619 + struct bpffs_btf_enums info; 752 620 753 - mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; 754 - if ((opts->delegate_maps & mask) == mask) 755 - seq_printf(m, ",delegate_maps=any"); 756 - else if (opts->delegate_maps) 757 - seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps); 621 + /* ignore errors, fallback to hex */ 622 + (void)find_bpffs_btf_enums(&info); 758 623 759 - mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; 760 - if ((opts->delegate_progs & mask) == mask) 761 - seq_printf(m, ",delegate_progs=any"); 762 - else if (opts->delegate_progs) 763 - seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs); 624 + mask = (1ULL << __MAX_BPF_CMD) - 1; 625 + seq_print_delegate_opts(m, "delegate_cmds", 626 + info.btf, info.cmd_t, "BPF_", 627 + opts->delegate_cmds, mask); 764 628 765 - mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; 766 - if ((opts->delegate_attachs & mask) == mask) 767 - seq_printf(m, ",delegate_attachs=any"); 768 - else if (opts->delegate_attachs) 769 - seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs); 629 + mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1; 630 + seq_print_delegate_opts(m, "delegate_maps", 631 + info.btf, info.map_t, "BPF_MAP_TYPE_", 632 + opts->delegate_maps, mask); 633 + 634 + mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1; 635 + seq_print_delegate_opts(m, "delegate_progs", 636 + info.btf, info.prog_t, "BPF_PROG_TYPE_", 637 + opts->delegate_progs, mask); 638 + 639 + mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1; 640 + seq_print_delegate_opts(m, "delegate_attachs", 641 + info.btf, info.attach_t, "BPF_", 642 + opts->delegate_attachs, mask); 643 + } 644 + 770 645 return 0; 771 646 } 772 647 ··· 821 686 kuid_t uid; 822 687 kgid_t gid; 823 688 int opt, err; 824 - u64 msk; 825 689 826 690 opt = fs_parse(fc, bpf_fs_parameters, param, &result); 827 691 if (opt < 0) { ··· 875 741 case OPT_DELEGATE_CMDS: 876 742 case OPT_DELEGATE_MAPS: 877 743 case OPT_DELEGATE_PROGS: 878 - case OPT_DELEGATE_ATTACHS: 879 - if (strcmp(param->string, "any") == 0) { 880 - msk = ~0ULL; 881 - } else { 882 - err = kstrtou64(param->string, 0, &msk); 883 - if (err) 884 - return err; 744 + case OPT_DELEGATE_ATTACHS: { 745 + struct bpffs_btf_enums info; 746 + const struct btf_type *enum_t; 747 + const char *enum_pfx; 748 + u64 *delegate_msk, msk = 0; 749 + char *p; 750 + int val; 751 + 752 + /* ignore errors, fallback to hex */ 753 + (void)find_bpffs_btf_enums(&info); 754 + 755 + switch (opt) { 756 + case OPT_DELEGATE_CMDS: 757 + delegate_msk = &opts->delegate_cmds; 758 + enum_t = info.cmd_t; 759 + enum_pfx = "BPF_"; 760 + break; 761 + case OPT_DELEGATE_MAPS: 762 + delegate_msk = &opts->delegate_maps; 763 + enum_t = info.map_t; 764 + enum_pfx = "BPF_MAP_TYPE_"; 765 + break; 766 + case OPT_DELEGATE_PROGS: 767 + delegate_msk = &opts->delegate_progs; 768 + enum_t = info.prog_t; 769 + enum_pfx = "BPF_PROG_TYPE_"; 770 + break; 771 + case OPT_DELEGATE_ATTACHS: 772 + delegate_msk = &opts->delegate_attachs; 773 + enum_t = info.attach_t; 774 + enum_pfx = "BPF_"; 775 + break; 776 + default: 777 + return -EINVAL; 885 778 } 779 + 780 + while ((p = strsep(&param->string, ":"))) { 781 + if (strcmp(p, "any") == 0) { 782 + msk |= ~0ULL; 783 + } else if (find_btf_enum_const(info.btf, enum_t, enum_pfx, p, &val)) { 784 + msk |= 1ULL << val; 785 + } else { 786 + err = kstrtou64(p, 0, &msk); 787 + if (err) 788 + return err; 789 + } 790 + } 791 + 886 792 /* Setting delegation mount options requires privileges */ 887 793 if (msk && !capable(CAP_SYS_ADMIN)) 888 794 return -EPERM; 889 - switch (opt) { 890 - case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break; 891 - case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break; 892 - case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break; 893 - case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break; 894 - default: return -EINVAL; 895 - } 795 + 796 + *delegate_msk |= msk; 797 + break; 798 + } 799 + default: 800 + /* ignore unknown mount options */ 896 801 break; 897 802 } 898 803
+32 -20
tools/testing/selftests/bpf/prog_tests/token.c
··· 66 66 return cap_enable_effective(old_caps, NULL); 67 67 } 68 68 69 - static int set_delegate_mask(int fs_fd, const char *key, __u64 mask) 69 + static int set_delegate_mask(int fs_fd, const char *key, __u64 mask, const char *mask_str) 70 70 { 71 71 char buf[32]; 72 72 int err; 73 73 74 - snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask); 74 + if (!mask_str) { 75 + if (mask == ~0ULL) { 76 + mask_str = "any"; 77 + } else { 78 + snprintf(buf, sizeof(buf), "0x%llx", (unsigned long long)mask); 79 + mask_str = buf; 80 + } 81 + } 82 + 75 83 err = sys_fsconfig(fs_fd, FSCONFIG_SET_STRING, key, 76 - mask == ~0ULL ? "any" : buf, 0); 84 + mask_str, 0); 77 85 if (err < 0) 78 86 err = -errno; 79 87 return err; ··· 94 86 __u64 maps; 95 87 __u64 progs; 96 88 __u64 attachs; 89 + const char *cmds_str; 90 + const char *maps_str; 91 + const char *progs_str; 92 + const char *attachs_str; 97 93 }; 98 94 99 95 static int create_bpffs_fd(void) ··· 116 104 int mnt_fd, err; 117 105 118 106 /* set up token delegation mount options */ 119 - err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds); 107 + err = set_delegate_mask(fs_fd, "delegate_cmds", opts->cmds, opts->cmds_str); 120 108 if (!ASSERT_OK(err, "fs_cfg_cmds")) 121 109 return err; 122 - err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps); 110 + err = set_delegate_mask(fs_fd, "delegate_maps", opts->maps, opts->maps_str); 123 111 if (!ASSERT_OK(err, "fs_cfg_maps")) 124 112 return err; 125 - err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs); 113 + err = set_delegate_mask(fs_fd, "delegate_progs", opts->progs, opts->progs_str); 126 114 if (!ASSERT_OK(err, "fs_cfg_progs")) 127 115 return err; 128 - err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs); 116 + err = set_delegate_mask(fs_fd, "delegate_attachs", opts->attachs, opts->attachs_str); 129 117 if (!ASSERT_OK(err, "fs_cfg_attachs")) 130 118 return err; 131 119 ··· 307 295 } 308 296 309 297 /* ensure unprivileged child cannot set delegation options */ 310 - err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1); 298 + err = set_delegate_mask(fs_fd, "delegate_cmds", 0x1, NULL); 311 299 ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm"); 312 - err = set_delegate_mask(fs_fd, "delegate_maps", 0x1); 300 + err = set_delegate_mask(fs_fd, "delegate_maps", 0x1, NULL); 313 301 ASSERT_EQ(err, -EPERM, "delegate_maps_eperm"); 314 - err = set_delegate_mask(fs_fd, "delegate_progs", 0x1); 302 + err = set_delegate_mask(fs_fd, "delegate_progs", 0x1, NULL); 315 303 ASSERT_EQ(err, -EPERM, "delegate_progs_eperm"); 316 - err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1); 304 + err = set_delegate_mask(fs_fd, "delegate_attachs", 0x1, NULL); 317 305 ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm"); 318 306 319 307 /* pass BPF FS context object to parent */ ··· 337 325 } 338 326 339 327 /* ensure unprivileged child cannot reconfigure to set delegation options */ 340 - err = set_delegate_mask(fs_fd, "delegate_cmds", ~0ULL); 328 + err = set_delegate_mask(fs_fd, "delegate_cmds", 0, "any"); 341 329 if (!ASSERT_EQ(err, -EPERM, "delegate_cmd_eperm_reconfig")) { 342 330 err = -EINVAL; 343 331 goto cleanup; 344 332 } 345 - err = set_delegate_mask(fs_fd, "delegate_maps", ~0ULL); 333 + err = set_delegate_mask(fs_fd, "delegate_maps", 0, "any"); 346 334 if (!ASSERT_EQ(err, -EPERM, "delegate_maps_eperm_reconfig")) { 347 335 err = -EINVAL; 348 336 goto cleanup; 349 337 } 350 - err = set_delegate_mask(fs_fd, "delegate_progs", ~0ULL); 338 + err = set_delegate_mask(fs_fd, "delegate_progs", 0, "any"); 351 339 if (!ASSERT_EQ(err, -EPERM, "delegate_progs_eperm_reconfig")) { 352 340 err = -EINVAL; 353 341 goto cleanup; 354 342 } 355 - err = set_delegate_mask(fs_fd, "delegate_attachs", ~0ULL); 343 + err = set_delegate_mask(fs_fd, "delegate_attachs", 0, "any"); 356 344 if (!ASSERT_EQ(err, -EPERM, "delegate_attachs_eperm_reconfig")) { 357 345 err = -EINVAL; 358 346 goto cleanup; ··· 945 933 { 946 934 if (test__start_subtest("map_token")) { 947 935 struct bpffs_opts opts = { 948 - .cmds = 1ULL << BPF_MAP_CREATE, 949 - .maps = 1ULL << BPF_MAP_TYPE_STACK, 936 + .cmds_str = "map_create", 937 + .maps_str = "stack", 950 938 }; 951 939 952 940 subtest_userns(&opts, userns_map_create); ··· 960 948 } 961 949 if (test__start_subtest("prog_token")) { 962 950 struct bpffs_opts opts = { 963 - .cmds = 1ULL << BPF_PROG_LOAD, 964 - .progs = 1ULL << BPF_PROG_TYPE_XDP, 965 - .attachs = 1ULL << BPF_XDP, 951 + .cmds_str = "PROG_LOAD", 952 + .progs_str = "XDP", 953 + .attachs_str = "xdp", 966 954 }; 967 955 968 956 subtest_userns(&opts, userns_prog_load);