mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH bpf 0/3] bpf: expose cgroup preorder attachment state to userspace
@ 2026-09-18 17:24 Hui Su
  2026-09-18 17:24 ` [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries Hui Su
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Hui Su @ 2026-09-18 17:24 UTC (permalink / raw)
  To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yonghong Song, Quentin Monnet, Martin KaFai Lau, Song Liu,
	Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan,
	linux-kselftest, linux-kernel, Hui Su

Commit 4b82b181a26c ("bpf: Allow pre-ordering for bpf cgroup progs")
introduced BPF_F_PREORDER to request pre-order execution across the
cgroup hierarchy. While the kernel records BPF_F_PREORDER in pl->flags,
__cgroup_bpf_query() currently fails to report it to user space in
prog_attach_flags[] during direct cgroup program queries.

This series fixes the kernel query path, extends BPF selftests to
verify the fix, and updates bpftool to recognize and format the
BPF_F_PREORDER flag.

Patch 1 fixes __cgroup_bpf_query() to merge (pl->flags & BPF_F_PREORDER)
with cgroup flags when copying per-program attach flags to user space.

Patch 2 extends selftests/bpf (cgroup_mprog_opts) to verify that direct
and link queries report BPF_F_PREORDER (0x42), matching programs by
prog_id with guarded failure paths.

Patch 3 adds bpftool support: a bitmask flags formatter for cgroup show,
support for "preorder" in cgroup attach, documentation updates, and bash
completion.

Testing:
- Verified on unpatched kernel: selftest reproduces failure
  (actual 2 != expected 66).
- Verified on patched kernel (bpf/master): both cgroup_mprog_opts and
  cgroup_preorder pass 100% in QEMU guest environment.
- Verified bpftool build, format unit tests, and checkpatch
  (0 errors, 0 warnings).

Hui Su (3):
  bpf: Report BPF_F_PREORDER in cgroup program queries
  selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments
  bpftool: Add support for BPF_F_PREORDER cgroup attach flag

 kernel/bpf/cgroup.c                           | 16 ++--
 .../bpftool/Documentation/bpftool-cgroup.rst  |  9 +-
 tools/bpf/bpftool/bash-completion/bpftool     |  2 +-
 tools/bpf/bpftool/cgroup.c                    | 55 +++++++----
 .../bpf/prog_tests/cgroup_mprog_opts.c        | 94 ++++++++++++++++++-
 5 files changed, 144 insertions(+), 32 deletions(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries
  2026-09-18 17:24 [PATCH bpf 0/3] bpf: expose cgroup preorder attachment state to userspace Hui Su
@ 2026-09-18 17:24 ` Hui Su
  2026-09-18 17:51   ` Alexei Starovoitov
  2026-09-18 18:23   ` bot+bpf-ci
  2026-09-18 17:24 ` [PATCH bpf 2/3] selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments Hui Su
  2026-09-18 17:24 ` [PATCH bpf 3/3] bpftool: Add support for BPF_F_PREORDER cgroup attach flag Hui Su
  2 siblings, 2 replies; 8+ messages in thread
From: Hui Su @ 2026-09-18 17:24 UTC (permalink / raw)
  To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yonghong Song, Quentin Monnet, Martin KaFai Lau, Song Liu,
	Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan,
	linux-kselftest, linux-kernel, Hui Su

Commit 4b82b181a26c ("bpf: Allow pre-ordering for bpf cgroup progs")
introduced BPF_F_PREORDER to request pre-order execution across the
cgroup hierarchy, altering the effective prog array ordering.

While pl->flags stores BPF_F_PREORDER for each attached program,
__cgroup_bpf_query() currently fails to report it. When querying
attached programs (!effective_query), __cgroup_bpf_query() fills
prog_attach_flags[] with cgrp->bpf.flags[atype] for all entries,
omitting the per-program BPF_F_PREORDER attribute.

As a result, user space tools and query callers cannot distinguish
pre-ordered programs from standard multi-prog attachments via
BPF_PROG_QUERY.

Fix this by merging (pl->flags & BPF_F_PREORDER) with the cgroup-wide
flags when copying prog_attach_flags to user space. Only BPF_F_PREORDER
is extracted from pl->flags to ensure transient positioning flags (such
as BPF_F_BEFORE, BPF_F_AFTER, BPF_F_ID, or BPF_F_REPLACE) are not
leaked to user space. Also perform both ID and attach flags copies
within the same hlist iteration.

Fixes: 4b82b181a26c ("bpf: Allow pre-ordering for bpf cgroup progs")
Signed-off-by: Hui Su <sh_def@163.com>
---
 kernel/bpf/cgroup.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 149672c76c49..e7c7efa1baa7 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -1353,19 +1353,19 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
 				id = prog->aux->id;
 				if (copy_to_user(prog_ids + i, &id, sizeof(id)))
 					return -EFAULT;
+				if (prog_attach_flags) {
+					flags = cgrp->bpf.flags[atype] |
+						(pl->flags & BPF_F_PREORDER);
+					if (copy_to_user(prog_attach_flags + i,
+							 &flags, sizeof(flags)))
+						return -EFAULT;
+				}
 				if (++i == cnt)
 					break;
 			}
 
-			if (prog_attach_flags) {
-				flags = cgrp->bpf.flags[atype];
-
-				for (i = 0; i < cnt; i++)
-					if (copy_to_user(prog_attach_flags + i,
-							 &flags, sizeof(flags)))
-						return -EFAULT;
+			if (prog_attach_flags)
 				prog_attach_flags += cnt;
-			}
 		}
 
 		prog_ids += cnt;
-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH bpf 2/3] selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments
  2026-09-18 17:24 [PATCH bpf 0/3] bpf: expose cgroup preorder attachment state to userspace Hui Su
  2026-09-18 17:24 ` [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries Hui Su
@ 2026-09-18 17:24 ` Hui Su
  2026-09-18 18:23   ` bot+bpf-ci
  2026-09-18 17:24 ` [PATCH bpf 3/3] bpftool: Add support for BPF_F_PREORDER cgroup attach flag Hui Su
  2 siblings, 1 reply; 8+ messages in thread
From: Hui Su @ 2026-09-18 17:24 UTC (permalink / raw)
  To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yonghong Song, Quentin Monnet, Martin KaFai Lau, Song Liu,
	Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan,
	linux-kselftest, linux-kernel, Hui Su

Extend cgroup_mprog_opts selftests to verify that BPF_PROG_QUERY reports
BPF_F_PREORDER in prog_attach_flags for both direct program and link
attachments.

Specifically, in test_preorder_prog_attach_detach() and
test_preorder_link_attach_detach(), verify that:
- Programs attached with BPF_F_PREORDER report
  BPF_F_ALLOW_MULTI | BPF_F_PREORDER (0x42) in prog_attach_flags.
- Programs attached without BPF_F_PREORDER report BPF_F_ALLOW_MULTI (0x2).
- Transient flags such as BPF_F_AFTER or BPF_F_LINK are not present in
  prog_attach_flags.
- Per-program attach flags are validated by matching each attached prog_id
  via a query helper, avoiding fragile assumptions on the internal slot
  order of the direct query list.

Signed-off-by: Hui Su <sh_def@163.com>
---
 .../bpf/prog_tests/cgroup_mprog_opts.c        | 94 ++++++++++++++++++-
 1 file changed, 91 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c b/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c
index bb60704a3ef9..343357d9c460 100644
--- a/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c
+++ b/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c
@@ -273,13 +273,31 @@ static void test_link_attach_detach(int atype)
 	close(cg);
 }
 
+static int find_prog_attach_flags(const struct bpf_prog_query_opts *opts,
+				  __u32 prog_id, __u32 *flags)
+{
+	__u32 i;
+
+	for (i = 0; i < opts->count; i++) {
+		if (opts->prog_ids[i] == prog_id) {
+			*flags = opts->prog_attach_flags[i];
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
 static void test_preorder_prog_attach_detach(int atype)
 {
 	LIBBPF_OPTS(bpf_prog_attach_opts, opta);
 	LIBBPF_OPTS(bpf_prog_detach_opts, optd);
-	__u32 fd1, fd2, fd3, fd4;
+	LIBBPF_OPTS(bpf_prog_query_opts, optq);
+	__u32 fd1, fd2, fd3, fd4, id1, id2, id3, id4;
+	__u32 prog_attach_flags[10] = {0};
+	__u32 prog_ids[10] = {0};
 	struct cgroup_mprog *skel;
 	int cg, err;
+	__u32 flags;
 
 	cg = test__join_cgroup("/preorder_prog_attach_detach");
 	if (!ASSERT_GE(cg, 0, "join_cgroup /preorder_prog_attach_detach"))
@@ -294,6 +312,11 @@ static void test_preorder_prog_attach_detach(int atype)
 	fd3 = bpf_program__fd(skel->progs.getsockopt_3);
 	fd4 = bpf_program__fd(skel->progs.getsockopt_4);
 
+	id1 = id_from_prog_fd(fd1);
+	id2 = id_from_prog_fd(fd2);
+	id3 = id_from_prog_fd(fd3);
+	id4 = id_from_prog_fd(fd4);
+
 	assert_mprog_count(cg, atype, 0);
 
 	LIBBPF_OPTS_RESET(opta,
@@ -357,6 +380,34 @@ static void test_preorder_prog_attach_detach(int atype)
 
 	assert_mprog_count(cg, atype, 4);
 
+	optq.prog_ids = prog_ids;
+	optq.prog_attach_flags = prog_attach_flags;
+	optq.count = 10;
+	err = bpf_prog_query_opts(cg, atype, &optq);
+	if (!ASSERT_OK(err, "prog_query"))
+		goto cleanup4;
+
+	ASSERT_EQ(optq.count, 4, "count");
+	/* Direct query reports attached programs in cgroup list order.
+	 * Lookup by prog_id to verify per-program flags independently of slot index.
+	 */
+	err = find_prog_attach_flags(&optq, id1, &flags);
+	if (ASSERT_OK(err, "find id1"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id1");
+
+	err = find_prog_attach_flags(&optq, id2, &flags);
+	if (ASSERT_OK(err, "find id2"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id2");
+
+	err = find_prog_attach_flags(&optq, id3, &flags);
+	if (ASSERT_OK(err, "find id3"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id3");
+
+	err = find_prog_attach_flags(&optq, id4, &flags);
+	if (ASSERT_OK(err, "find id4"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id4");
+
+cleanup4:
 	err = bpf_prog_detach_opts(fd4, cg, atype, &optd);
 	ASSERT_OK(err, "prog_detach");
 	assert_mprog_count(cg, atype, 3);
@@ -384,10 +435,14 @@ static void test_preorder_prog_attach_detach(int atype)
 static void test_preorder_link_attach_detach(int atype)
 {
 	LIBBPF_OPTS(bpf_cgroup_opts, opta);
+	LIBBPF_OPTS(bpf_prog_query_opts, optq);
 	struct bpf_link *link1, *link2, *link3, *link4;
 	struct cgroup_mprog *skel;
-	__u32 fd2;
-	int cg;
+	__u32 fd2, id1, id2, id3, id4;
+	__u32 prog_attach_flags[10] = {0};
+	__u32 prog_ids[10] = {0};
+	int cg, err;
+	__u32 flags;
 
 	cg = test__join_cgroup("/preorder_link_attach_detach");
 	if (!ASSERT_GE(cg, 0, "join_cgroup /preorder_link_attach_detach"))
@@ -399,6 +454,11 @@ static void test_preorder_link_attach_detach(int atype)
 
 	fd2 = bpf_program__fd(skel->progs.getsockopt_2);
 
+	id1 = id_from_prog_fd(bpf_program__fd(skel->progs.getsockopt_1));
+	id2 = id_from_prog_fd(fd2);
+	id3 = id_from_prog_fd(bpf_program__fd(skel->progs.getsockopt_3));
+	id4 = id_from_prog_fd(bpf_program__fd(skel->progs.getsockopt_4));
+
 	assert_mprog_count(cg, atype, 0);
 
 	LIBBPF_OPTS_RESET(opta,
@@ -460,6 +520,34 @@ static void test_preorder_link_attach_detach(int atype)
 
 	assert_mprog_count(cg, atype, 4);
 
+	optq.prog_ids = prog_ids;
+	optq.prog_attach_flags = prog_attach_flags;
+	optq.count = 10;
+	err = bpf_prog_query_opts(cg, atype, &optq);
+	if (!ASSERT_OK(err, "prog_query"))
+		goto cleanup4;
+
+	ASSERT_EQ(optq.count, 4, "count");
+	/* Direct query reports attached programs in cgroup list order.
+	 * Lookup by prog_id to verify per-program flags independently of slot index.
+	 */
+	err = find_prog_attach_flags(&optq, id1, &flags);
+	if (ASSERT_OK(err, "find id1"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id1");
+
+	err = find_prog_attach_flags(&optq, id2, &flags);
+	if (ASSERT_OK(err, "find id2"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id2");
+
+	err = find_prog_attach_flags(&optq, id3, &flags);
+	if (ASSERT_OK(err, "find id3"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id3");
+
+	err = find_prog_attach_flags(&optq, id4, &flags);
+	if (ASSERT_OK(err, "find id4"))
+		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id4");
+
+cleanup4:
 	bpf_link__destroy(link4);
 	assert_mprog_count(cg, atype, 3);
 
-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH bpf 3/3] bpftool: Add support for BPF_F_PREORDER cgroup attach flag
  2026-09-18 17:24 [PATCH bpf 0/3] bpf: expose cgroup preorder attachment state to userspace Hui Su
  2026-09-18 17:24 ` [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries Hui Su
  2026-09-18 17:24 ` [PATCH bpf 2/3] selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments Hui Su
@ 2026-09-18 17:24 ` Hui Su
  2026-09-18 18:23   ` bot+bpf-ci
  2 siblings, 1 reply; 8+ messages in thread
From: Hui Su @ 2026-09-18 17:24 UTC (permalink / raw)
  To: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Eduard Zingerman, Kumar Kartikeya Dwivedi
  Cc: Yonghong Song, Quentin Monnet, Martin KaFai Lau, Song Liu,
	Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan,
	linux-kselftest, linux-kernel, Hui Su

Commit 4b82b181a26c ("bpf: Allow pre-ordering for bpf cgroup progs")
introduced BPF_F_PREORDER to request pre-order execution across the
cgroup hierarchy. Furthermore, attachments legitimately use combinations
such as BPF_F_ALLOW_MULTI | BPF_F_PREORDER.

With BPF_PROG_QUERY reporting the per-program BPF_F_PREORDER attribute,
bpftool's exact-match formatter falls back to "unknown(40)" when
BPF_F_PREORDER is present alone, or "unknown(42)" when combined with
BPF_F_ALLOW_MULTI. Additionally, do_attach() only accepts "multi" and
"override", rejecting "preorder" with "unknown option".

Before:
  $ bpftool cgroup show <cg>
  1234  cgroup_inet_ingress  unknown(42)  test_prog
  $ bpftool cgroup attach <cg> cgroup_inet_ingress id 5678 multi preorder
  Error: unknown option: preorder

After:
  $ bpftool cgroup show <cg>
  1234  cgroup_inet_ingress  multi,preorder  test_prog
  $ bpftool cgroup attach <cg> cgroup_inet_ingress id 5678 multi preorder
  (attaches successfully)

Refactor the attach flags formatter to use a bitmask formatter that outputs
comma-separated flag names while preserving unrecognized bits as
"unknown(...)". Also accept "preorder" in do_attach(), and update
bpftool-cgroup.rst, usage help, and bash completion.

Signed-off-by: Hui Su <sh_def@163.com>
---
 .../bpftool/Documentation/bpftool-cgroup.rst  |  9 ++-
 tools/bpf/bpftool/bash-completion/bpftool     |  2 +-
 tools/bpf/bpftool/cgroup.c                    | 55 +++++++++++++------
 3 files changed, 45 insertions(+), 21 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
index e8185596a759..8ec2546c0b8e 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
@@ -45,7 +45,7 @@ CGROUP COMMANDS
 |     **cgroup_unix_recvmsg** | **cgroup_sysctl** |
 |     **cgroup_getsockopt** | **cgroup_setsockopt** |
 |     **cgroup_inet_sock_release** }
-| *ATTACH_FLAGS* := { **multi** | **override** }
+| *ATTACH_FLAGS* := { **multi** | **override** | **preorder** }
 
 DESCRIPTION
 ===========
@@ -75,10 +75,13 @@ bpftool cgroup attach *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
     Attach program *PROG* to the cgroup *CGROUP* with attach type *ATTACH_TYPE*
     and optional *ATTACH_FLAGS*.
 
-    *ATTACH_FLAGS* can be one of: **override** if a sub-cgroup installs some
+    *ATTACH_FLAGS* can include: **override** if a sub-cgroup installs some
     bpf program, the program in this cgroup yields to sub-cgroup program;
     **multi** if a sub-cgroup installs some bpf program, that cgroup program
-    gets run in addition to the program in this cgroup.
+    gets run in addition to the program in this cgroup;
+    **preorder** requests that this program executes before programs attached
+    further down the cgroup hierarchy during evaluation. **preorder** can be
+    combined with **multi**.
 
     Only one program is allowed to be attached to a cgroup with no attach flags
     or the **override** flag. Attaching another program will release old
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 75cbcb512eba..819757d7a360 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -1057,7 +1057,7 @@ _bpftool()
                 attach|detach)
                     local BPFTOOL_CGROUP_ATTACH_TYPES="$(bpftool feature list_builtins attach_types 2>/dev/null | \
                         grep '^cgroup_')"
-                    local ATTACH_FLAGS='multi override'
+                    local ATTACH_FLAGS='multi override preorder'
                     # Check for $prev = $command first
                     if [ $prev = $command ]; then
                         _filedir
diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
index ce69d1e5468e..aec1281c95d8 100644
--- a/tools/bpf/bpftool/cgroup.c
+++ b/tools/bpf/bpftool/cgroup.c
@@ -56,7 +56,7 @@ static const int cgroup_attach_types[] = {
 };
 
 #define HELP_SPEC_ATTACH_FLAGS						\
-	"ATTACH_FLAGS := { multi | override }"
+	"ATTACH_FLAGS := { multi | override | preorder }"
 
 #define HELP_SPEC_ATTACH_TYPES						\
 	"       ATTACH_TYPE := { cgroup_inet_ingress | cgroup_inet_egress |\n" \
@@ -269,6 +269,39 @@ static int show_effective_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
 	return 0;
 }
 
+static const char *format_attach_flags(__u32 attach_flags, char *buf, size_t sz)
+{
+	static const struct {
+		__u32 flag;
+		const char *name;
+	} flags[] = {
+		{ BPF_F_ALLOW_MULTI, "multi" },
+		{ BPF_F_ALLOW_OVERRIDE, "override" },
+		{ BPF_F_PREORDER, "preorder" },
+	};
+	size_t len = 0;
+	size_t i;
+	int n;
+
+	buf[0] = '\0';
+	for (i = 0; i < ARRAY_SIZE(flags); i++) {
+		if (attach_flags & flags[i].flag) {
+			n = snprintf(buf + len, sz - len, "%s%s",
+				     len ? "," : "", flags[i].name);
+			if (n < 0 || (size_t)n >= sz - len)
+				return buf;
+			len += n;
+			attach_flags &= ~flags[i].flag;
+		}
+	}
+
+	if (attach_flags)
+		snprintf(buf + len, sz - len, "%sunknown(%x)",
+			 len ? "," : "", attach_flags);
+
+	return buf;
+}
+
 static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
 				   int level)
 {
@@ -276,7 +309,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
 	__u32 prog_attach_flags[1024] = {0};
 	const char *attach_flags_str;
 	__u32 prog_ids[1024] = {0};
-	char buf[32];
+	char buf[64];
 	__u32 iter;
 	int ret;
 
@@ -296,21 +329,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
 		__u32 attach_flags;
 
 		attach_flags = prog_attach_flags[iter] ?: p.attach_flags;
-
-		switch (attach_flags) {
-		case BPF_F_ALLOW_MULTI:
-			attach_flags_str = "multi";
-			break;
-		case BPF_F_ALLOW_OVERRIDE:
-			attach_flags_str = "override";
-			break;
-		case 0:
-			attach_flags_str = "";
-			break;
-		default:
-			snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
-			attach_flags_str = buf;
-		}
+		attach_flags_str = format_attach_flags(attach_flags, buf, sizeof(buf));
 
 		show_bpf_prog(prog_ids[iter], type,
 			      attach_flags_str, level);
@@ -593,6 +612,8 @@ static int do_attach(int argc, char **argv)
 			attach_flags |= BPF_F_ALLOW_MULTI;
 		} else if (is_prefix(argv[i], "override")) {
 			attach_flags |= BPF_F_ALLOW_OVERRIDE;
+		} else if (is_prefix(argv[i], "preorder")) {
+			attach_flags |= BPF_F_PREORDER;
 		} else {
 			p_err("unknown option: %s", argv[i]);
 			goto exit_cgroup;
-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries
  2026-09-18 17:24 ` [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries Hui Su
@ 2026-09-18 17:51   ` Alexei Starovoitov
  2026-09-18 18:23   ` bot+bpf-ci
  1 sibling, 0 replies; 8+ messages in thread
From: Alexei Starovoitov @ 2026-09-18 17:51 UTC (permalink / raw)
  To: Hui Su, bpf, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman,
	Kumar Kartikeya Dwivedi
  Cc: Yonghong Song, Quentin Monnet, Martin KaFai Lau, Song Liu,
	Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Shuah Khan,
	linux-kselftest, linux-kernel

On Sat, Sep 19, 2026 at 02:24 AM Hui Su <sh_def@163.com> wrote:
> As a result, user space tools and query callers cannot distinguish
> pre-ordered programs from standard multi-prog attachments via
> BPF_PROG_QUERY.

[...]

> Fixes: 4b82b181a26c ("bpf: Allow pre-ordering for bpf cgroup progs")

That's not a fix. Nothing is broken.
The patch changes what BPF_PROG_QUERY returns to user space and
existing bpftool will start printing "unknown(42)" for such progs.
That shouldn't go to stable.
Drop the Fixes tag and resend the series for bpf-next.

pw-bot: cr

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf 2/3] selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments
  2026-09-18 17:24 ` [PATCH bpf 2/3] selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments Hui Su
@ 2026-09-18 18:23   ` bot+bpf-ci
  0 siblings, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-09-18 18:23 UTC (permalink / raw)
  To: sh_def, bpf, ast, daniel, andrii, eddyz87, memxor
  Cc: yonghong.song, qmo, martin.lau, song, jolsa, emil, ihor.solodrai,
	shuah, linux-kselftest, linux-kernel, sh_def, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3518 bytes --]

> diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c b/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c
> index bb60704a3ef92..343357d9c460e 100644
> --- a/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c
> +++ b/tools/testing/selftests/bpf/prog_tests/cgroup_mprog_opts.c

[ ... ]

> @@ -357,6 +380,34 @@ static void test_preorder_prog_attach_detach(int atype)
>
>  	assert_mprog_count(cg, atype, 4);
>
> +	optq.prog_ids = prog_ids;
> +	optq.prog_attach_flags = prog_attach_flags;
> +	optq.count = 10;
> +	err = bpf_prog_query_opts(cg, atype, &optq);
> +	if (!ASSERT_OK(err, "prog_query"))
> +		goto cleanup4;
> +
> +	ASSERT_EQ(optq.count, 4, "count");
> +	/* Direct query reports attached programs in cgroup list order.
> +	 * Lookup by prog_id to verify per-program flags independently of slot index.
> +	 */
> +	err = find_prog_attach_flags(&optq, id1, &flags);
> +	if (ASSERT_OK(err, "find id1"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id1");
> +
> +	err = find_prog_attach_flags(&optq, id2, &flags);
> +	if (ASSERT_OK(err, "find id2"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id2");
> +
> +	err = find_prog_attach_flags(&optq, id3, &flags);
> +	if (ASSERT_OK(err, "find id3"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id3");
> +
> +	err = find_prog_attach_flags(&optq, id4, &flags);
> +	if (ASSERT_OK(err, "find id4"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id4");
> +
> +cleanup4:
>  	err = bpf_prog_detach_opts(fd4, cg, atype, &optd);

[ ... ]

> @@ -460,6 +520,34 @@ static void test_preorder_link_attach_detach(int atype)
>
>  	assert_mprog_count(cg, atype, 4);
>
> +	optq.prog_ids = prog_ids;
> +	optq.prog_attach_flags = prog_attach_flags;
> +	optq.count = 10;
> +	err = bpf_prog_query_opts(cg, atype, &optq);
> +	if (!ASSERT_OK(err, "prog_query"))
> +		goto cleanup4;
> +
> +	ASSERT_EQ(optq.count, 4, "count");
> +	/* Direct query reports attached programs in cgroup list order.
> +	 * Lookup by prog_id to verify per-program flags independently of slot index.
> +	 */
> +	err = find_prog_attach_flags(&optq, id1, &flags);
> +	if (ASSERT_OK(err, "find id1"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id1");
> +
> +	err = find_prog_attach_flags(&optq, id2, &flags);
> +	if (ASSERT_OK(err, "find id2"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id2");
> +
> +	err = find_prog_attach_flags(&optq, id3, &flags);
> +	if (ASSERT_OK(err, "find id3"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI | BPF_F_PREORDER, "flags id3");
> +
> +	err = find_prog_attach_flags(&optq, id4, &flags);
> +	if (ASSERT_OK(err, "find id4"))
> +		ASSERT_EQ(flags, BPF_F_ALLOW_MULTI, "flags id4");
> +
> +cleanup4:
>  	bpf_link__destroy(link4);

This isn't a bug, but since the patch already introduces a helper
(find_prog_attach_flags), would it be worth folding this
query-and-check block into one too, so the two preorder subtests
share it instead of carrying identical copies?

The pattern appears twice: first in test_preorder_prog_attach_detach()
and again verbatim in test_preorder_link_attach_detach() - same query
setup, same comment, same four id/flag expectations, together with
duplicated locals (prog_ids[10], prog_attach_flags[10], flags, optq).


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35376083935

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries
  2026-09-18 17:24 ` [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries Hui Su
  2026-09-18 17:51   ` Alexei Starovoitov
@ 2026-09-18 18:23   ` bot+bpf-ci
  1 sibling, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-09-18 18:23 UTC (permalink / raw)
  To: sh_def, bpf, ast, daniel, andrii, eddyz87, memxor
  Cc: yonghong.song, qmo, martin.lau, song, jolsa, emil, ihor.solodrai,
	shuah, linux-kselftest, linux-kernel, sh_def, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3777 bytes --]

> diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
> index 149672c76c49c..e7c7efa1baa75 100644
> --- a/kernel/bpf/cgroup.c
> +++ b/kernel/bpf/cgroup.c
> @@ -1353,19 +1353,19 @@ static int __cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
>  				id = prog->aux->id;
>  				if (copy_to_user(prog_ids + i, &id, sizeof(id)))
>  					return -EFAULT;
> +				if (prog_attach_flags) {
> +					flags = cgrp->bpf.flags[atype] |
> +						(pl->flags & BPF_F_PREORDER);
> +					if (copy_to_user(prog_attach_flags + i,
> +							 &flags, sizeof(flags)))
> +						return -EFAULT;
> +				}
>  				if (++i == cnt)
>  					break;
>  			}
>
> -			if (prog_attach_flags) {
> -				flags = cgrp->bpf.flags[atype];
> -
> -				for (i = 0; i < cnt; i++)
> -					if (copy_to_user(prog_attach_flags + i,
> -							 &flags, sizeof(flags)))
> -						return -EFAULT;
> +			if (prog_attach_flags)
>  				prog_attach_flags += cnt;
> -			}
>  		}
>
>  		prog_ids += cnt;

This changes BPF_PROG_QUERY to report a new flag value (BPF_F_PREORDER)
that was never reported before. Could this cause compatibility issues
with the stable backport?

Before this patch, prog_attach_flags[i] could only contain
BPF_F_ALLOW_OVERRIDE (0x1) and BPF_F_ALLOW_MULTI (0x2). After this patch,
it can additionally carry BPF_F_PREORDER (0x40), producing new values 0x40
and 0x42 where 0x00/0x02 appeared before.

Existing in-tree userspace does exact-match formatting on these values.
tools/bpf/bpftool/cgroup.c, show_attached_bpf_progs(), before commit
2af5b738880b2 (the third commit in this series):

    attach_flags = prog_attach_flags[iter] ?: p.attach_flags;

    switch (attach_flags) {
    case BPF_F_ALLOW_MULTI:
            attach_flags_str = "multi";
            break;
    case BPF_F_ALLOW_OVERRIDE:
            attach_flags_str = "override";
            break;
    case 0:
            attach_flags_str = "";
            break;
    default:
            snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
            attach_flags_str = buf;
    }

The series' third commit documents the fallout: bpftool displays
"unknown(40)" when BPF_F_PREORDER is present alone, or "unknown(42)" when
combined with BPF_F_ALLOW_MULTI.

Within this series that is resolved (bpftool is fixed in commit 3), but
the tagging creates an asymmetry: this commit carries Fixes: 4b82b181a26c
(v6.15) which drives stable selection, while neither the selftest nor the
bpftool commit carries a Fixes: tag or stable Cc.

A stable backport of this commit alone would land the new query output on
a stable tree whose bpftool still has the exact-match switch, turning
bpftool cgroup show output from "multi" into "unknown(42)" for pre-ordered
attachments. The same skew applies to any distro bpftool older than
commit 3.

Should the Fixes: tag be dropped, or should the bpftool commit also carry
the same Fixes: tag so the two are backported together?

Also, the commit message does not state that BPF_PROG_QUERY starts
returning a previously-unreported bit in prog_attach_flags[]. Could that
compatibility fact be stated explicitly for reviewers?

---

Alexei Starovoitov raised a concern about the Fixes tag and target tree.
Alexei noted that this is not a bug fix but a user-space API change, and
existing bpftool will display "unknown(42)" for programs with
BPF_F_PREORDER. The suggestion was to target bpf-next (not bpf) and drop
the Fixes tag to prevent backporting to stable kernels.

Should this series target bpf-next instead of bpf, and should the Fixes
tag be removed?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35376083935

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH bpf 3/3] bpftool: Add support for BPF_F_PREORDER cgroup attach flag
  2026-09-18 17:24 ` [PATCH bpf 3/3] bpftool: Add support for BPF_F_PREORDER cgroup attach flag Hui Su
@ 2026-09-18 18:23   ` bot+bpf-ci
  0 siblings, 0 replies; 8+ messages in thread
From: bot+bpf-ci @ 2026-09-18 18:23 UTC (permalink / raw)
  To: sh_def, bpf, ast, daniel, andrii, eddyz87, memxor
  Cc: yonghong.song, qmo, martin.lau, song, jolsa, emil, ihor.solodrai,
	shuah, linux-kselftest, linux-kernel, sh_def, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, mason, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 6612 bytes --]

> diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> index e8185596a759b..8ec2546c0b8ee 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> @@ -45,7 +45,7 @@ CGROUP COMMANDS
> |     **cgroup_unix_recvmsg** | **cgroup_sysctl** |
> |     **cgroup_getsockopt** | **cgroup_setsockopt** |
> |     **cgroup_inet_sock_release** }
> -| *ATTACH_FLAGS* := { **multi** | **override** }
> +| *ATTACH_FLAGS* := { **multi** | **override** | **preorder** }
>
> DESCRIPTION
> ===========
> @@ -75,10 +75,13 @@ bpftool cgroup attach *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
>     Attach program *PROG* to the cgroup *CGROUP* with attach type *ATTACH_TYPE*
>     and optional *ATTACH_FLAGS*.
>
> -    *ATTACH_FLAGS* can be one of: **override** if a sub-cgroup installs some
> +    *ATTACH_FLAGS* can include: **override** if a sub-cgroup installs some
>     bpf program, the program in this cgroup yields to sub-cgroup program;
>     **multi** if a sub-cgroup installs some bpf program, that cgroup program
> -    gets run in addition to the program in this cgroup.
> +    gets run in addition to the program in this cgroup;
> +    **preorder** requests that this program executes before programs attached
> +    further down the cgroup hierarchy during evaluation. **preorder** can be
> +    combined with **multi**.

Does the new description accurately capture BPF_F_PREORDER's ordering
behavior? The paragraph says preorder programs execute "before programs
attached further down the cgroup hierarchy", which focuses on descendant
cgroups. But compute_effective_progs() in kernel/bpf/cgroup.c places all
preorder programs before all non-preorder programs regardless of where they
are attached:

    fstart = preorder_cnt;
    bstart = preorder_cnt - 1;
    ...
        if (pl->flags & BPF_F_PREORDER) {
            item = &progs->items[bstart];
            bstart--;
        } else {
            item = &progs->items[fstart];
            fstart++;
        }

This means a preorder program runs before every non-preorder program,
including those attached in the same cgroup and in ancestor cgroups. Commit
4b82b181a26c's example shows root with p1,p2 and a child with p3,p4 where
p2 and p4 are preorder - the effective order is "p2 p4 p3 p1". So the
child's preorder p4 runs before the root's non-preorder p1, and p2 runs
before its same-cgroup sibling p1.

Also, the paragraph says preorder "can be combined with multi", but
do_attach() now accepts "preorder" as a standalone flag. When used alone
(without multi), does __cgroup_bpf_attach() stay in the NONE regime where
"Only one program is allowed to be attached to a cgroup"? The phrase "can
be combined" leaves it ambiguous whether preorder alone enables multi-prog
attachment.

>
>     Only one program is allowed to be attached to a cgroup with no attach flags
>     or the **override** flag. Attaching another program will release old

[ ... ]

> diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
> index 75cbcb512ebae..819757d7a3609 100644
> --- a/tools/bpf/bpftool/bash-completion/bpftool
> +++ b/tools/bpf/bpftool/bash-completion/bpftool
> @@ -1057,7 +1057,7 @@ _bpftool()
>                 attach|detach)
>                     local BPFTOOL_CGROUP_ATTACH_TYPES="$(bpftool feature list_builtins attach_types 2>/dev/null | \
>                         grep '^cgroup_')"
> -                    local ATTACH_FLAGS='multi override'
> +                    local ATTACH_FLAGS='multi override preorder'
>                     # Check for $prev = $command first
>                     if [ $prev = $command ]; then
>                         _filedir

Can bash completion handle combined flags after this change? The commit
message's After: example shows:

  $ bpftool cgroup attach <cg> cgroup_inet_ingress id 5678 multi preorder

and the rst documentation states "preorder can be combined with multi". But
ATTACH_FLAGS is passed to _bpftool_one_of_list(), which is defined as:

    _bpftool_one_of_list()
    {
        _bpftool_search_list $* && return 1
        COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) )
    }

This helper returns early once any word from the list is already on the
command line, leaving COMPREPLY empty. That was correct when the list was
the mutually-exclusive pair {multi, override}, but now that preorder can
combine with multi, typing "... multi <TAB>" finds "multi" in the words
array and suppresses all completions. Won't this prevent completing the
second flag?

> diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
> index ce69d1e5468e3..aec1281c95d8e 100644
> --- a/tools/bpf/bpftool/cgroup.c
> +++ b/tools/bpf/bpftool/cgroup.c
> @@ -56,7 +56,7 @@ static const int cgroup_attach_types[] = {
> };
>
> #define HELP_SPEC_ATTACH_FLAGS						\
> -	"ATTACH_FLAGS := { multi | override }"
> +	"ATTACH_FLAGS := { multi | override | preorder }"

[ ... ]

> +static const char *format_attach_flags(__u32 attach_flags, char *buf, size_t sz)
> +{
> +	static const struct {
> +		__u32 flag;
> +		const char *name;
> +	} flags[] = {
> +		{ BPF_F_ALLOW_MULTI, "multi" },
> +		{ BPF_F_ALLOW_OVERRIDE, "override" },
> +		{ BPF_F_PREORDER, "preorder" },
> +	};
> +	size_t len = 0;
> +	size_t i;
> +	int n;
> +
> +	buf[0] = '\0';
> +	for (i = 0; i < ARRAY_SIZE(flags); i++) {
> +		if (attach_flags & flags[i].flag) {
> +			n = snprintf(buf + len, sz - len, "%s%s",
> +				     len ? "," : "", flags[i].name);
> +			if (n < 0 || (size_t)n >= sz - len)
> +				return buf;
> +			len += n;
> +			attach_flags &= ~flags[i].flag;
> +		}
> +	}
> +
> +	if (attach_flags)
> +		snprintf(buf + len, sz - len, "%sunknown(%x)",
> +			 len ? "," : "", attach_flags);
> +
> +	return buf;
> +}

[ ... ]

> @@ -593,6 +612,8 @@ static int do_attach(int argc, char **argv)
> 			attach_flags |= BPF_F_ALLOW_MULTI;
> 		} else if (is_prefix(argv[i], "override")) {
> 			attach_flags |= BPF_F_ALLOW_OVERRIDE;
> +		} else if (is_prefix(argv[i], "preorder")) {
> +			attach_flags |= BPF_F_PREORDER;
> 		} else {
> 			p_err("unknown option: %s", argv[i]);
> 			goto exit_cgroup;

[ ... ]

This looks like a bug fix for commit 4b82b181a26c. Should this include:

  Fixes: 4b82b181a26c ("bpf: Allow pre-ordering for bpf cgroup progs")


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/35376083935

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-18 18:23 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 17:24 [PATCH bpf 0/3] bpf: expose cgroup preorder attachment state to userspace Hui Su
2026-09-18 17:24 ` [PATCH bpf 1/3] bpf: Report BPF_F_PREORDER in cgroup program queries Hui Su
2026-09-18 17:51   ` Alexei Starovoitov
2026-09-18 18:23   ` bot+bpf-ci
2026-09-18 17:24 ` [PATCH bpf 2/3] selftests/bpf: Test querying BPF_F_PREORDER cgroup attachments Hui Su
2026-09-18 18:23   ` bot+bpf-ci
2026-09-18 17:24 ` [PATCH bpf 3/3] bpftool: Add support for BPF_F_PREORDER cgroup attach flag Hui Su
2026-09-18 18:23   ` bot+bpf-ci

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®