Message ID | tencent_97F8B56B340F51DB604B482FEBF012460505@qq.com |
---|---|
State | New |
Headers | show |
Series | [bpf-next,1/2] bpf: Add bpf_task_cwd_from_pid() kfunc | expand |
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. >> >> [1] https://github.com/bpftrace/bpftrace/issues/3314 > 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. >>> >>> [1] https://github.com/bpftrace/bpftrace/issues/3314 >> 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. >>>> >>>> [1] https://github.com/bpftrace/bpftrace/issues/3314 >>> 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-selftests-for-bpf_task_cwd_from_pid/20250529-113933 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.com 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@intel.com/config) 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 }
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)