public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc
@ 2024-11-19 17:49 Juntong Deng
  2024-11-19 17:53 ` [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs Juntong Deng
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 17:49 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

This patch series adds open-coded style process file iterator
bpf_iter_task_file and bpf_fget_task() kfunc, and corresponding
selftests test cases.

In addition, since fs kfuncs is generic and useful for scenarios
other than LSM, this patch makes fs kfuncs available for SYSCALL
and TRACING program types [0].

[0]: https://lore.kernel.org/bpf/CAPhsuW6ud21v2xz8iSXf=CiDL+R_zpQ+p8isSTMTw=EiJQtRSw@mail.gmail.com/

Known future merge conflict: In linux-next task_lookup_next_fdget_rcu()
has been removed and replaced with fget_task_next() [1], but that has
not happened yet in bpf-next, so I still
use task_lookup_next_fdget_rcu() in bpf_iter_task_file_next().

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=8fd3395ec9051a52828fcca2328cb50a69dea8ef

Although iter/task_file already exists, for CRIB we still need the
open-coded iterator style process file iterator, and the same is true
for other bpf iterators such as iter/tcp, iter/udp, etc.

The traditional bpf iterator is more like a bpf version of procfs, but
similar to procfs, it is not suitable for CRIB scenarios that need to
obtain large amounts of complex, multi-level in-kernel information.

The following is from previous discussions [2].

[2]: https://lore.kernel.org/bpf/AM6PR03MB5848CA34B5B68C90F210285E99B12@AM6PR03MB5848.eurprd03.prod.outlook.com/

This is because the context of bpf iterators is fixed and bpf iterators
cannot be nested. This means that a bpf iterator program can only
complete a specific small iterative dump task, and cannot dump
multi-level data.

An example, when we need to dump all the sockets of a process, we need
to iterate over all the files (sockets) of the process, and iterate over
the all packets in the queue of each socket, and iterate over all data
in each packet.

If we use bpf iterator, since the iterator can not be nested, we need to
use socket iterator program to get all the basic information of all
sockets (pass pid as filter), and then use packet iterator program to
get the basic information of all packets of a specific socket (pass pid,
fd as filter), and then use packet data iterator program to get all the
data of a specific packet (pass pid, fd, packet index as filter).

This would be complicated and require a lot of (each iteration)
bpf program startup and exit (leading to poor performance).

By comparison, open coded iterator is much more flexible, we can iterate
in any context, at any time, and iteration can be nested, so we can
achieve more flexible and more elegant dumping through open coded
iterators.

With open coded iterators, all of the above can be done in a single
bpf program, and with nested iterators, everything becomes compact
and simple.

Also, bpf iterators transmit data to user space through seq_file,
which involves a lot of open (bpf_iter_create), read, close syscalls,
context switching, memory copying, and cannot achieve the performance
of using ringbuf.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
v3 -> v4:
* Make all kfuncs generic, not CRIB specific.

* Move bpf_fget_task to fs/bpf_fs_kfuncs.c.

* Remove bpf_iter_task_file_get_fd and bpf_get_file_ops_type.

* Use struct bpf_iter_task_file_item * as the return value of
  bpf_iter_task_file_next.

* Change fd to unsigned int type and add next_fd.

* Add KF_RCU_PROTECTED to bpf_iter_task_file_new.

* Make fs kfuncs available to SYSCALL and TRACING program types.

* Update all relevant test cases.

* Remove the discussion section from cover letter.

v2 -> v3:
* Move task_file open-coded iterator to kernel/bpf/helpers.c.

* Fix duplicate error code 7 in test_bpf_iter_task_file().

* Add comment for case when bpf_iter_task_file_get_fd() returns -1.

* Add future plans in commit message of "Add struct file related
  CRIB kfuncs".

* Add Discussion section to cover letter.

v1 -> v2:
* Fix a type definition error in the fd parameter of
  bpf_fget_task() at crib_common.h.

Juntong Deng (5):
  bpf: Introduce task_file open-coded iterator kfuncs
  selftests/bpf: Add tests for open-coded style process file iterator
  bpf: Add bpf_fget_task() kfunc
  bpf: Make fs kfuncs available for SYSCALL and TRACING program types
  selftests/bpf: Add tests for bpf_fget_task() kfunc

 fs/bpf_fs_kfuncs.c                            |  42 ++++---
 kernel/bpf/helpers.c                          |   3 +
 kernel/bpf/task_iter.c                        |  92 ++++++++++++++
 .../testing/selftests/bpf/bpf_experimental.h  |  15 +++
 .../selftests/bpf/prog_tests/fs_kfuncs.c      |  46 +++++++
 .../testing/selftests/bpf/prog_tests/iters.c  | 105 ++++++++++++++++
 .../selftests/bpf/progs/fs_kfuncs_failure.c   |  33 +++++
 .../selftests/bpf/progs/iters_task_file.c     |  71 +++++++++++
 .../bpf/progs/iters_task_file_failure.c       | 114 ++++++++++++++++++
 .../selftests/bpf/progs/test_fget_task.c      |  49 ++++++++
 10 files changed, 554 insertions(+), 16 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/fs_kfuncs_failure.c
 create mode 100644 tools/testing/selftests/bpf/progs/iters_task_file.c
 create mode 100644 tools/testing/selftests/bpf/progs/iters_task_file_failure.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_fget_task.c

-- 
2.39.5


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

* [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs
  2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
@ 2024-11-19 17:53 ` Juntong Deng
  2024-11-20 10:55   ` Jiri Olsa
  2024-11-19 17:53 ` [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator Juntong Deng
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 17:53 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

This patch adds the open-coded iterator style process file iterator
kfuncs bpf_iter_task_file_{new,next,destroy} that iterates over all
files opened by the specified process.

bpf_iter_task_file_next returns a pointer to bpf_iter_task_file_item,
which currently contains *task, *file, fd. This is an extensible
structure that enables compatibility with different versions
through CO-RE.

The reference to struct file acquired by the previous
bpf_iter_task_file_next() is released in the next
bpf_iter_task_file_next(), and the last reference is released in the
last bpf_iter_task_file_next() that returns NULL.

In the bpf_iter_task_file_destroy(), if the iterator does not iterate to
the end, then the last struct file reference is released at this time.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 kernel/bpf/helpers.c   |  3 ++
 kernel/bpf/task_iter.c | 92 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 751c150f9e1c..ed99d2bfd425 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -3130,6 +3130,9 @@ BTF_ID_FLAGS(func, bpf_iter_css_destroy, KF_ITER_DESTROY)
 BTF_ID_FLAGS(func, bpf_iter_task_new, KF_ITER_NEW | KF_TRUSTED_ARGS | KF_RCU_PROTECTED)
 BTF_ID_FLAGS(func, bpf_iter_task_next, KF_ITER_NEXT | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_iter_task_destroy, KF_ITER_DESTROY)
+BTF_ID_FLAGS(func, bpf_iter_task_file_new, KF_ITER_NEW | KF_TRUSTED_ARGS | KF_RCU_PROTECTED)
+BTF_ID_FLAGS(func, bpf_iter_task_file_next, KF_ITER_NEXT | KF_RET_NULL)
+BTF_ID_FLAGS(func, bpf_iter_task_file_destroy, KF_ITER_DESTROY)
 BTF_ID_FLAGS(func, bpf_dynptr_adjust)
 BTF_ID_FLAGS(func, bpf_dynptr_is_null)
 BTF_ID_FLAGS(func, bpf_dynptr_is_rdonly)
diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c
index 5af9e130e500..7a3d8c9c3480 100644
--- a/kernel/bpf/task_iter.c
+++ b/kernel/bpf/task_iter.c
@@ -1031,6 +1031,98 @@ __bpf_kfunc void bpf_iter_task_destroy(struct bpf_iter_task *it)
 {
 }
 
+struct bpf_iter_task_file_item {
+	struct task_struct *task;
+	struct file *file;
+	unsigned int fd;
+} __aligned(8);
+
+struct bpf_iter_task_file {
+	__u64 __opaque[4];
+} __aligned(8);
+
+struct bpf_iter_task_file_kern {
+	struct bpf_iter_task_file_item item;
+	unsigned int next_fd;
+} __aligned(8);
+
+/**
+ * bpf_iter_task_file_new() - Initialize a new task file iterator for a task,
+ * used to iterate over all files opened by a specified task
+ *
+ * Note that task file iterator requires to be used within RCU CS.
+ *
+ * @it: the new bpf_iter_task_file to be created
+ * @task: a pointer pointing to a task to be iterated over
+ */
+__bpf_kfunc int bpf_iter_task_file_new(struct bpf_iter_task_file *it,
+		struct task_struct *task)
+{
+	struct bpf_iter_task_file_kern *kit = (void *)it;
+	struct bpf_iter_task_file_item *item = &kit->item;
+
+	BUILD_BUG_ON(sizeof(struct bpf_iter_task_file_kern) > sizeof(struct bpf_iter_task_file));
+	BUILD_BUG_ON(__alignof__(struct bpf_iter_task_file_kern) !=
+		     __alignof__(struct bpf_iter_task_file));
+
+	item->task = task;
+	item->file = NULL;
+	item->fd = 0;
+	kit->next_fd = 0;
+
+	return 0;
+}
+
+/**
+ * bpf_iter_task_file_next() - Get the next file in bpf_iter_task_file
+ *
+ * bpf_iter_task_file_next acquires a reference to the struct file.
+ *
+ * The reference to struct file acquired by the previous
+ * bpf_iter_task_file_next() is released in the next bpf_iter_task_file_next(),
+ * and the last reference is released in the last bpf_iter_task_file_next()
+ * that returns NULL.
+ *
+ * @it: the bpf_iter_task_file to be checked
+ *
+ * @returns a pointer to bpf_iter_task_file_item
+ */
+__bpf_kfunc struct bpf_iter_task_file_item *bpf_iter_task_file_next(struct bpf_iter_task_file *it)
+{
+	struct bpf_iter_task_file_kern *kit = (void *)it;
+	struct bpf_iter_task_file_item *item = &kit->item;
+
+	if (item->file)
+		fput(item->file);
+
+	item->file = task_lookup_next_fdget_rcu(item->task, &kit->next_fd);
+	item->fd = kit->next_fd;
+
+	kit->next_fd++;
+
+	if (!item->file)
+		return NULL;
+
+	return item;
+}
+
+/**
+ * bpf_iter_task_file_destroy() - Destroy a bpf_iter_task_file
+ *
+ * If the iterator does not iterate to the end, then the last
+ * struct file reference is released at this time.
+ *
+ * @it: the bpf_iter_task_file to be destroyed
+ */
+__bpf_kfunc void bpf_iter_task_file_destroy(struct bpf_iter_task_file *it)
+{
+	struct bpf_iter_task_file_kern *kit = (void *)it;
+	struct bpf_iter_task_file_item *item = &kit->item;
+
+	if (item->file)
+		fput(item->file);
+}
+
 __bpf_kfunc_end_defs();
 
 DEFINE_PER_CPU(struct mmap_unlock_irq_work, mmap_unlock_work);
-- 
2.39.5


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

* [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator
  2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
  2024-11-19 17:53 ` [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs Juntong Deng
@ 2024-11-19 17:53 ` Juntong Deng
  2024-11-20 11:27   ` Jiri Olsa
  2024-11-19 17:54 ` [PATCH bpf-next v4 3/5] bpf: Add bpf_fget_task() kfunc Juntong Deng
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 17:53 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

This patch adds test cases for open-coded style process file iterator.

Test cases related to process files are run in the newly created child
process. Close all opened files inherited from the parent process in
the child process to avoid the files opened by the parent process
affecting the test results.

In addition, this patch adds failure test cases where bpf programs
cannot pass the verifier due to uninitialized or untrusted
arguments, or not in RCU CS, etc.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 .../testing/selftests/bpf/bpf_experimental.h  |   7 ++
 .../testing/selftests/bpf/prog_tests/iters.c  | 105 ++++++++++++++++
 .../selftests/bpf/progs/iters_task_file.c     |  71 +++++++++++
 .../bpf/progs/iters_task_file_failure.c       | 114 ++++++++++++++++++
 4 files changed, 297 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/iters_task_file.c
 create mode 100644 tools/testing/selftests/bpf/progs/iters_task_file_failure.c

diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
index cd8ecd39c3f3..ce1520c56b55 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -588,4 +588,11 @@ extern int bpf_iter_kmem_cache_new(struct bpf_iter_kmem_cache *it) __weak __ksym
 extern struct kmem_cache *bpf_iter_kmem_cache_next(struct bpf_iter_kmem_cache *it) __weak __ksym;
 extern void bpf_iter_kmem_cache_destroy(struct bpf_iter_kmem_cache *it) __weak __ksym;
 
+struct bpf_iter_task_file;
+struct bpf_iter_task_file_item;
+extern int bpf_iter_task_file_new(struct bpf_iter_task_file *it, struct task_struct *task) __ksym;
+extern struct bpf_iter_task_file_item *
+bpf_iter_task_file_next(struct bpf_iter_task_file *it) __ksym;
+extern void bpf_iter_task_file_destroy(struct bpf_iter_task_file *it) __ksym;
+
 #endif
diff --git a/tools/testing/selftests/bpf/prog_tests/iters.c b/tools/testing/selftests/bpf/prog_tests/iters.c
index 3cea71f9c500..4944810e9b2f 100644
--- a/tools/testing/selftests/bpf/prog_tests/iters.c
+++ b/tools/testing/selftests/bpf/prog_tests/iters.c
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
 
+#define _GNU_SOURCE
+#include <sys/socket.h>
 #include <sys/syscall.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
@@ -16,11 +18,13 @@
 #include "iters_num.skel.h"
 #include "iters_testmod.skel.h"
 #include "iters_testmod_seq.skel.h"
+#include "iters_task_file.skel.h"
 #include "iters_task_vma.skel.h"
 #include "iters_task.skel.h"
 #include "iters_css_task.skel.h"
 #include "iters_css.skel.h"
 #include "iters_task_failure.skel.h"
+#include "iters_task_file_failure.skel.h"
 
 static void subtest_num_iters(void)
 {
@@ -291,6 +295,104 @@ static void subtest_css_iters(void)
 	iters_css__destroy(skel);
 }
 
+struct files_test_args {
+	bool *setup_end;
+	bool *test_end;
+};
+
+static int task_file_test_process(void *args)
+{
+	struct files_test_args *test_args = (struct files_test_args *)args;
+	int pipefd[2], sockfd, err = 0;
+
+	/* Create a clean file descriptor table for the test process */
+	close_range(0, ~0U, 0);
+
+	if (pipe(pipefd) < 0)
+		return 1;
+
+	sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	if (sockfd < 0) {
+		err = 2;
+		goto cleanup_pipe;
+	}
+
+	*test_args->setup_end = true;
+
+	while (!*test_args->test_end)
+		;
+
+	close(sockfd);
+cleanup_pipe:
+	close(pipefd[0]);
+	close(pipefd[1]);
+	return err;
+}
+
+static void subtest_task_file_iters(void)
+{
+	int prog_fd, child_pid, wstatus, err = 0;
+	const int stack_size = 1024 * 1024;
+	struct iters_task_file *skel;
+	struct files_test_args args;
+	struct bpf_program *prog;
+	bool setup_end, test_end;
+	char *stack;
+
+	skel = iters_task_file__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "open_and_load"))
+		return;
+
+	if (!ASSERT_OK(skel->bss->err, "pre_test_err"))
+		goto cleanup_skel;
+
+	prog = bpf_object__find_program_by_name(skel->obj, "test_bpf_iter_task_file");
+	if (!ASSERT_OK_PTR(prog, "find_program_by_name"))
+		goto cleanup_skel;
+
+	prog_fd = bpf_program__fd(prog);
+	if (!ASSERT_GT(prog_fd, -1, "bpf_program__fd"))
+		goto cleanup_skel;
+
+	stack = (char *)malloc(stack_size);
+	if (!ASSERT_OK_PTR(stack, "clone_stack"))
+		goto cleanup_skel;
+
+	setup_end = false;
+	test_end = false;
+
+	args.setup_end = &setup_end;
+	args.test_end = &test_end;
+
+	/* Note that there is no CLONE_FILES */
+	child_pid = clone(task_file_test_process, stack + stack_size, CLONE_VM | SIGCHLD, &args);
+	if (!ASSERT_GT(child_pid, -1, "child_pid"))
+		goto cleanup_stack;
+
+	while (!setup_end)
+		;
+
+	skel->bss->pid = child_pid;
+
+	err = bpf_prog_test_run_opts(prog_fd, NULL);
+	if (!ASSERT_OK(err, "prog_test_run"))
+		goto cleanup_stack;
+
+	test_end = true;
+
+	if (!ASSERT_GT(waitpid(child_pid, &wstatus, 0), -1, "waitpid"))
+		goto cleanup_stack;
+
+	if (!ASSERT_OK(WEXITSTATUS(wstatus), "run_task_file_iters_test_err"))
+		goto cleanup_stack;
+
+	ASSERT_OK(skel->bss->err, "run_task_file_iters_test_failure");
+cleanup_stack:
+	free(stack);
+cleanup_skel:
+	iters_task_file__destroy(skel);
+}
+
 void test_iters(void)
 {
 	RUN_TESTS(iters_state_safety);
@@ -315,5 +417,8 @@ void test_iters(void)
 		subtest_css_task_iters();
 	if (test__start_subtest("css"))
 		subtest_css_iters();
+	if (test__start_subtest("task_file"))
+		subtest_task_file_iters();
 	RUN_TESTS(iters_task_failure);
+	RUN_TESTS(iters_task_file_failure);
 }
diff --git a/tools/testing/selftests/bpf/progs/iters_task_file.c b/tools/testing/selftests/bpf/progs/iters_task_file.c
new file mode 100644
index 000000000000..f14b473936c7
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/iters_task_file.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+#include "task_kfunc_common.h"
+
+char _license[] SEC("license") = "GPL";
+
+int err, pid;
+
+SEC("syscall")
+int test_bpf_iter_task_file(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+	struct bpf_iter_task_file_item *item;
+	struct task_struct *task;
+
+	task = bpf_task_from_vpid(pid);
+	if (task == NULL) {
+		err = 1;
+		return 0;
+	}
+
+	bpf_rcu_read_lock();
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	item = bpf_iter_task_file_next(&task_file_it);
+	if (item == NULL) {
+		err = 2;
+		goto cleanup;
+	}
+
+	if (item->fd != 0) {
+		err = 3;
+		goto cleanup;
+	}
+
+	item = bpf_iter_task_file_next(&task_file_it);
+	if (item == NULL) {
+		err = 4;
+		goto cleanup;
+	}
+
+	if (item->fd != 1) {
+		err = 5;
+		goto cleanup;
+	}
+
+	item = bpf_iter_task_file_next(&task_file_it);
+	if (item == NULL) {
+		err = 6;
+		goto cleanup;
+	}
+
+	if (item->fd != 2) {
+		err = 7;
+		goto cleanup;
+	}
+
+	item = bpf_iter_task_file_next(&task_file_it);
+	if (item != NULL)
+		err = 8;
+cleanup:
+	bpf_iter_task_file_destroy(&task_file_it);
+	bpf_rcu_read_unlock();
+	bpf_task_release(task);
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/iters_task_file_failure.c b/tools/testing/selftests/bpf/progs/iters_task_file_failure.c
new file mode 100644
index 000000000000..c3de9235b888
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/iters_task_file_failure.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+#include "task_kfunc_common.h"
+
+char _license[] SEC("license") = "GPL";
+
+SEC("syscall")
+__failure __msg("expected an RCU CS when using bpf_iter_task_file")
+int bpf_iter_task_file_new_without_rcu_lock(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+	struct task_struct *task;
+
+	task = bpf_get_current_task_btf();
+
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	bpf_iter_task_file_destroy(&task_file_it);
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("expected uninitialized iter_task_file as arg #1")
+int bpf_iter_task_file_new_inited_iter(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+	struct task_struct *task;
+
+	task = bpf_get_current_task_btf();
+
+	bpf_rcu_read_lock();
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	bpf_iter_task_file_destroy(&task_file_it);
+	bpf_rcu_read_unlock();
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("Possibly NULL pointer passed to trusted arg1")
+int bpf_iter_task_file_new_null_task(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+	struct task_struct *task = NULL;
+
+	bpf_rcu_read_lock();
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	bpf_iter_task_file_destroy(&task_file_it);
+	bpf_rcu_read_unlock();
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("R2 must be referenced or trusted")
+int bpf_iter_task_file_new_untrusted_task(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+	struct task_struct *task;
+
+	task = bpf_get_current_task_btf()->parent;
+
+	bpf_rcu_read_lock();
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	bpf_iter_task_file_destroy(&task_file_it);
+	bpf_rcu_read_unlock();
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("Unreleased reference")
+int bpf_iter_task_file_no_destory(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+	struct task_struct *task;
+
+	task = bpf_get_current_task_btf();
+
+	bpf_rcu_read_lock();
+	bpf_iter_task_file_new(&task_file_it, task);
+
+	bpf_rcu_read_unlock();
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("expected an initialized iter_task_file as arg #1")
+int bpf_iter_task_file_next_uninit_iter(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+
+	bpf_iter_task_file_next(&task_file_it);
+
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("expected an initialized iter_task_file as arg #1")
+int bpf_iter_task_file_destroy_uninit_iter(void *ctx)
+{
+	struct bpf_iter_task_file task_file_it;
+
+	bpf_iter_task_file_destroy(&task_file_it);
+
+	return 0;
+}
-- 
2.39.5


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

* [PATCH bpf-next v4 3/5] bpf: Add bpf_fget_task() kfunc
  2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
  2024-11-19 17:53 ` [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs Juntong Deng
  2024-11-19 17:53 ` [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator Juntong Deng
@ 2024-11-19 17:54 ` Juntong Deng
  2024-11-19 17:54 ` [PATCH bpf-next v4 4/5] bpf: Make fs kfuncs available for SYSCALL and TRACING program types Juntong Deng
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 17:54 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

This patch adds bpf_fget_task() kfunc.

bpf_fget_task() is used to get a pointer to the struct file
corresponding to the task file descriptor. Note that this function
acquires a reference to struct file.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 fs/bpf_fs_kfuncs.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
index 3fe9f59ef867..19a9d45c47f9 100644
--- a/fs/bpf_fs_kfuncs.c
+++ b/fs/bpf_fs_kfuncs.c
@@ -152,6 +152,26 @@ __bpf_kfunc int bpf_get_file_xattr(struct file *file, const char *name__str,
 	return bpf_get_dentry_xattr(dentry, name__str, value_p);
 }
 
+/**
+ * bpf_fget_task() - Get a pointer to the struct file corresponding to
+ * the task file descriptor
+ *
+ * Note that this function acquires a reference to struct file.
+ *
+ * @task: the specified struct task_struct
+ * @fd: the file descriptor
+ *
+ * @returns the corresponding struct file pointer if found,
+ * otherwise returns NULL
+ */
+__bpf_kfunc struct file *bpf_fget_task(struct task_struct *task, unsigned int fd)
+{
+	struct file *file;
+
+	file = fget_task(task, fd);
+	return file;
+}
+
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(bpf_fs_kfunc_set_ids)
@@ -161,6 +181,7 @@ BTF_ID_FLAGS(func, bpf_put_file, KF_RELEASE)
 BTF_ID_FLAGS(func, bpf_path_d_path, KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
+BTF_ID_FLAGS(func, bpf_fget_task, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL)
 BTF_KFUNCS_END(bpf_fs_kfunc_set_ids)
 
 static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id)
-- 
2.39.5


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

* [PATCH bpf-next v4 4/5] bpf: Make fs kfuncs available for SYSCALL and TRACING program types
  2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
                   ` (2 preceding siblings ...)
  2024-11-19 17:54 ` [PATCH bpf-next v4 3/5] bpf: Add bpf_fget_task() kfunc Juntong Deng
@ 2024-11-19 17:54 ` Juntong Deng
  2024-11-19 17:54 ` [PATCH bpf-next v4 5/5] selftests/bpf: Add tests for bpf_fget_task() kfunc Juntong Deng
  2024-11-19 18:40 ` [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and " Juntong Deng
  5 siblings, 0 replies; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 17:54 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

Currently fs kfuncs are only available for LSM program type, but fs
kfuncs are generic and useful for scenarios other than LSM.

This patch makes fs kfuncs available for SYSCALL and TRACING
program types.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 fs/bpf_fs_kfuncs.c | 21 +++++----------------
 1 file changed, 5 insertions(+), 16 deletions(-)

diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c
index 19a9d45c47f9..609d6b2af1db 100644
--- a/fs/bpf_fs_kfuncs.c
+++ b/fs/bpf_fs_kfuncs.c
@@ -26,8 +26,6 @@ __bpf_kfunc_start_defs();
  * acquired by this BPF kfunc will result in the BPF program being rejected by
  * the BPF verifier.
  *
- * This BPF kfunc may only be called from BPF LSM programs.
- *
  * Internally, this BPF kfunc leans on get_task_exe_file(), such that calling
  * bpf_get_task_exe_file() would be analogous to calling get_task_exe_file()
  * directly in kernel context.
@@ -49,8 +47,6 @@ __bpf_kfunc struct file *bpf_get_task_exe_file(struct task_struct *task)
  * passed to this BPF kfunc. Attempting to pass an unreferenced file pointer, or
  * any other arbitrary pointer for that matter, will result in the BPF program
  * being rejected by the BPF verifier.
- *
- * This BPF kfunc may only be called from BPF LSM programs.
  */
 __bpf_kfunc void bpf_put_file(struct file *file)
 {
@@ -70,8 +66,6 @@ __bpf_kfunc void bpf_put_file(struct file *file)
  * reference, or else the BPF program will be outright rejected by the BPF
  * verifier.
  *
- * This BPF kfunc may only be called from BPF LSM programs.
- *
  * Return: A positive integer corresponding to the length of the resolved
  * pathname in *buf*, including the NUL termination character. On error, a
  * negative integer is returned.
@@ -184,23 +178,18 @@ BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE | KF_TRUSTED_ARGS)
 BTF_ID_FLAGS(func, bpf_fget_task, KF_ACQUIRE | KF_TRUSTED_ARGS | KF_RET_NULL)
 BTF_KFUNCS_END(bpf_fs_kfunc_set_ids)
 
-static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id)
-{
-	if (!btf_id_set8_contains(&bpf_fs_kfunc_set_ids, kfunc_id) ||
-	    prog->type == BPF_PROG_TYPE_LSM)
-		return 0;
-	return -EACCES;
-}
-
 static const struct btf_kfunc_id_set bpf_fs_kfunc_set = {
 	.owner = THIS_MODULE,
 	.set = &bpf_fs_kfunc_set_ids,
-	.filter = bpf_fs_kfuncs_filter,
 };
 
 static int __init bpf_fs_kfuncs_init(void)
 {
-	return register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fs_kfunc_set);
+	int ret;
+
+	ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_fs_kfunc_set);
+	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_fs_kfunc_set);
+	return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_fs_kfunc_set);
 }
 
 late_initcall(bpf_fs_kfuncs_init);
-- 
2.39.5


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

* [PATCH bpf-next v4 5/5] selftests/bpf: Add tests for bpf_fget_task() kfunc
  2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
                   ` (3 preceding siblings ...)
  2024-11-19 17:54 ` [PATCH bpf-next v4 4/5] bpf: Make fs kfuncs available for SYSCALL and TRACING program types Juntong Deng
@ 2024-11-19 17:54 ` Juntong Deng
  2024-11-19 18:40 ` [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and " Juntong Deng
  5 siblings, 0 replies; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 17:54 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

This patch adds test cases for bpf_fget_task() kfunc.

test_bpf_fget_task is used to test obtaining struct file based on
the file descriptor in the current process.

bpf_fget_task_null_task and bpf_fget_task_untrusted_task are used to
test the failure cases of passing NULL or untrusted pointer as argument.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
---
 .../testing/selftests/bpf/bpf_experimental.h  |  8 +++
 .../selftests/bpf/prog_tests/fs_kfuncs.c      | 46 +++++++++++++++++
 .../selftests/bpf/progs/fs_kfuncs_failure.c   | 33 +++++++++++++
 .../selftests/bpf/progs/test_fget_task.c      | 49 +++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/fs_kfuncs_failure.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_fget_task.c

diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
index ce1520c56b55..e0c9e7d9ba0a 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -221,6 +221,14 @@ extern void bpf_put_file(struct file *file) __ksym;
  */
 extern int bpf_path_d_path(struct path *path, char *buf, size_t buf__sz) __ksym;
 
+/* Description
+ *	Get a pointer to the struct file corresponding to the task file descriptor
+ *	Note that this function acquires a reference to struct file.
+ * Returns
+ *	The corresponding struct file pointer if found, otherwise returns NULL
+ */
+extern struct file *bpf_fget_task(struct task_struct *task, unsigned int fd) __ksym;
+
 /* This macro must be used to mark the exception callback corresponding to the
  * main program. For example:
  *
diff --git a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
index 5a0b51157451..83dfe64aa3fb 100644
--- a/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
+++ b/tools/testing/selftests/bpf/prog_tests/fs_kfuncs.c
@@ -9,6 +9,8 @@
 #include <test_progs.h>
 #include "test_get_xattr.skel.h"
 #include "test_fsverity.skel.h"
+#include "test_fget_task.skel.h"
+#include "fs_kfuncs_failure.skel.h"
 
 static const char testfile[] = "/tmp/test_progs_fs_kfuncs";
 
@@ -139,6 +141,45 @@ static void test_fsverity(void)
 	remove(testfile);
 }
 
+static void test_fget_task(void)
+{
+	int pipefd[2], prog_fd, err = 0;
+	struct test_fget_task *skel;
+	struct bpf_program *prog;
+
+	skel = test_fget_task__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "open_and_load"))
+		return;
+
+	if (!ASSERT_OK(skel->bss->err, "pre_test_err"))
+		goto cleanup_skel;
+
+	prog = bpf_object__find_program_by_name(skel->obj, "test_bpf_fget_task");
+	if (!ASSERT_OK_PTR(prog, "find_program_by_name"))
+		goto cleanup_skel;
+
+	prog_fd = bpf_program__fd(prog);
+	if (!ASSERT_GT(prog_fd, -1, "bpf_program__fd"))
+		goto cleanup_skel;
+
+	if (pipe(pipefd) < 0)
+		goto cleanup_skel;
+
+	skel->bss->test_fd1 = pipefd[0];
+	skel->bss->test_fd2 = pipefd[1];
+
+	err = bpf_prog_test_run_opts(prog_fd, NULL);
+	if (!ASSERT_OK(err, "prog_test_run"))
+		goto cleanup_pipe;
+
+	ASSERT_OK(skel->bss->err, "run_bpf_fget_task_test_failure");
+cleanup_pipe:
+	close(pipefd[0]);
+	close(pipefd[1]);
+cleanup_skel:
+	test_fget_task__destroy(skel);
+}
+
 void test_fs_kfuncs(void)
 {
 	if (test__start_subtest("xattr"))
@@ -146,4 +187,9 @@ void test_fs_kfuncs(void)
 
 	if (test__start_subtest("fsverity"))
 		test_fsverity();
+
+	if (test__start_subtest("fget_task"))
+		test_fget_task();
+
+	RUN_TESTS(fs_kfuncs_failure);
 }
diff --git a/tools/testing/selftests/bpf/progs/fs_kfuncs_failure.c b/tools/testing/selftests/bpf/progs/fs_kfuncs_failure.c
new file mode 100644
index 000000000000..57aa6d2787ac
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/fs_kfuncs_failure.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+char _license[] SEC("license") = "GPL";
+
+SEC("syscall")
+__failure __msg("Possibly NULL pointer passed to trusted arg0")
+int bpf_fget_task_null_task(void *ctx)
+{
+	struct task_struct *task = NULL;
+
+	bpf_fget_task(task, 1);
+
+	return 0;
+}
+
+SEC("syscall")
+__failure __msg("R1 must be referenced or trusted")
+int bpf_fget_task_untrusted_task(void *ctx)
+{
+	struct task_struct *task;
+
+	task = bpf_get_current_task_btf()->parent;
+
+	bpf_fget_task(task, 1);
+
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/test_fget_task.c b/tools/testing/selftests/bpf/progs/test_fget_task.c
new file mode 100644
index 000000000000..ec40360ac1b2
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_fget_task.c
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+#include "task_kfunc_common.h"
+
+char _license[] SEC("license") = "GPL";
+
+int err, test_fd1, test_fd2;
+
+SEC("syscall")
+int test_bpf_fget_task(void *ctx)
+{
+	struct task_struct *task;
+	struct file *file;
+
+	task = bpf_get_current_task_btf();
+	if (task == NULL) {
+		err = 1;
+		return 0;
+	}
+
+	file = bpf_fget_task(task, test_fd1);
+	if (file == NULL) {
+		err = 2;
+		return 0;
+	}
+
+	bpf_put_file(file);
+
+	file = bpf_fget_task(task, test_fd2);
+	if (file == NULL) {
+		err = 3;
+		return 0;
+	}
+
+	bpf_put_file(file);
+
+	file = bpf_fget_task(task, 9999);
+	if (file != NULL) {
+		err = 4;
+		bpf_put_file(file);
+	}
+
+	return 0;
+}
-- 
2.39.5


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

* Re: [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc
  2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
                   ` (4 preceding siblings ...)
  2024-11-19 17:54 ` [PATCH bpf-next v4 5/5] selftests/bpf: Add tests for bpf_fget_task() kfunc Juntong Deng
@ 2024-11-19 18:40 ` Juntong Deng
  2024-11-20  9:12   ` Christian Brauner
  5 siblings, 1 reply; 15+ messages in thread
From: Juntong Deng @ 2024-11-19 18:40 UTC (permalink / raw)
  To: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht,
	brauner
  Cc: bpf, linux-kernel, linux-fsdevel

I noticed that the path_d_path_kfunc_non_lsm test case failed in BPF CI,
I will fix it in the next version.

But before that, I would like to get some feedback. :)

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

* Re: [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc
  2024-11-19 18:40 ` [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and " Juntong Deng
@ 2024-11-20  9:12   ` Christian Brauner
  2024-11-26 22:15     ` Juntong Deng
  0 siblings, 1 reply; 15+ messages in thread
From: Christian Brauner @ 2024-11-20  9:12 UTC (permalink / raw)
  To: Juntong Deng
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht, bpf,
	linux-kernel, linux-fsdevel

On Tue, Nov 19, 2024 at 06:40:12PM +0000, Juntong Deng wrote:
> I noticed that the path_d_path_kfunc_non_lsm test case failed in BPF CI,
> I will fix it in the next version.
> 
> But before that, I would like to get some feedback. :)

Please resend once -rc1 is out and rebased to upstream where - as you
noticed - all fdget_rcu() variants are gone.

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

* Re: [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs
  2024-11-19 17:53 ` [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs Juntong Deng
@ 2024-11-20 10:55   ` Jiri Olsa
  2024-11-20 11:04     ` Jiri Olsa
  0 siblings, 1 reply; 15+ messages in thread
From: Jiri Olsa @ 2024-11-20 10:55 UTC (permalink / raw)
  To: Juntong Deng
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, memxor, snorcht, brauner,
	bpf, linux-kernel, linux-fsdevel

On Tue, Nov 19, 2024 at 05:53:58PM +0000, Juntong Deng wrote:

SNIP

> +/**
> + * bpf_iter_task_file_next() - Get the next file in bpf_iter_task_file
> + *
> + * bpf_iter_task_file_next acquires a reference to the struct file.
> + *
> + * The reference to struct file acquired by the previous
> + * bpf_iter_task_file_next() is released in the next bpf_iter_task_file_next(),
> + * and the last reference is released in the last bpf_iter_task_file_next()
> + * that returns NULL.
> + *
> + * @it: the bpf_iter_task_file to be checked
> + *
> + * @returns a pointer to bpf_iter_task_file_item
> + */
> +__bpf_kfunc struct bpf_iter_task_file_item *bpf_iter_task_file_next(struct bpf_iter_task_file *it)
> +{
> +	struct bpf_iter_task_file_kern *kit = (void *)it;
> +	struct bpf_iter_task_file_item *item = &kit->item;
> +
> +	if (item->file)
> +		fput(item->file);
> +

missing rcu_read_lock ?

jirka

> +	item->file = task_lookup_next_fdget_rcu(item->task, &kit->next_fd);
> +	item->fd = kit->next_fd;
> +
> +	kit->next_fd++;
> +
> +	if (!item->file)
> +		return NULL;
> +
> +	return item;
> +}
> +
> +/**
> + * bpf_iter_task_file_destroy() - Destroy a bpf_iter_task_file
> + *
> + * If the iterator does not iterate to the end, then the last
> + * struct file reference is released at this time.
> + *
> + * @it: the bpf_iter_task_file to be destroyed
> + */
> +__bpf_kfunc void bpf_iter_task_file_destroy(struct bpf_iter_task_file *it)
> +{
> +	struct bpf_iter_task_file_kern *kit = (void *)it;
> +	struct bpf_iter_task_file_item *item = &kit->item;
> +
> +	if (item->file)
> +		fput(item->file);
> +}
> +
>  __bpf_kfunc_end_defs();
>  
>  DEFINE_PER_CPU(struct mmap_unlock_irq_work, mmap_unlock_work);
> -- 
> 2.39.5
> 

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

* Re: [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs
  2024-11-20 10:55   ` Jiri Olsa
@ 2024-11-20 11:04     ` Jiri Olsa
  0 siblings, 0 replies; 15+ messages in thread
From: Jiri Olsa @ 2024-11-20 11:04 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Juntong Deng, ast, daniel, john.fastabend, andrii, martin.lau,
	eddyz87, song, yonghong.song, kpsingh, sdf, haoluo, memxor,
	snorcht, brauner, bpf, linux-kernel, linux-fsdevel

On Wed, Nov 20, 2024 at 11:55:23AM +0100, Jiri Olsa wrote:
> On Tue, Nov 19, 2024 at 05:53:58PM +0000, Juntong Deng wrote:
> 
> SNIP
> 
> > +/**
> > + * bpf_iter_task_file_next() - Get the next file in bpf_iter_task_file
> > + *
> > + * bpf_iter_task_file_next acquires a reference to the struct file.
> > + *
> > + * The reference to struct file acquired by the previous
> > + * bpf_iter_task_file_next() is released in the next bpf_iter_task_file_next(),
> > + * and the last reference is released in the last bpf_iter_task_file_next()
> > + * that returns NULL.
> > + *
> > + * @it: the bpf_iter_task_file to be checked
> > + *
> > + * @returns a pointer to bpf_iter_task_file_item
> > + */
> > +__bpf_kfunc struct bpf_iter_task_file_item *bpf_iter_task_file_next(struct bpf_iter_task_file *it)
> > +{
> > +	struct bpf_iter_task_file_kern *kit = (void *)it;
> > +	struct bpf_iter_task_file_item *item = &kit->item;
> > +
> > +	if (item->file)
> > +		fput(item->file);
> > +
> 
> missing rcu_read_lock ?

nah user needs to take it explicitly, should have read the whole thing first, sry

jirka

> 
> jirka
> 
> > +	item->file = task_lookup_next_fdget_rcu(item->task, &kit->next_fd);
> > +	item->fd = kit->next_fd;
> > +
> > +	kit->next_fd++;
> > +
> > +	if (!item->file)
> > +		return NULL;
> > +
> > +	return item;
> > +}
> > +
> > +/**
> > + * bpf_iter_task_file_destroy() - Destroy a bpf_iter_task_file
> > + *
> > + * If the iterator does not iterate to the end, then the last
> > + * struct file reference is released at this time.
> > + *
> > + * @it: the bpf_iter_task_file to be destroyed
> > + */
> > +__bpf_kfunc void bpf_iter_task_file_destroy(struct bpf_iter_task_file *it)
> > +{
> > +	struct bpf_iter_task_file_kern *kit = (void *)it;
> > +	struct bpf_iter_task_file_item *item = &kit->item;
> > +
> > +	if (item->file)
> > +		fput(item->file);
> > +}
> > +
> >  __bpf_kfunc_end_defs();
> >  
> >  DEFINE_PER_CPU(struct mmap_unlock_irq_work, mmap_unlock_work);
> > -- 
> > 2.39.5
> > 

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

* Re: [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator
  2024-11-19 17:53 ` [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator Juntong Deng
@ 2024-11-20 11:27   ` Jiri Olsa
  2024-11-26 22:24     ` Juntong Deng
  0 siblings, 1 reply; 15+ messages in thread
From: Jiri Olsa @ 2024-11-20 11:27 UTC (permalink / raw)
  To: Juntong Deng
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, memxor, snorcht, brauner,
	bpf, linux-kernel, linux-fsdevel

On Tue, Nov 19, 2024 at 05:53:59PM +0000, Juntong Deng wrote:

SNIP

> +static void subtest_task_file_iters(void)
> +{
> +	int prog_fd, child_pid, wstatus, err = 0;
> +	const int stack_size = 1024 * 1024;
> +	struct iters_task_file *skel;
> +	struct files_test_args args;
> +	struct bpf_program *prog;
> +	bool setup_end, test_end;
> +	char *stack;
> +
> +	skel = iters_task_file__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "open_and_load"))
> +		return;
> +
> +	if (!ASSERT_OK(skel->bss->err, "pre_test_err"))
> +		goto cleanup_skel;
> +
> +	prog = bpf_object__find_program_by_name(skel->obj, "test_bpf_iter_task_file");
> +	if (!ASSERT_OK_PTR(prog, "find_program_by_name"))
> +		goto cleanup_skel;
> +
> +	prog_fd = bpf_program__fd(prog);
> +	if (!ASSERT_GT(prog_fd, -1, "bpf_program__fd"))
> +		goto cleanup_skel;

I don't think you need to check on this once we did iters_task_file__open_and_load 

> +
> +	stack = (char *)malloc(stack_size);
> +	if (!ASSERT_OK_PTR(stack, "clone_stack"))
> +		goto cleanup_skel;
> +
> +	setup_end = false;
> +	test_end = false;
> +
> +	args.setup_end = &setup_end;
> +	args.test_end = &test_end;
> +
> +	/* Note that there is no CLONE_FILES */
> +	child_pid = clone(task_file_test_process, stack + stack_size, CLONE_VM | SIGCHLD, &args);
> +	if (!ASSERT_GT(child_pid, -1, "child_pid"))
> +		goto cleanup_stack;
> +
> +	while (!setup_end)
> +		;

I thin kthe preferred way is to synchronize through pipe,
you can check prog_tests/uprobe_multi_test.c

> +
> +	skel->bss->pid = child_pid;
> +
> +	err = bpf_prog_test_run_opts(prog_fd, NULL);
> +	if (!ASSERT_OK(err, "prog_test_run"))
> +		goto cleanup_stack;
> +
> +	test_end = true;
> +
> +	if (!ASSERT_GT(waitpid(child_pid, &wstatus, 0), -1, "waitpid"))
> +		goto cleanup_stack;
> +
> +	if (!ASSERT_OK(WEXITSTATUS(wstatus), "run_task_file_iters_test_err"))
> +		goto cleanup_stack;
> +
> +	ASSERT_OK(skel->bss->err, "run_task_file_iters_test_failure");

could the test check on that the iterated files were (or contained) the ones we expected?

thanks,
jirka


> +cleanup_stack:
> +	free(stack);
> +cleanup_skel:
> +	iters_task_file__destroy(skel);
> +}
> +
>  void test_iters(void)
>  {
>  	RUN_TESTS(iters_state_safety);
> @@ -315,5 +417,8 @@ void test_iters(void)
>  		subtest_css_task_iters();
>  	if (test__start_subtest("css"))
>  		subtest_css_iters();
> +	if (test__start_subtest("task_file"))
> +		subtest_task_file_iters();
>  	RUN_TESTS(iters_task_failure);
> +	RUN_TESTS(iters_task_file_failure);
>  }
> diff --git a/tools/testing/selftests/bpf/progs/iters_task_file.c b/tools/testing/selftests/bpf/progs/iters_task_file.c
> new file mode 100644
> index 000000000000..f14b473936c7
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/iters_task_file.c
> @@ -0,0 +1,71 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "vmlinux.h"
> +#include <bpf/bpf_tracing.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_misc.h"
> +#include "bpf_experimental.h"
> +#include "task_kfunc_common.h"
> +
> +char _license[] SEC("license") = "GPL";
> +
> +int err, pid;
> +
> +SEC("syscall")
> +int test_bpf_iter_task_file(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +	struct bpf_iter_task_file_item *item;
> +	struct task_struct *task;
> +
> +	task = bpf_task_from_vpid(pid);
> +	if (task == NULL) {
> +		err = 1;
> +		return 0;
> +	}
> +
> +	bpf_rcu_read_lock();
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	item = bpf_iter_task_file_next(&task_file_it);
> +	if (item == NULL) {
> +		err = 2;
> +		goto cleanup;
> +	}
> +
> +	if (item->fd != 0) {
> +		err = 3;
> +		goto cleanup;
> +	}
> +
> +	item = bpf_iter_task_file_next(&task_file_it);
> +	if (item == NULL) {
> +		err = 4;
> +		goto cleanup;
> +	}
> +
> +	if (item->fd != 1) {
> +		err = 5;
> +		goto cleanup;
> +	}
> +
> +	item = bpf_iter_task_file_next(&task_file_it);
> +	if (item == NULL) {
> +		err = 6;
> +		goto cleanup;
> +	}
> +
> +	if (item->fd != 2) {
> +		err = 7;
> +		goto cleanup;
> +	}
> +
> +	item = bpf_iter_task_file_next(&task_file_it);
> +	if (item != NULL)
> +		err = 8;
> +cleanup:
> +	bpf_iter_task_file_destroy(&task_file_it);
> +	bpf_rcu_read_unlock();
> +	bpf_task_release(task);
> +	return 0;
> +}
> diff --git a/tools/testing/selftests/bpf/progs/iters_task_file_failure.c b/tools/testing/selftests/bpf/progs/iters_task_file_failure.c
> new file mode 100644
> index 000000000000..c3de9235b888
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/iters_task_file_failure.c
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include "vmlinux.h"
> +#include <bpf/bpf_tracing.h>
> +#include <bpf/bpf_helpers.h>
> +#include "bpf_misc.h"
> +#include "bpf_experimental.h"
> +#include "task_kfunc_common.h"
> +
> +char _license[] SEC("license") = "GPL";
> +
> +SEC("syscall")
> +__failure __msg("expected an RCU CS when using bpf_iter_task_file")
> +int bpf_iter_task_file_new_without_rcu_lock(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +	struct task_struct *task;
> +
> +	task = bpf_get_current_task_btf();
> +
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	bpf_iter_task_file_destroy(&task_file_it);
> +	return 0;
> +}
> +
> +SEC("syscall")
> +__failure __msg("expected uninitialized iter_task_file as arg #1")
> +int bpf_iter_task_file_new_inited_iter(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +	struct task_struct *task;
> +
> +	task = bpf_get_current_task_btf();
> +
> +	bpf_rcu_read_lock();
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	bpf_iter_task_file_destroy(&task_file_it);
> +	bpf_rcu_read_unlock();
> +	return 0;
> +}
> +
> +SEC("syscall")
> +__failure __msg("Possibly NULL pointer passed to trusted arg1")
> +int bpf_iter_task_file_new_null_task(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +	struct task_struct *task = NULL;
> +
> +	bpf_rcu_read_lock();
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	bpf_iter_task_file_destroy(&task_file_it);
> +	bpf_rcu_read_unlock();
> +	return 0;
> +}
> +
> +SEC("syscall")
> +__failure __msg("R2 must be referenced or trusted")
> +int bpf_iter_task_file_new_untrusted_task(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +	struct task_struct *task;
> +
> +	task = bpf_get_current_task_btf()->parent;
> +
> +	bpf_rcu_read_lock();
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	bpf_iter_task_file_destroy(&task_file_it);
> +	bpf_rcu_read_unlock();
> +	return 0;
> +}
> +
> +SEC("syscall")
> +__failure __msg("Unreleased reference")
> +int bpf_iter_task_file_no_destory(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +	struct task_struct *task;
> +
> +	task = bpf_get_current_task_btf();
> +
> +	bpf_rcu_read_lock();
> +	bpf_iter_task_file_new(&task_file_it, task);
> +
> +	bpf_rcu_read_unlock();
> +	return 0;
> +}
> +
> +SEC("syscall")
> +__failure __msg("expected an initialized iter_task_file as arg #1")
> +int bpf_iter_task_file_next_uninit_iter(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +
> +	bpf_iter_task_file_next(&task_file_it);
> +
> +	return 0;
> +}
> +
> +SEC("syscall")
> +__failure __msg("expected an initialized iter_task_file as arg #1")
> +int bpf_iter_task_file_destroy_uninit_iter(void *ctx)
> +{
> +	struct bpf_iter_task_file task_file_it;
> +
> +	bpf_iter_task_file_destroy(&task_file_it);
> +
> +	return 0;
> +}
> -- 
> 2.39.5
> 

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

* Re: [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc
  2024-11-20  9:12   ` Christian Brauner
@ 2024-11-26 22:15     ` Juntong Deng
  0 siblings, 0 replies; 15+ messages in thread
From: Juntong Deng @ 2024-11-26 22:15 UTC (permalink / raw)
  To: Christian Brauner
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, jolsa, memxor, snorcht, bpf,
	linux-kernel, linux-fsdevel

On 2024/11/20 09:12, Christian Brauner wrote:
> On Tue, Nov 19, 2024 at 06:40:12PM +0000, Juntong Deng wrote:
>> I noticed that the path_d_path_kfunc_non_lsm test case failed in BPF CI,
>> I will fix it in the next version.
>>
>> But before that, I would like to get some feedback. :)
> 
> Please resend once -rc1 is out and rebased to upstream where - as you
> noticed - all fdget_rcu() variants are gone.

Thanks for your reply.

I will rebase in the next version.


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

* Re: [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator
  2024-11-20 11:27   ` Jiri Olsa
@ 2024-11-26 22:24     ` Juntong Deng
  2024-11-27 11:21       ` Jiri Olsa
  0 siblings, 1 reply; 15+ messages in thread
From: Juntong Deng @ 2024-11-26 22:24 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, memxor, snorcht, brauner,
	bpf, linux-kernel, linux-fsdevel

On 2024/11/20 11:27, Jiri Olsa wrote:
> On Tue, Nov 19, 2024 at 05:53:59PM +0000, Juntong Deng wrote:
> 
> SNIP
> 
>> +static void subtest_task_file_iters(void)
>> +{
>> +	int prog_fd, child_pid, wstatus, err = 0;
>> +	const int stack_size = 1024 * 1024;
>> +	struct iters_task_file *skel;
>> +	struct files_test_args args;
>> +	struct bpf_program *prog;
>> +	bool setup_end, test_end;
>> +	char *stack;
>> +
>> +	skel = iters_task_file__open_and_load();
>> +	if (!ASSERT_OK_PTR(skel, "open_and_load"))
>> +		return;
>> +
>> +	if (!ASSERT_OK(skel->bss->err, "pre_test_err"))
>> +		goto cleanup_skel;
>> +
>> +	prog = bpf_object__find_program_by_name(skel->obj, "test_bpf_iter_task_file");
>> +	if (!ASSERT_OK_PTR(prog, "find_program_by_name"))
>> +		goto cleanup_skel;
>> +
>> +	prog_fd = bpf_program__fd(prog);
>> +	if (!ASSERT_GT(prog_fd, -1, "bpf_program__fd"))
>> +		goto cleanup_skel;
> 
> I don't think you need to check on this once we did iters_task_file__open_and_load
> 
>> +
>> +	stack = (char *)malloc(stack_size);
>> +	if (!ASSERT_OK_PTR(stack, "clone_stack"))
>> +		goto cleanup_skel;
>> +
>> +	setup_end = false;
>> +	test_end = false;
>> +
>> +	args.setup_end = &setup_end;
>> +	args.test_end = &test_end;
>> +
>> +	/* Note that there is no CLONE_FILES */
>> +	child_pid = clone(task_file_test_process, stack + stack_size, CLONE_VM | SIGCHLD, &args);
>> +	if (!ASSERT_GT(child_pid, -1, "child_pid"))
>> +		goto cleanup_stack;
>> +
>> +	while (!setup_end)
>> +		;
> 
> I thin kthe preferred way is to synchronize through pipe,
> you can check prog_tests/uprobe_multi_test.c
> 

Thanks for your reply.

Do we really need to use pipe? Currently this test is very simple.

In this test, all files opened by the test process will be closed first
so that there is an empty file description table, and then open the
test files.

This way the test process has only 3 newly opened files and the file
descriptors are always 0, 1, 2.

Although using pipe is feasible, this test will become more complicated
than it is now.

>> +
>> +	skel->bss->pid = child_pid;
>> +
>> +	err = bpf_prog_test_run_opts(prog_fd, NULL);
>> +	if (!ASSERT_OK(err, "prog_test_run"))
>> +		goto cleanup_stack;
>> +
>> +	test_end = true;
>> +
>> +	if (!ASSERT_GT(waitpid(child_pid, &wstatus, 0), -1, "waitpid"))
>> +		goto cleanup_stack;
>> +
>> +	if (!ASSERT_OK(WEXITSTATUS(wstatus), "run_task_file_iters_test_err"))
>> +		goto cleanup_stack;
>> +
>> +	ASSERT_OK(skel->bss->err, "run_task_file_iters_test_failure");
> 
> could the test check on that the iterated files were (or contained) the ones we expected?
> 

Yes, that is the purpose of this test, to check if the iterated process
files exactly match the files opened by the process.

If you mean further checking what exactly the file is, e.g. whether the
file is a pipe or a socket, then I can add that in the next version.

> thanks,
> jirka
> 
> 
>> +cleanup_stack:
>> +	free(stack);
>> +cleanup_skel:
>> +	iters_task_file__destroy(skel);
>> +}
>> +
>>   void test_iters(void)
>>   {
>>   	RUN_TESTS(iters_state_safety);
>> @@ -315,5 +417,8 @@ void test_iters(void)
>>   		subtest_css_task_iters();
>>   	if (test__start_subtest("css"))
>>   		subtest_css_iters();
>> +	if (test__start_subtest("task_file"))
>> +		subtest_task_file_iters();
>>   	RUN_TESTS(iters_task_failure);
>> +	RUN_TESTS(iters_task_file_failure);
>>   }
>> diff --git a/tools/testing/selftests/bpf/progs/iters_task_file.c b/tools/testing/selftests/bpf/progs/iters_task_file.c
>> new file mode 100644
>> index 000000000000..f14b473936c7
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/iters_task_file.c
>> @@ -0,0 +1,71 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include "vmlinux.h"
>> +#include <bpf/bpf_tracing.h>
>> +#include <bpf/bpf_helpers.h>
>> +#include "bpf_misc.h"
>> +#include "bpf_experimental.h"
>> +#include "task_kfunc_common.h"
>> +
>> +char _license[] SEC("license") = "GPL";
>> +
>> +int err, pid;
>> +
>> +SEC("syscall")
>> +int test_bpf_iter_task_file(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +	struct bpf_iter_task_file_item *item;
>> +	struct task_struct *task;
>> +
>> +	task = bpf_task_from_vpid(pid);
>> +	if (task == NULL) {
>> +		err = 1;
>> +		return 0;
>> +	}
>> +
>> +	bpf_rcu_read_lock();
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	item = bpf_iter_task_file_next(&task_file_it);
>> +	if (item == NULL) {
>> +		err = 2;
>> +		goto cleanup;
>> +	}
>> +
>> +	if (item->fd != 0) {
>> +		err = 3;
>> +		goto cleanup;
>> +	}
>> +
>> +	item = bpf_iter_task_file_next(&task_file_it);
>> +	if (item == NULL) {
>> +		err = 4;
>> +		goto cleanup;
>> +	}
>> +
>> +	if (item->fd != 1) {
>> +		err = 5;
>> +		goto cleanup;
>> +	}
>> +
>> +	item = bpf_iter_task_file_next(&task_file_it);
>> +	if (item == NULL) {
>> +		err = 6;
>> +		goto cleanup;
>> +	}
>> +
>> +	if (item->fd != 2) {
>> +		err = 7;
>> +		goto cleanup;
>> +	}
>> +
>> +	item = bpf_iter_task_file_next(&task_file_it);
>> +	if (item != NULL)
>> +		err = 8;
>> +cleanup:
>> +	bpf_iter_task_file_destroy(&task_file_it);
>> +	bpf_rcu_read_unlock();
>> +	bpf_task_release(task);
>> +	return 0;
>> +}
>> diff --git a/tools/testing/selftests/bpf/progs/iters_task_file_failure.c b/tools/testing/selftests/bpf/progs/iters_task_file_failure.c
>> new file mode 100644
>> index 000000000000..c3de9235b888
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/iters_task_file_failure.c
>> @@ -0,0 +1,114 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#include "vmlinux.h"
>> +#include <bpf/bpf_tracing.h>
>> +#include <bpf/bpf_helpers.h>
>> +#include "bpf_misc.h"
>> +#include "bpf_experimental.h"
>> +#include "task_kfunc_common.h"
>> +
>> +char _license[] SEC("license") = "GPL";
>> +
>> +SEC("syscall")
>> +__failure __msg("expected an RCU CS when using bpf_iter_task_file")
>> +int bpf_iter_task_file_new_without_rcu_lock(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +	struct task_struct *task;
>> +
>> +	task = bpf_get_current_task_btf();
>> +
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	bpf_iter_task_file_destroy(&task_file_it);
>> +	return 0;
>> +}
>> +
>> +SEC("syscall")
>> +__failure __msg("expected uninitialized iter_task_file as arg #1")
>> +int bpf_iter_task_file_new_inited_iter(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +	struct task_struct *task;
>> +
>> +	task = bpf_get_current_task_btf();
>> +
>> +	bpf_rcu_read_lock();
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	bpf_iter_task_file_destroy(&task_file_it);
>> +	bpf_rcu_read_unlock();
>> +	return 0;
>> +}
>> +
>> +SEC("syscall")
>> +__failure __msg("Possibly NULL pointer passed to trusted arg1")
>> +int bpf_iter_task_file_new_null_task(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +	struct task_struct *task = NULL;
>> +
>> +	bpf_rcu_read_lock();
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	bpf_iter_task_file_destroy(&task_file_it);
>> +	bpf_rcu_read_unlock();
>> +	return 0;
>> +}
>> +
>> +SEC("syscall")
>> +__failure __msg("R2 must be referenced or trusted")
>> +int bpf_iter_task_file_new_untrusted_task(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +	struct task_struct *task;
>> +
>> +	task = bpf_get_current_task_btf()->parent;
>> +
>> +	bpf_rcu_read_lock();
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	bpf_iter_task_file_destroy(&task_file_it);
>> +	bpf_rcu_read_unlock();
>> +	return 0;
>> +}
>> +
>> +SEC("syscall")
>> +__failure __msg("Unreleased reference")
>> +int bpf_iter_task_file_no_destory(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +	struct task_struct *task;
>> +
>> +	task = bpf_get_current_task_btf();
>> +
>> +	bpf_rcu_read_lock();
>> +	bpf_iter_task_file_new(&task_file_it, task);
>> +
>> +	bpf_rcu_read_unlock();
>> +	return 0;
>> +}
>> +
>> +SEC("syscall")
>> +__failure __msg("expected an initialized iter_task_file as arg #1")
>> +int bpf_iter_task_file_next_uninit_iter(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +
>> +	bpf_iter_task_file_next(&task_file_it);
>> +
>> +	return 0;
>> +}
>> +
>> +SEC("syscall")
>> +__failure __msg("expected an initialized iter_task_file as arg #1")
>> +int bpf_iter_task_file_destroy_uninit_iter(void *ctx)
>> +{
>> +	struct bpf_iter_task_file task_file_it;
>> +
>> +	bpf_iter_task_file_destroy(&task_file_it);
>> +
>> +	return 0;
>> +}
>> -- 
>> 2.39.5
>>


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

* Re: [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator
  2024-11-26 22:24     ` Juntong Deng
@ 2024-11-27 11:21       ` Jiri Olsa
  2024-12-10 14:17         ` Juntong Deng
  0 siblings, 1 reply; 15+ messages in thread
From: Jiri Olsa @ 2024-11-27 11:21 UTC (permalink / raw)
  To: Juntong Deng
  Cc: Jiri Olsa, ast, daniel, john.fastabend, andrii, martin.lau,
	eddyz87, song, yonghong.song, kpsingh, sdf, haoluo, memxor,
	snorcht, brauner, bpf, linux-kernel, linux-fsdevel

On Tue, Nov 26, 2024 at 10:24:07PM +0000, Juntong Deng wrote:
> On 2024/11/20 11:27, Jiri Olsa wrote:
> > On Tue, Nov 19, 2024 at 05:53:59PM +0000, Juntong Deng wrote:
> > 
> > SNIP
> > 
> > > +static void subtest_task_file_iters(void)
> > > +{
> > > +	int prog_fd, child_pid, wstatus, err = 0;
> > > +	const int stack_size = 1024 * 1024;
> > > +	struct iters_task_file *skel;
> > > +	struct files_test_args args;
> > > +	struct bpf_program *prog;
> > > +	bool setup_end, test_end;
> > > +	char *stack;
> > > +
> > > +	skel = iters_task_file__open_and_load();
> > > +	if (!ASSERT_OK_PTR(skel, "open_and_load"))
> > > +		return;
> > > +
> > > +	if (!ASSERT_OK(skel->bss->err, "pre_test_err"))
> > > +		goto cleanup_skel;
> > > +
> > > +	prog = bpf_object__find_program_by_name(skel->obj, "test_bpf_iter_task_file");
> > > +	if (!ASSERT_OK_PTR(prog, "find_program_by_name"))
> > > +		goto cleanup_skel;
> > > +
> > > +	prog_fd = bpf_program__fd(prog);
> > > +	if (!ASSERT_GT(prog_fd, -1, "bpf_program__fd"))
> > > +		goto cleanup_skel;
> > 
> > I don't think you need to check on this once we did iters_task_file__open_and_load
> > 
> > > +
> > > +	stack = (char *)malloc(stack_size);
> > > +	if (!ASSERT_OK_PTR(stack, "clone_stack"))
> > > +		goto cleanup_skel;
> > > +
> > > +	setup_end = false;
> > > +	test_end = false;
> > > +
> > > +	args.setup_end = &setup_end;
> > > +	args.test_end = &test_end;
> > > +
> > > +	/* Note that there is no CLONE_FILES */
> > > +	child_pid = clone(task_file_test_process, stack + stack_size, CLONE_VM | SIGCHLD, &args);
> > > +	if (!ASSERT_GT(child_pid, -1, "child_pid"))
> > > +		goto cleanup_stack;
> > > +
> > > +	while (!setup_end)
> > > +		;
> > 
> > I thin kthe preferred way is to synchronize through pipe,
> > you can check prog_tests/uprobe_multi_test.c
> > 
> 
> Thanks for your reply.
> 
> Do we really need to use pipe? Currently this test is very simple.
> 
> In this test, all files opened by the test process will be closed first
> so that there is an empty file description table, and then open the
> test files.
> 
> This way the test process has only 3 newly opened files and the file
> descriptors are always 0, 1, 2.
> 
> Although using pipe is feasible, this test will become more complicated
> than it is now.

I see, I missed the close_range call.. anyway I'd still prefer pipe to busy waiting

perhaps you could use fentry probe triggered by the task_file_test_process
and do the fd/file iteration in there? that way there'be no need for the sync

jirka

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

* Re: [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator
  2024-11-27 11:21       ` Jiri Olsa
@ 2024-12-10 14:17         ` Juntong Deng
  0 siblings, 0 replies; 15+ messages in thread
From: Juntong Deng @ 2024-12-10 14:17 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: ast, daniel, john.fastabend, andrii, martin.lau, eddyz87, song,
	yonghong.song, kpsingh, sdf, haoluo, memxor, snorcht, brauner,
	bpf, linux-kernel, linux-fsdevel

On 2024/11/27 11:21, Jiri Olsa wrote:
> On Tue, Nov 26, 2024 at 10:24:07PM +0000, Juntong Deng wrote:
>> On 2024/11/20 11:27, Jiri Olsa wrote:
>>> On Tue, Nov 19, 2024 at 05:53:59PM +0000, Juntong Deng wrote:
>>>
>>> SNIP
>>>
>>>> +static void subtest_task_file_iters(void)
>>>> +{
>>>> +	int prog_fd, child_pid, wstatus, err = 0;
>>>> +	const int stack_size = 1024 * 1024;
>>>> +	struct iters_task_file *skel;
>>>> +	struct files_test_args args;
>>>> +	struct bpf_program *prog;
>>>> +	bool setup_end, test_end;
>>>> +	char *stack;
>>>> +
>>>> +	skel = iters_task_file__open_and_load();
>>>> +	if (!ASSERT_OK_PTR(skel, "open_and_load"))
>>>> +		return;
>>>> +
>>>> +	if (!ASSERT_OK(skel->bss->err, "pre_test_err"))
>>>> +		goto cleanup_skel;
>>>> +
>>>> +	prog = bpf_object__find_program_by_name(skel->obj, "test_bpf_iter_task_file");
>>>> +	if (!ASSERT_OK_PTR(prog, "find_program_by_name"))
>>>> +		goto cleanup_skel;
>>>> +
>>>> +	prog_fd = bpf_program__fd(prog);
>>>> +	if (!ASSERT_GT(prog_fd, -1, "bpf_program__fd"))
>>>> +		goto cleanup_skel;
>>>
>>> I don't think you need to check on this once we did iters_task_file__open_and_load
>>>
>>>> +
>>>> +	stack = (char *)malloc(stack_size);
>>>> +	if (!ASSERT_OK_PTR(stack, "clone_stack"))
>>>> +		goto cleanup_skel;
>>>> +
>>>> +	setup_end = false;
>>>> +	test_end = false;
>>>> +
>>>> +	args.setup_end = &setup_end;
>>>> +	args.test_end = &test_end;
>>>> +
>>>> +	/* Note that there is no CLONE_FILES */
>>>> +	child_pid = clone(task_file_test_process, stack + stack_size, CLONE_VM | SIGCHLD, &args);
>>>> +	if (!ASSERT_GT(child_pid, -1, "child_pid"))
>>>> +		goto cleanup_stack;
>>>> +
>>>> +	while (!setup_end)
>>>> +		;
>>>
>>> I thin kthe preferred way is to synchronize through pipe,
>>> you can check prog_tests/uprobe_multi_test.c
>>>
>>
>> Thanks for your reply.
>>
>> Do we really need to use pipe? Currently this test is very simple.
>>
>> In this test, all files opened by the test process will be closed first
>> so that there is an empty file description table, and then open the
>> test files.
>>
>> This way the test process has only 3 newly opened files and the file
>> descriptors are always 0, 1, 2.
>>
>> Although using pipe is feasible, this test will become more complicated
>> than it is now.
> 
> I see, I missed the close_range call.. anyway I'd still prefer pipe to busy waiting
> 
> perhaps you could use fentry probe triggered by the task_file_test_process
> and do the fd/file iteration in there? that way there'be no need for the sync
> 
> jirka

Sorry for the delay, I have been a bit busy recently.

Thanks for letting me know, fentry is a good approach.

I used fentry in patch series v5.


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

end of thread, other threads:[~2024-12-10 14:17 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-19 17:49 [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and bpf_fget_task() kfunc Juntong Deng
2024-11-19 17:53 ` [PATCH bpf-next v4 1/5] bpf: Introduce task_file open-coded iterator kfuncs Juntong Deng
2024-11-20 10:55   ` Jiri Olsa
2024-11-20 11:04     ` Jiri Olsa
2024-11-19 17:53 ` [PATCH bpf-next v4 2/5] selftests/bpf: Add tests for open-coded style process file iterator Juntong Deng
2024-11-20 11:27   ` Jiri Olsa
2024-11-26 22:24     ` Juntong Deng
2024-11-27 11:21       ` Jiri Olsa
2024-12-10 14:17         ` Juntong Deng
2024-11-19 17:54 ` [PATCH bpf-next v4 3/5] bpf: Add bpf_fget_task() kfunc Juntong Deng
2024-11-19 17:54 ` [PATCH bpf-next v4 4/5] bpf: Make fs kfuncs available for SYSCALL and TRACING program types Juntong Deng
2024-11-19 17:54 ` [PATCH bpf-next v4 5/5] selftests/bpf: Add tests for bpf_fget_task() kfunc Juntong Deng
2024-11-19 18:40 ` [PATCH bpf-next v4 0/5] bpf: Add open-coded style process file iterator and " Juntong Deng
2024-11-20  9:12   ` Christian Brauner
2024-11-26 22:15     ` Juntong Deng

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