* [PATCH bpf-next v1 2/2] bpf/selftests: Add test cases for retrieving classid
2025-05-28 16:16 [PATCH bpf-next v1 1/2] bpf: Restrict usage scope of bpf_get_cgroup_classid Jiayuan Chen
@ 2025-05-28 16:16 ` Jiayuan Chen
2025-05-29 16:46 ` [PATCH bpf-next v1 1/2] bpf: Restrict usage scope of bpf_get_cgroup_classid Alexei Starovoitov
1 sibling, 0 replies; 3+ messages in thread
From: Jiayuan Chen @ 2025-05-28 16:16 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman, Song Liu,
Yonghong Song, John Fastabend, KP Singh, Stanislav Fomichev,
Hao Luo, Jiri Olsa, Mykola Lysenko, Shuah Khan, Feng Yang,
Tejun Heo, linux-kernel, linux-kselftest
Covers all scenarios where classid can be retrieved with bpf.
./test_progs -a cgroup_get_classid
53/1 cgroup_get_classid/get classid from tc:OK
53/2 cgroup_get_classid/get classid from sysctl:OK
53/3 cgroup_get_classid/get classid from cgroup dev:OK
53/4 cgroup_get_classid/get classid from cgroup sockopt:OK
53 cgroup_get_classid:OK
Summary: 1/4 PASSED, 0 SKIPPED, 0 FAILED
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
.../selftests/bpf/prog_tests/cgroup_classid.c | 212 ++++++++++++++++++
.../selftests/bpf/progs/test_cgroup_classid.c | 51 +++++
2 files changed, 263 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/cgroup_classid.c
create mode 100644 tools/testing/selftests/bpf/progs/test_cgroup_classid.c
diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_classid.c b/tools/testing/selftests/bpf/prog_tests/cgroup_classid.c
new file mode 100644
index 000000000000..f00da952e52c
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/cgroup_classid.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <test_progs.h>
+#include "cgroup_helpers.h"
+#include "network_helpers.h"
+#include "test_cgroup_classid.skel.h"
+
+#define TEST_CGROUP "/cgroup_classid"
+
+static int test_cgroup_get_classid_from_tc(int cgroup_fd, int srv_fd, int srv_port, bool egress)
+{
+ struct test_cgroup_classid *skel;
+ int cli_fd = -1, ret = -1, expected;
+
+ LIBBPF_OPTS(bpf_tcx_opts, optl);
+
+ skel = test_cgroup_classid__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ return ret;
+
+ skel->bss->classid = -1;
+ if (egress) {
+ expected = getpid();
+ skel->links.tc_egress =
+ bpf_program__attach_tcx(skel->progs.tc_egress, 1, &optl);
+ } else {
+ expected = 0;
+ skel->links.tc_ingress =
+ bpf_program__attach_tcx(skel->progs.tc_ingress, 1, &optl);
+ }
+
+ cli_fd = connect_to_fd_opts(srv_fd, NULL);
+ if (!ASSERT_GE(cli_fd, 0, "connect_to_fd_opts"))
+ goto out;
+
+ ASSERT_EQ(skel->bss->classid, expected, "classid mismatch");
+ ret = 0;
+out:
+ if (cli_fd > 0)
+ close(cli_fd);
+
+ test_cgroup_classid__destroy(skel);
+ return ret;
+}
+
+static void test_cgroup_get_classid_tc(void)
+{
+ int srv_fd = -1, srv_port = -1;
+ int cgroup_fd = -1;
+
+ setup_classid_environment();
+ set_classid();
+ join_classid();
+
+ cgroup_fd = open_classid();
+ if (!ASSERT_GE(cgroup_fd, 0, "open_classid"))
+ goto out;
+
+ srv_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
+ if (!ASSERT_GE(srv_fd, 0, "srv_fd"))
+ goto out;
+
+ srv_port = get_socket_local_port(srv_fd);
+ if (!ASSERT_GE(srv_port, 0, "get_socket_local_port"))
+ goto out;
+
+ ASSERT_OK(test_cgroup_get_classid_from_tc(cgroup_fd, srv_fd, srv_port, 1), "egress");
+ ASSERT_OK(test_cgroup_get_classid_from_tc(cgroup_fd, srv_fd, srv_port, 0), "ingress");
+out:
+ if (srv_fd > 0)
+ close(srv_fd);
+ if (cgroup_fd > 0)
+ close(cgroup_fd);
+ cleanup_classid_environment();
+}
+
+static void test_cgroup_get_classid_cgroup_dev(void)
+{
+ struct test_cgroup_classid *skel = NULL;
+ int cgroup_fd = -1;
+
+ cgroup_fd = test__join_cgroup(TEST_CGROUP);
+ if (!ASSERT_GE(cgroup_fd, 0, "join cgroup"))
+ goto out;
+
+ if (!ASSERT_OK(setup_classid_environment(), "setup env"))
+ goto out;
+
+ if (!ASSERT_OK(set_classid(), "set_classid"))
+ goto out;
+
+ skel = test_cgroup_classid__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "load program"))
+ goto out;
+
+ skel->links.cg_dev =
+ bpf_program__attach_cgroup(skel->progs.cg_dev, cgroup_fd);
+
+ if (!ASSERT_OK_PTR(skel->links.cg_dev, "attach_program"))
+ goto out;
+
+ skel->bss->classid = -1;
+ if (!ASSERT_OK(join_classid(), "join_classid"))
+ goto out;
+
+ open("/dev/null", O_RDWR);
+ ASSERT_EQ(skel->bss->classid, getpid(), "classid mismatch");
+out:
+ if (cgroup_fd > 0)
+ close(cgroup_fd);
+ test_cgroup_classid__destroy(skel);
+ cleanup_classid_environment();
+}
+
+static void test_cgroup_get_classid_sysctl(void)
+{
+ struct test_cgroup_classid *skel = NULL;
+ int cgroup_fd = -1;
+
+ cgroup_fd = test__join_cgroup(TEST_CGROUP);
+ if (!ASSERT_GE(cgroup_fd, 0, "join cgroup"))
+ goto out;
+
+ if (!ASSERT_OK(setup_classid_environment(), "setup env"))
+ goto out;
+
+ if (!ASSERT_OK(set_classid(), "set_classid"))
+ goto out;
+
+ skel = test_cgroup_classid__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "load program"))
+ goto out;
+
+ skel->links.sysctl_tcp_mem =
+ bpf_program__attach_cgroup(skel->progs.sysctl_tcp_mem, cgroup_fd);
+ if (!ASSERT_OK_PTR(skel->links.sysctl_tcp_mem, "attach_program"))
+ goto out;
+
+ skel->bss->classid = -1;
+ if (!ASSERT_OK(join_classid(), "join_classid"))
+ goto out;
+
+ SYS_NOFAIL("cat /proc/sys/net/ipv4/tcp_mem");
+ ASSERT_EQ(skel->bss->classid, getpid(), "classid mismatch");
+out:
+ if (cgroup_fd > 0)
+ close(cgroup_fd);
+ test_cgroup_classid__destroy(skel);
+ cleanup_classid_environment();
+}
+
+static void test_cgroup_get_classid_sockopt(void)
+{
+ struct test_cgroup_classid *skel = NULL;
+ int cgroup_fd = -1, fd = -1, val, err;
+ socklen_t val_len;
+
+ cgroup_fd = test__join_cgroup(TEST_CGROUP);
+ if (!ASSERT_GE(cgroup_fd, 0, "join cgroup"))
+ goto out;
+
+ if (!ASSERT_OK(setup_classid_environment(), "setup env"))
+ goto out;
+
+ if (!ASSERT_OK(set_classid(), "set_classid"))
+ goto out;
+
+ skel = test_cgroup_classid__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "load program"))
+ goto out;
+
+ skel->links.cg_getsockopt =
+ bpf_program__attach_cgroup(skel->progs.cg_getsockopt, cgroup_fd);
+ if (!ASSERT_OK_PTR(skel->links.cg_getsockopt, "attach_program"))
+ goto out;
+
+ skel->bss->classid = -1;
+ if (!ASSERT_OK(join_classid(), "join_classid"))
+ goto out;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (!ASSERT_OK_FD(fd, "socket"))
+ goto out;
+
+ val_len = sizeof(val);
+ err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &val_len);
+ if (!ASSERT_OK(err, "getsockopt"))
+ goto out;
+
+ ASSERT_EQ(skel->bss->classid, getpid(), "classid mismatch");
+out:
+ if (fd > 0)
+ close(fd);
+ if (cgroup_fd > 0)
+ close(cgroup_fd);
+ test_cgroup_classid__destroy(skel);
+ cleanup_classid_environment();
+}
+
+void test_cgroup_get_classid(void)
+{
+ if (test__start_subtest("get classid from tc"))
+ test_cgroup_get_classid_tc();
+ if (test__start_subtest("get classid from sysctl"))
+ test_cgroup_get_classid_sysctl();
+ if (test__start_subtest("get classid from cgroup dev"))
+ test_cgroup_get_classid_cgroup_dev();
+ if (test__start_subtest("get classid from cgroup sockopt"))
+ test_cgroup_get_classid_sockopt();
+}
diff --git a/tools/testing/selftests/bpf/progs/test_cgroup_classid.c b/tools/testing/selftests/bpf/progs/test_cgroup_classid.c
new file mode 100644
index 000000000000..7a555ba6bb17
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_cgroup_classid.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <sys/socket.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+int classid;
+
+SEC("tc/egress")
+int tc_egress(struct __sk_buff *skb)
+{
+ /* expecte real classid */
+ classid = bpf_get_cgroup_classid(skb);
+ return TCX_PASS;
+}
+
+SEC("tc/ingress")
+int tc_ingress(struct __sk_buff *skb)
+{
+ /* expecte 0 */
+ classid = bpf_get_cgroup_classid(skb);
+ return TCX_PASS;
+}
+
+SEC("cgroup/dev")
+int cg_dev(struct bpf_cgroup_dev_ctx *ctx)
+{
+ /* expecte real classid */
+ classid = bpf_get_cgroup_classid((struct __sk_buff *)ctx);
+ /* Allow all */
+ return 1;
+}
+
+SEC("cgroup/sysctl")
+int sysctl_tcp_mem(struct bpf_sysctl *ctx)
+{
+ /* expecte real classid */
+ classid = bpf_get_cgroup_classid((struct __sk_buff *)ctx);
+ return 1;
+}
+
+SEC("cgroup/getsockopt")
+int cg_getsockopt(struct bpf_sockopt *ctx)
+{
+ /* expecte real classid */
+ classid = bpf_get_cgroup_classid((struct __sk_buff *)ctx);
+ return 1;
+}
+
+char _license[] SEC("license") = "GPL";
--
2.47.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH bpf-next v1 1/2] bpf: Restrict usage scope of bpf_get_cgroup_classid
2025-05-28 16:16 [PATCH bpf-next v1 1/2] bpf: Restrict usage scope of bpf_get_cgroup_classid Jiayuan Chen
2025-05-28 16:16 ` [PATCH bpf-next v1 2/2] bpf/selftests: Add test cases for retrieving classid Jiayuan Chen
@ 2025-05-29 16:46 ` Alexei Starovoitov
1 sibling, 0 replies; 3+ messages in thread
From: Alexei Starovoitov @ 2025-05-29 16:46 UTC (permalink / raw)
To: Jiayuan Chen
Cc: bpf, syzbot+9767c7ed68b95cfa69e6, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa, Mykola Lysenko,
Shuah Khan, Feng Yang, Tejun Heo, LKML,
open list:KERNEL SELFTEST FRAMEWORK
On Wed, May 28, 2025 at 9:17 AM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
> A previous commit expanded the usage scope of bpf_get_cgroup_classid() to
> all contexts (see Fixes tag), but this was inappropriate.
>
> First, syzkaller reported a bug [1].
> Second, it uses skb as an argument, but its implementation varies across
> different bpf prog types. For example, in sock_filter and sock_addr, it
> retrieves the classid from the current context
> (bpf_get_cgroup_classid_curr_proto) instead of from skb. In tc egress and
> lwt, it fetches the classid from skb->sk, but in tc ingress, it returns 0.
>
> In summary, the definition of bpf_get_cgroup_classid() is ambiguous and
> its usage scenarios are limited. It should not be treated as a
> general-purpose helper. This patch reverts part of the previous commit.
I think it's better to make it generic enough instead
of reintroducing a bunch of prog specific proto handlers.
See this discussion:
https://lore.kernel.org/bpf/20250528020755.33182-1-yangfeng59949@163.com/
pw-bot: cr
^ permalink raw reply [flat|nested] 3+ messages in thread