From: Rong Tao rongtao@cestc.cn
It is a bit troublesome to get cwd based on pid in bpf program, such as bpftrace example [1].
This patch therefore adds a new bpf_task_cwd_from_pid() kfunc which allows BPF programs to get cwd from a pid.
[1] https://github.com/bpftrace/bpftrace/issues/3314
Signed-off-by: Rong Tao rongtao@cestc.cn --- kernel/bpf/helpers.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index b71e428ad936..0f32fbc997bb 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -24,6 +24,10 @@ #include <linux/bpf_mem_alloc.h> #include <linux/kasan.h> #include <linux/bpf_verifier.h> +#include <linux/fs.h> +#include <linux/fs_struct.h> +#include <linux/path.h> +#include <linux/string.h>
#include "../../lib/kstrtox.h"
@@ -2643,6 +2647,46 @@ __bpf_kfunc struct task_struct *bpf_task_from_vpid(s32 vpid) return p; }
+/** + * bpf_task_cwd_from_pid - Get a task's absolute pathname of the current + * working directory from its pid. + * @pid: The pid of the task being looked up. + * @buf: The array pointed to by buf. + * @buf_len: buf length. + */ +__bpf_kfunc int bpf_task_cwd_from_pid(s32 pid, char *buf, u32 buf_len) +{ + struct path pwd; + char kpath[256], *path; + struct task_struct *task; + + if (!buf || buf_len == 0) + return -EINVAL; + + rcu_read_lock(); + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if (!task) { + rcu_read_unlock(); + return -ESRCH; + } + task_lock(task); + if (!task->fs) { + task_unlock(task); + return -ENOENT; + } + get_fs_pwd(task->fs, &pwd); + task_unlock(task); + rcu_read_unlock(); + + path = d_path(&pwd, kpath, sizeof(kpath)); + path_put(&pwd); + if (IS_ERR(path)) + return PTR_ERR(path); + + strncpy(buf, path, buf_len); + return 0; +} + /** * bpf_dynptr_slice() - Obtain a read-only pointer to the dynptr data. * @p: The dynptr whose data slice to retrieve @@ -3314,6 +3358,7 @@ BTF_ID_FLAGS(func, bpf_task_get_cgroup1, KF_ACQUIRE | KF_RCU | KF_RET_NULL) #endif BTF_ID_FLAGS(func, bpf_task_from_pid, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_task_from_vpid, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_task_cwd_from_pid, KF_RET_NULL) BTF_ID_FLAGS(func, bpf_throw) #ifdef CONFIG_BPF_EVENTS BTF_ID_FLAGS(func, bpf_send_signal_task, KF_TRUSTED_ARGS)
On Wed, May 28, 2025 at 8:37 PM Rong Tao rtoax@foxmail.com wrote:
From: Rong Tao rongtao@cestc.cn
It is a bit troublesome to get cwd based on pid in bpf program, such as bpftrace example [1].
This patch therefore adds a new bpf_task_cwd_from_pid() kfunc which allows BPF programs to get cwd from a pid.
Yes. This is cumbersome, but adding a very specific kfunc to the kernel is not a solution. This is tracing, no need for precise cwd. probe_read_kernel can do the job. bpftrace needs to have better C interop. Once that happens any kind of tracing extraction will be easy to write in C. Like this bpf_task_cwd_from_pid() can already be written as C bpf program.
On 5/29/25 13:44, Alexei Starovoitov wrote:
On Wed, May 28, 2025 at 8:37 PM Rong Tao rtoax@foxmail.com wrote:
From: Rong Tao rongtao@cestc.cn
It is a bit troublesome to get cwd based on pid in bpf program, such as bpftrace example [1].
This patch therefore adds a new bpf_task_cwd_from_pid() kfunc which allows BPF programs to get cwd from a pid.
Yes. This is cumbersome, but adding a very specific kfunc to the kernel is not a solution. This is tracing, no need for precise cwd. probe_read_kernel can do the job. bpftrace needs to have better C interop. Once that happens any kind of tracing extraction will be easy to write in C. Like this bpf_task_cwd_from_pid() can already be written as C bpf program.
Thanks for your reply, Yesterday I tried many ways to implement the solution of getting cwd from pid/task, but all failed. The basic idea is to rewrite the d_path() code, but in the bpf program, there will be various memory security access problems, even if enough `if (!ptr)` are added, the program cannot be loaded successfully.
https://github.com/Rtoax/bcc/commit/2ba7a2389fc1183264e5195ff26561d93038886c
bcc/tools$ sudo ./opensnoop.py -F
; if (dentry == vfsmnt->mnt_root || dentry == dentry->d_parent) { @ main.c:174 109: (79) r2 = *(u64 *)(r7 +0) R7 invalid mem access 'scalar'
At the same time, bpf_d_path cannot be used because it can only be applied to functions in btf_allowlist_d_path. Currently, it is impossible to get cwd from pid/task in user mode. Any suggestions?
In addition, I fully tested this patch yesterday and it performed well.
Rong Tao
On 5/29/25 6:28 PM, Rong Tao wrote:
On 5/29/25 13:44, Alexei Starovoitov wrote:
On Wed, May 28, 2025 at 8:37 PM Rong Tao rtoax@foxmail.com wrote:
From: Rong Tao rongtao@cestc.cn
It is a bit troublesome to get cwd based on pid in bpf program, such as bpftrace example [1].
This patch therefore adds a new bpf_task_cwd_from_pid() kfunc which allows BPF programs to get cwd from a pid.
Yes. This is cumbersome, but adding a very specific kfunc to the kernel is not a solution. This is tracing, no need for precise cwd. probe_read_kernel can do the job. bpftrace needs to have better C interop. Once that happens any kind of tracing extraction will be easy to write in C. Like this bpf_task_cwd_from_pid() can already be written as C bpf program.
Thanks for your reply, Yesterday I tried many ways to implement the solution of getting cwd from pid/task, but all failed. The basic idea is to rewrite the d_path() code, but in the bpf program, there will be various memory security access problems, even if enough `if (!ptr)` are added, the program cannot be loaded successfully.
https://github.com/Rtoax/bcc/commit/2ba7a2389fc1183264e5195ff26561d93038886c
bcc/tools$ sudo ./opensnoop.py -F
; if (dentry == vfsmnt->mnt_root || dentry == dentry->d_parent) { @ main.c:174 109: (79) r2 = *(u64 *)(r7 +0) R7 invalid mem access 'scalar'
I think you can use bpf_probe_read_kernel() helper to get r2?
At the same time, bpf_d_path cannot be used because it can only be applied to functions in btf_allowlist_d_path. Currently, it is impossible to get cwd from pid/task in user mode. Any suggestions?
In addition, I fully tested this patch yesterday and it performed well.
Rong Tao
On 5/30/25 09:55, Yonghong Song wrote:
On 5/29/25 6:28 PM, Rong Tao wrote:
On 5/29/25 13:44, Alexei Starovoitov wrote:
On Wed, May 28, 2025 at 8:37 PM Rong Tao rtoax@foxmail.com wrote:
From: Rong Tao rongtao@cestc.cn
It is a bit troublesome to get cwd based on pid in bpf program, such as bpftrace example [1].
This patch therefore adds a new bpf_task_cwd_from_pid() kfunc which allows BPF programs to get cwd from a pid.
Yes. This is cumbersome, but adding a very specific kfunc to the kernel is not a solution. This is tracing, no need for precise cwd. probe_read_kernel can do the job. bpftrace needs to have better C interop. Once that happens any kind of tracing extraction will be easy to write in C. Like this bpf_task_cwd_from_pid() can already be written as C bpf program.
Thanks for your reply, Yesterday I tried many ways to implement the solution of getting cwd from pid/task, but all failed. The basic idea is to rewrite the d_path() code, but in the bpf program, there will be various memory security access problems, even if enough `if (!ptr)` are added, the program cannot be loaded successfully.
https://github.com/Rtoax/bcc/commit/2ba7a2389fc1183264e5195ff26561d93038886c
bcc/tools$ sudo ./opensnoop.py -F
; if (dentry == vfsmnt->mnt_root || dentry == dentry->d_parent) { @ main.c:174 109: (79) r2 = *(u64 *)(r7 +0) R7 invalid mem access 'scalar'
I think you can use bpf_probe_read_kernel() helper to get r2?
Thanks a lot, bpf_probe_read_kernel() works :)
At the same time, bpf_d_path cannot be used because it can only be applied to functions in btf_allowlist_d_path. Currently, it is impossible to get cwd from pid/task in user mode. Any suggestions?
In addition, I fully tested this patch yesterday and it performed well.
Rong Tao
Hi Rong,
kernel test robot noticed the following build warnings:
url: https://github.com/intel-lab-lkp/linux/commits/Rong-Tao/selftests-bpf-Add-se... base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master patch link: https://lore.kernel.org/r/tencent_97F8B56B340F51DB604B482FEBF012460505%40qq.... patch subject: [PATCH bpf-next 1/2] bpf: Add bpf_task_cwd_from_pid() kfunc config: x86_64-randconfig-161-20250529 (https://download.01.org/0day-ci/archive/20250530/202505300432.nZC50gOu-lkp@i...) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot lkp@intel.com | Reported-by: Dan Carpenter dan.carpenter@linaro.org | Closes: https://lore.kernel.org/r/202505300432.nZC50gOu-lkp@intel.com/
smatch warnings: kernel/bpf/helpers.c:2687 bpf_task_cwd_from_pid() warn: inconsistent returns 'rcu_read'.
vim +/rcu_read +2687 kernel/bpf/helpers.c
b24383bde5a454 Rong Tao 2025-05-29 2657 __bpf_kfunc int bpf_task_cwd_from_pid(s32 pid, char *buf, u32 buf_len) b24383bde5a454 Rong Tao 2025-05-29 2658 { b24383bde5a454 Rong Tao 2025-05-29 2659 struct path pwd; b24383bde5a454 Rong Tao 2025-05-29 2660 char kpath[256], *path; b24383bde5a454 Rong Tao 2025-05-29 2661 struct task_struct *task; b24383bde5a454 Rong Tao 2025-05-29 2662 b24383bde5a454 Rong Tao 2025-05-29 2663 if (!buf || buf_len == 0) b24383bde5a454 Rong Tao 2025-05-29 2664 return -EINVAL; b24383bde5a454 Rong Tao 2025-05-29 2665 b24383bde5a454 Rong Tao 2025-05-29 2666 rcu_read_lock(); b24383bde5a454 Rong Tao 2025-05-29 2667 task = pid_task(find_vpid(pid), PIDTYPE_PID); b24383bde5a454 Rong Tao 2025-05-29 2668 if (!task) { b24383bde5a454 Rong Tao 2025-05-29 2669 rcu_read_unlock(); b24383bde5a454 Rong Tao 2025-05-29 2670 return -ESRCH; b24383bde5a454 Rong Tao 2025-05-29 2671 } b24383bde5a454 Rong Tao 2025-05-29 2672 task_lock(task); b24383bde5a454 Rong Tao 2025-05-29 2673 if (!task->fs) { b24383bde5a454 Rong Tao 2025-05-29 2674 task_unlock(task); b24383bde5a454 Rong Tao 2025-05-29 2675 return -ENOENT;
rcu_read_unlock();
b24383bde5a454 Rong Tao 2025-05-29 2676 } b24383bde5a454 Rong Tao 2025-05-29 2677 get_fs_pwd(task->fs, &pwd); b24383bde5a454 Rong Tao 2025-05-29 2678 task_unlock(task); b24383bde5a454 Rong Tao 2025-05-29 2679 rcu_read_unlock(); b24383bde5a454 Rong Tao 2025-05-29 2680 b24383bde5a454 Rong Tao 2025-05-29 2681 path = d_path(&pwd, kpath, sizeof(kpath)); b24383bde5a454 Rong Tao 2025-05-29 2682 path_put(&pwd); b24383bde5a454 Rong Tao 2025-05-29 2683 if (IS_ERR(path)) b24383bde5a454 Rong Tao 2025-05-29 2684 return PTR_ERR(path); b24383bde5a454 Rong Tao 2025-05-29 2685 b24383bde5a454 Rong Tao 2025-05-29 2686 strncpy(buf, path, buf_len); b24383bde5a454 Rong Tao 2025-05-29 @2687 return 0; b24383bde5a454 Rong Tao 2025-05-29 2688 }
linux-kselftest-mirror@lists.linaro.org