linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii@kernel.org>
To: <bpf@vger.kernel.org>, <netdev@vger.kernel.org>,
	<paul@paul-moore.com>, <brauner@kernel.org>
Cc: <linux-fsdevel@vger.kernel.org>,
	<linux-security-module@vger.kernel.org>, <keescook@chromium.org>,
	<kernel-team@meta.com>, <sargun@sargun.me>
Subject: [PATCH RFC bpf-next 2/3] bpf: extend parsing logic for BPF FS delegate_cmds mount option
Date: Thu, 7 Dec 2023 14:27:54 -0800	[thread overview]
Message-ID: <20231207222755.3920286-3-andrii@kernel.org> (raw)
In-Reply-To: <20231207222755.3920286-1-andrii@kernel.org>

Besides already supported special "any" value and hex bit mask, support
string-based parsing of enum bpf_cmd values based on exact enumerator
names. We use __BPF_CMD_MAPPER macro to generate a lookup table. So
"BPF_PROG_LOAD" and "BPF_MAP_CREATE" are valid values to specify for
delegate_cmds options.

A bunch of code changes are setting up generic routines which will make
similar support for delegate_maps, delegate_progs, and delegate_attachs
mount options trivial to add once we have similar mapper macros for
respective enums.

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 (which shouldn't happen for
delegate_cmds, but is necessary for the same routing to be able to
handle other delegate_xxx options).

Example below shows various ways to specify delegate_cmds options
through mount command and how mount options are printed back:

  $ sudo mkdir -p /sys/fs/bpf/token
  $ sudo mount -t bpf bpffs /sys/fs/bpf/token \
               -o delegate_cmds=BPF_PROG_LOAD \
               -o delegate_cmds=BPF_MAP_CREATE \
               -o delegate_cmds=BPF_TOKEN_CREATE:BPF_BTF_LOAD:BPF_LINK_CREATE
  $ mount | grep token
  bpffs on /sys/fs/bpf/token type bpf (rw,relatime,delegate_cmds=BPF_MAP_CREATE:BPF_PROG_LOAD:BPF_BTF_LOAD:BPF_LINK_CREATE:BPF_TOKEN_CREATE)

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 kernel/bpf/inode.c | 127 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 96 insertions(+), 31 deletions(-)

diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index 5359a0929c35..20b2d170fc0b 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -595,6 +595,54 @@ struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type typ
 }
 EXPORT_SYMBOL(bpf_prog_get_type_path);
 
+#define __BPF_KV_FN(name, val) { #name, val },
+static const struct constant_table cmd_kvs[] = {
+	__BPF_CMD_MAPPER(__BPF_KV_FN)
+	{}
+};
+static const struct constant_table map_kvs[] = {
+	{}
+};
+static const struct constant_table prog_kvs[] = {
+	{}
+};
+static const struct constant_table attach_kvs[] = {
+	{}
+};
+#undef __BPF_KV_FN
+
+static void seq_print_delegate_opts(struct seq_file *m,
+				    const char *opt_name,
+				    const struct constant_table *tbl,
+				    u64 delegate_msk, u64 any_msk)
+{
+	bool first = true;
+	u64 msk;
+	int i;
+
+	delegate_msk &= any_msk; /* clear unknown bits */
+
+	if (delegate_msk == 0)
+		return;
+
+	if (delegate_msk == any_msk) {
+		seq_printf(m, ",%s=any", opt_name);
+		return;
+	}
+
+	seq_printf(m, ",%s", opt_name);
+	for (i = 0; cmd_kvs[i].name; i++) {
+		msk = 1ULL << cmd_kvs[i].value;
+		if (delegate_msk & msk) {
+			seq_printf(m, "%c%s", first ? '=' : ':', cmd_kvs[i].name);
+			delegate_msk &= ~msk;
+			first = false;
+		}
+	}
+	if (delegate_msk)
+		seq_printf(m, "%c0x%llx", first ? '=' : ':', delegate_msk);
+}
+
 /*
  * Display the mount options in /proc/mounts.
  */
@@ -608,28 +656,17 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root)
 		seq_printf(m, ",mode=%o", mode);
 
 	mask = (1ULL << __MAX_BPF_CMD) - 1;
-	if ((opts->delegate_cmds & mask) == mask)
-		seq_printf(m, ",delegate_cmds=any");
-	else if (opts->delegate_cmds)
-		seq_printf(m, ",delegate_cmds=0x%llx", opts->delegate_cmds);
+	seq_print_delegate_opts(m, "delegate_cmds", cmd_kvs, opts->delegate_cmds, mask);
 
 	mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
-	if ((opts->delegate_maps & mask) == mask)
-		seq_printf(m, ",delegate_maps=any");
-	else if (opts->delegate_maps)
-		seq_printf(m, ",delegate_maps=0x%llx", opts->delegate_maps);
+	seq_print_delegate_opts(m, "delegate_maps", map_kvs, opts->delegate_maps, mask);
 
 	mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
-	if ((opts->delegate_progs & mask) == mask)
-		seq_printf(m, ",delegate_progs=any");
-	else if (opts->delegate_progs)
-		seq_printf(m, ",delegate_progs=0x%llx", opts->delegate_progs);
+	seq_print_delegate_opts(m, "delegate_progs", prog_kvs, opts->delegate_progs, mask);
 
 	mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
-	if ((opts->delegate_attachs & mask) == mask)
-		seq_printf(m, ",delegate_attachs=any");
-	else if (opts->delegate_attachs)
-		seq_printf(m, ",delegate_attachs=0x%llx", opts->delegate_attachs);
+	seq_print_delegate_opts(m, "delegate_attachs", attach_kvs, opts->delegate_attachs, mask);
+
 	return 0;
 }
 
@@ -673,7 +710,6 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
 	struct bpf_mount_opts *opts = fc->s_fs_info;
 	struct fs_parse_result result;
 	int opt, err;
-	u64 msk;
 
 	opt = fs_parse(fc, bpf_fs_parameters, param, &result);
 	if (opt < 0) {
@@ -700,26 +736,55 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
 	case OPT_DELEGATE_CMDS:
 	case OPT_DELEGATE_MAPS:
 	case OPT_DELEGATE_PROGS:
-	case OPT_DELEGATE_ATTACHS:
-		if (strcmp(param->string, "any") == 0) {
-			msk = ~0ULL;
-		} else {
-			err = kstrtou64(param->string, 0, &msk);
-			if (err)
-				return err;
+	case OPT_DELEGATE_ATTACHS: {
+		const struct constant_table *kvs;
+		u64 *delegate_msk, msk = 0;
+		char *p;
+		int val;
+
+		switch (opt) {
+		case OPT_DELEGATE_CMDS:
+			delegate_msk = &opts->delegate_cmds;
+			kvs = cmd_kvs;
+			break;
+		case OPT_DELEGATE_MAPS:
+			delegate_msk = &opts->delegate_maps;
+			kvs = map_kvs;
+			break;
+		case OPT_DELEGATE_PROGS:
+			delegate_msk = &opts->delegate_progs;
+			kvs = prog_kvs;
+			break;
+		case OPT_DELEGATE_ATTACHS:
+			delegate_msk = &opts->delegate_attachs;
+			kvs = attach_kvs;
+			break;
+		default:
+			return -EINVAL;
 		}
+
+		while ((p = strsep(&param->string, ":"))) {
+			if (strcmp(p, "any") == 0) {
+				msk |= ~0ULL;
+			} else if ((val = lookup_constant(kvs, p, -1)) >= 0) {
+				msk |= 1ULL << val;
+			} else {
+				err = kstrtou64(p, 0, &msk);
+				if (err)
+					return err;
+			}
+		}
+
 		/* Setting delegation mount options requires privileges */
 		if (msk && !capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		switch (opt) {
-		case OPT_DELEGATE_CMDS: opts->delegate_cmds |= msk; break;
-		case OPT_DELEGATE_MAPS: opts->delegate_maps |= msk; break;
-		case OPT_DELEGATE_PROGS: opts->delegate_progs |= msk; break;
-		case OPT_DELEGATE_ATTACHS: opts->delegate_attachs |= msk; break;
-		default: return -EINVAL;
-		}
+
+		*delegate_msk |= msk;
 		break;
 	}
+	default:
+		/* ignore unknown mount options */
+	}
 
 	return 0;
 }
-- 
2.34.1


  parent reply	other threads:[~2023-12-07 22:28 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-07 22:27 [PATCH RFC bpf-next 0/3] BPF FS mount options parsing follow ups Andrii Nakryiko
2023-12-07 22:27 ` [PATCH RFC bpf-next 1/3] bpf: add mapper macro for bpf_cmd enum Andrii Nakryiko
2023-12-12  2:40   ` Alexei Starovoitov
2023-12-12  4:01     ` Andrii Nakryiko
2023-12-12  4:06       ` Alexei Starovoitov
2023-12-13  1:37         ` Martin KaFai Lau
2023-12-13 17:26           ` Andrii Nakryiko
2023-12-07 22:27 ` Andrii Nakryiko [this message]
2023-12-07 22:27 ` [PATCH RFC bpf-next 3/3] selftests/bpf: utilize string values for delegate_xxx mount options Andrii Nakryiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231207222755.3920286-3-andrii@kernel.org \
    --to=andrii@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=brauner@kernel.org \
    --cc=keescook@chromium.org \
    --cc=kernel-team@meta.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=paul@paul-moore.com \
    --cc=sargun@sargun.me \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).