From nobody Sat Sep 26 20:29:40 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1E52835C68C; Mon, 31 Aug 2026 02:59:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788145152; cv=none; b=fmiFtByHiuwHrd8FtR5q5yfcGCix1eSTHwyNpcTiGaj7W/18KNJgCGEI+fgjSOFH+DoHBS4UzM1xp7Sj8kVSaRDcjbYEcc0eSihQoH22I9vu6kCtnlN0E7v1ucSIUJpdIKH2lXCzmD2la1FSydws+QAHEgbM+9rwrhrpN/i9Ye8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788145152; c=relaxed/simple; bh=diMrWF/LmTzet43A7eKj6E3amyHbnnDa/tpKXigKzZw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jD6SdLe+MDOJ2oVvij/3QBObBFNJZHBYLao1p5ExYoyq43hO8apegc4Jofnb/6G1Gm6sHix5Xl5KK7xgv8bRNt7vvtsqjmp9+smTD4g6BsWGvzMHf/Sz0vo1+qB1z9pFTzFGiZLlnrlWxBtq0Hse64TcyyVUn/y1yyGXYQt3MSk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=L55ZscrO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="L55ZscrO" Received: by smtp.kernel.org (Postfix) with ESMTPS id AE156C2BCFA; Mon, 31 Aug 2026 02:59:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1788145151; bh=diMrWF/LmTzet43A7eKj6E3amyHbnnDa/tpKXigKzZw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=L55ZscrO3tXErkI5OAaHQVqcs+LwX/H1nDJu7RNNoaonWreSTOJeIxhfRUMc9raZ8 L/PX7lVCOgCq68xuX66DqYeLbi6YLPS2tWM7VcZhnlAPqwhR6MhjNr4NI2W+4q1PMx sdQ6xn6BuBR7vTcYkh1klhUD1B7+IvPEYov/KGm8eadQPWQ1du6NcX8Zls9jI02YRv zt99AkHvdmb3V/bY3eKcEA/MifNIDgFBV3gqhbwVZV4UF4XBOTv0Tk71jK8+lxDnLU fa/F0CAd1Dhwy+GsD35dZ9VPiSMq9K24OeeGOZYz1jwDmqPOB+wBkZuDIAvbRq1UYg WsniX3MNb8dDw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8B0DCC61DE2; Mon, 31 Aug 2026 02:59:11 +0000 (UTC) From: Chen Linxuan via B4 Relay Date: Mon, 31 Aug 2026 10:59:06 +0800 Subject: [PATCH v2 1/3] fs: Introduce task path helpers Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260831-pidfd-get-paths-v2-1-c59ea6a21b72@black-desk.cn> References: <20260831-pidfd-get-paths-v2-0-c59ea6a21b72@black-desk.cn> In-Reply-To: <20260831-pidfd-get-paths-v2-0-c59ea6a21b72@black-desk.cn> To: Alexander Viro , Christian Brauner , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Ingo Molnar , Peter Zijlstra , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , K Prateek Nayak , Kees Cook , John Johansen , Georgia Garcia , Paul Moore , James Morris , "Serge E. Hallyn" Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, apparmor@lists.ubuntu.com, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org, Chen Linxuan X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=6540; i=me@black-desk.cn; s=20260831; h=from:subject:message-id; bh=5So2OP5xtxhWElec19b9ZT6vFlwvdbmJSxLeLau4rVo=; b=owEBbQKS/ZANAwAKAXYe5hQ5ma6LAcsmYgBqlO38hlMmWYrfhNP7tNxvYyk/trBioVtyxuO0L 54fL84jSkCJAjMEAAEKAB0WIQTO1VElAk6xdvy0ZVp2HuYUOZmuiwUCapTt/AAKCRB2HuYUOZmu i/oQD/9roMaaNnUmCilRvUZYD8kg+6YObUuwkSY9d99SWki86zWmjnaICnVR+Zb2W8WBtOvGZKB 6jJRoML7cvLT2hBpblOSeMCQNQK0aC6E3aAWlPdUCDesQdi77+V2pW7TEnve0oy2yGy2VI4Oehd h6cf2M5RlpdB2Qk2wd/ASa7xGgcF0UUx0Je/e6Z8kqyWrqaPGGcEr2kJiyDgQ5TnGcyS7etamrO wgif/QpDRx+2UYqUbGnAQh1eHfQFMlfKvI36EjtFBqaUCC5y2MC/AadKqtBcDaq6oJQCf7oS0/k dY8MXF5nEsqRAGoex3WZV2FMuRg6b8qo4ytELiFKlNsBY/a59YynuRiMzBqI0MsbAsGFYQznNa5 88UDWMfpUTMB/7fS7xwyV1Sc8rI2fR3Vg7bfoRteDU1zUgrnfalv0MZSa+398Y3IBu0q0JRaVp5 ECbyOznGF4D8gbD0IiXzV6XnInvJTX7UrfKEdzI4XU2UUWFEOyq/uXoTTZ/IOgDK+AR0tPjMbBr 0We4F21C4pk/F5ZEhucZ8qdPYzCNRfCNkYt5zk8XXbd7biq9LJoDBPt3zFtDEAmohqdbzTfPeed zIt2DrJbd3/iU1BtXbZ1aP04uRnh1E2a+ha+noDPZQ/5tmZQ3OioxmWNeAtrv03A6onDNUibqlZ QAHLvTlgoussE/Q== X-Developer-Key: i=me@black-desk.cn; a=openpgp; fpr=D818ACDD385CAE92D4BAC01A6269794D24791D21 X-Endpoint-Received: by B4 Relay for me@black-desk.cn/20260831 with auth_id=991 X-Original-From: Chen Linxuan Reply-To: me@black-desk.cn From: Chen Linxuan Introduce helpers that acquire a referenced struct path for a task's executable, root, and working directory. Reuse them for procfs task links and AppArmor executable-path handling instead of duplicating file and path reference handling at each call site. Assisted-by: LLM Signed-off-by: Chen Linxuan --- fs/fs_struct.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ fs/proc/base.c | 34 ++-------------------------------- include/linux/fs_struct.h | 3 +++ include/linux/mm.h | 1 + kernel/fork.c | 21 +++++++++++++++++++++ security/apparmor/task.c | 12 +++--------- 6 files changed, 74 insertions(+), 41 deletions(-) diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 34699f3b6f88..5c772896260a 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c @@ -10,6 +10,50 @@ #include "internal.h" #include "mount.h" =20 +/** + * get_task_root - acquire a reference to the task's root path + * @task: The task. + * @root: The task's root path. + * + * Returns 0 if the task has a root path, or -ENOENT if it does not. The + * caller must release the path through path_put() on success. + */ +int get_task_root(struct task_struct *task, struct path *root) +{ + int ret =3D -ENOENT; + + task_lock(task); + if (task->real_fs) { + get_fs_root(task->real_fs, root); + ret =3D 0; + } + task_unlock(task); + + return ret; +} + +/** + * get_task_pwd - acquire a reference to the task's working directory + * @task: The task. + * @pwd: The task's working directory. + * + * Returns 0 if the task has a working directory, or -ENOENT if it does no= t. + * The caller must release the path through path_put() on success. + */ +int get_task_pwd(struct task_struct *task, struct path *pwd) +{ + int ret =3D -ENOENT; + + task_lock(task); + if (task->real_fs) { + get_fs_pwd(task->real_fs, pwd); + ret =3D 0; + } + task_unlock(task); + + return ret; +} + /* * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. * It can block. diff --git a/fs/proc/base.c b/fs/proc/base.c index 6a39de424f62..7e2c0538323c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -206,31 +206,10 @@ static unsigned int __init pid_entry_nlink(const stru= ct pid_entry *entries, return count; } =20 -static int get_task_root(struct task_struct *task, struct path *root) -{ - int result =3D -ENOENT; - - task_lock(task); - if (task->real_fs) { - get_fs_root(task->real_fs, root); - result =3D 0; - } - task_unlock(task); - return result; -} - static int proc_cwd_link(struct dentry *dentry, struct path *path, struct task_struct *task) { - int result =3D -ENOENT; - - task_lock(task); - if (task->real_fs) { - get_fs_pwd(task->real_fs, path); - result =3D 0; - } - task_unlock(task); - return result; + return get_task_pwd(task, path); } =20 static int proc_root_link(struct dentry *dentry, struct path *path, @@ -1761,16 +1740,7 @@ static const struct file_operations proc_pid_set_com= m_operations =3D { static int proc_exe_link(struct dentry *dentry, struct path *exe_path, struct task_struct *task) { - struct file *exe_file; - - exe_file =3D get_task_exe_file(task); - if (exe_file) { - *exe_path =3D exe_file->f_path; - path_get(&exe_file->f_path); - fput(exe_file); - return 0; - } else - return -ENOENT; + return get_task_exe_path(task, exe_path); } =20 static int call_proc_get_link(struct dentry *dentry, struct inode *inode, = struct path *path_out) diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index 97eef8d3863d..fb725707754d 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -42,6 +42,9 @@ static inline void get_fs_pwd(struct fs_struct *fs, struc= t path *pwd) read_sequnlock_excl(&fs->seq); } =20 +int get_task_root(struct task_struct *task, struct path *root); +int get_task_pwd(struct task_struct *task, struct path *pwd); + struct fs_struct *switch_fs_struct(struct fs_struct *new_fs); =20 extern bool current_chrooted(void); diff --git a/include/linux/mm.h b/include/linux/mm.h index dd09c438fa23..a65f24b2e65b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4239,6 +4239,7 @@ extern int set_mm_exe_file(struct mm_struct *mm, stru= ct file *new_exe_file); extern int replace_mm_exe_file(struct mm_struct *mm, struct file *new_exe_= file); extern struct file *get_mm_exe_file(struct mm_struct *mm); extern struct file *get_task_exe_file(struct task_struct *task); +int get_task_exe_path(struct task_struct *task, struct path *exe_path); =20 extern void vm_stat_account(struct mm_struct *, vm_flags_t, long npages); =20 diff --git a/kernel/fork.c b/kernel/fork.c index 416758c8a3d4..a493de3ae5c2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1371,6 +1371,27 @@ struct file *get_task_exe_file(struct task_struct *t= ask) return exe_file; } =20 +/** + * get_task_exe_path - acquire a reference to the task's executable path + * @task: The task. + * @exe_path: The task's executable path. + * + * Returns 0 if the task has an executable path, or -ENOENT if it does not. + * The caller must release the path through path_put() on success. + */ +int get_task_exe_path(struct task_struct *task, struct path *exe_path) +{ + struct file *exe_file =3D get_task_exe_file(task); + + if (!exe_file) + return -ENOENT; + + *exe_path =3D exe_file->f_path; + path_get(exe_path); + fput(exe_file); + return 0; +} + /** * get_task_mm - acquire a reference to the task's mm * @task: The task. diff --git a/security/apparmor/task.c b/security/apparmor/task.c index e16ff4130bc2..05cba261dd34 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -13,6 +13,7 @@ */ =20 #include +#include #include #include =20 @@ -330,22 +331,15 @@ int aa_may_ptrace(const struct cred *tracer_cred, str= uct aa_label *tracer, =20 static const char *get_current_exe_path(char *buffer, int buffer_size) { - struct file *exe_file; - struct path p; + struct path p __free(path_put) =3D {}; const char *path_str; =20 - exe_file =3D get_task_exe_file(current); - if (!exe_file) + if (get_task_exe_path(current, &p)) return ERR_PTR(-ENOENT); - p =3D exe_file->f_path; - path_get(&p); =20 if (aa_path_name(&p, FLAG_VIEW_SUBNS, buffer, &path_str, NULL, NULL)) path_str =3D ERR_PTR(-ENOMEM); =20 - fput(exe_file); - path_put(&p); - return path_str; } =20 --=20 2.53.0 From nobody Sat Sep 26 20:29:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1E42C2D73B6; Mon, 31 Aug 2026 02:59:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788145152; cv=none; b=jlTWsWkSBG4jvuywsaDRyjY5lbgfFSoF6OysGkbsG+lfz+JJxICl6tTu9lrspJHhGtHr+b1XMrH/ufqVGqx/zvbwL2yItFNYaeV3HScea1j3sA2QyiYXj2i36qxsxDjr9i5Fcg1cXQd8+Pvv95tco+PD3M5p2jOSfPEMWX4h1sk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788145152; c=relaxed/simple; bh=qsO+jEt062xFpgDrZl1uHqGbUzP7YQqOBcQcPn6gP4I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZVwAgZWArkucDD17o1SO6eW9ApZIW3jtws2mCd3lY33Vb1TxXpkTWeO1w+sVXazBGsux36D5+wbJKmfkyu7UDabidVqQ33V9bipHFTMJdPzpOnU8+S9z1PdFKVftnIp4Cl/eClwYVWt56KhNNjRlZsO+byoMxV8ji5dmvosSSco= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=cBavrKJE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="cBavrKJE" Received: by smtp.kernel.org (Postfix) with ESMTPS id BA023C2BCFB; Mon, 31 Aug 2026 02:59:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1788145151; bh=qsO+jEt062xFpgDrZl1uHqGbUzP7YQqOBcQcPn6gP4I=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=cBavrKJEZ7jFJ8mfLHkDO14p3adji9j2EnNV18XzEhac8oDOLM5kKFReMgjfG1W/v T/EAoV44UaRXUndDbGH3WFXwCqAWrDxaa54Z2iO5SeRAGTg3r7zDExw2taIj02zOY6 FZT9Dj6s5HetE+pScGPSuOEnujcXho6JfxslxH3G41lQWd6X+ZOWvT/guT+vPh21ag TrPOZ2DD/HZMj9McsvlCTwqdDFmogjZSwCR68TAjmTOfM+45AEq1u5oSdxVFD7+UPa vAvdrLBgxw0wb9jxfmQspKCSH3MUzsfMhqrlN6QUr5z7ntKyL5DRAcKcoLO/hbgckC lRs4R8qcWlhPg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9D645C61DE4; Mon, 31 Aug 2026 02:59:11 +0000 (UTC) From: Chen Linxuan via B4 Relay Date: Mon, 31 Aug 2026 10:59:07 +0800 Subject: [PATCH v2 2/3] pidfd: Use scoped cleanup for task access Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260831-pidfd-get-paths-v2-2-c59ea6a21b72@black-desk.cn> References: <20260831-pidfd-get-paths-v2-0-c59ea6a21b72@black-desk.cn> In-Reply-To: <20260831-pidfd-get-paths-v2-0-c59ea6a21b72@black-desk.cn> To: Alexander Viro , Christian Brauner , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Ingo Molnar , Peter Zijlstra , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , K Prateek Nayak , Kees Cook , John Johansen , Georgia Garcia , Paul Moore , James Morris , "Serge E. Hallyn" Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, apparmor@lists.ubuntu.com, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org, Chen Linxuan X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5079; i=me@black-desk.cn; s=20260831; h=from:subject:message-id; bh=SVmkrkqreGdyu4HBET8Otf2T/l+VOx0ddobGuHRudwA=; b=owEBbQKS/ZANAwAKAXYe5hQ5ma6LAcsmYgBqlO38jtoUK7Zb2KaX9LmA95hJa9Ar2TOqQKP0Y mknRd85v6uJAjMEAAEKAB0WIQTO1VElAk6xdvy0ZVp2HuYUOZmuiwUCapTt/AAKCRB2HuYUOZmu i5X5EACIqaukJokPjfQSlW5sUrgCjOuBxwqea6WJwCreP8MQShFKmwjR4Qmbul9kBNZMsGgkWgD pHbwT8els8YMxEYg+Pf1exMDyQJTlhXjpgpIKZKRbDo154/bfblKtzFjAqQVQdWt7JnLv71ric9 u6squ8kjcsenN0dhwuO8Y00xsDBdD2HJm0mpw+smScEDAbqoZuFrrU7+3nb6EJGVelkXIIWtIjv fZrX57jCQCpNBCBlihI1FoX9RW+JEaoII/mVrXK/RfZmgWBBHKt32vCiW0T4TsXbgxsIKKaS7VV nRrGBERlyFyufsbAXVuQIcfpvvnt0Rm96XBpfR9OhLptzD1Wi+mI69M+QOXccIs2HGrK2TwtAzI LP34Z4zSZAWMbafTwNO6ZBy3zRnEFaKjAaPHAcc1Dl1UWS2SzT38ANIrlI5bpEDxKqlqZFL2JLa lKrhCX4nG7CDqSZ6freKOsne110U/HFPFSs7uyU7pUcPLEHlsbXIibjCMTiBEq53yebl+ka2vxA oeWS7CnAxRaAh+FitafaT41X3gyg9Bhhjn0C2PCRg1TqnieM3QG1mBkHxh3B/8Xb2cDZ9hfmH9T 5dhHrLPxUHWf2X1YLnQMwQarcA7H69XPnF8qpf5KLAGo3HE1EFSNKM5WusZhqK394lWi2VIp6Qg RjwpZnuocjYlECA== X-Developer-Key: i=me@black-desk.cn; a=openpgp; fpr=D818ACDD385CAE92D4BAC01A6269794D24791D21 X-Endpoint-Received: by B4 Relay for me@black-desk.cn/20260831 with auth_id=991 X-Original-From: Chen Linxuan Reply-To: me@black-desk.cn From: Chen Linxuan Split namespace acquisition from namespace fd creation and represent a privileged target task as a scoped class that owns both the task reference and exec_update_lock. Use the class for namespace lookups so ptrace access checks and task state reads remain tied to the same exec critical section, while open_namespace() stays outside the lock. Assisted-by: LLM Signed-off-by: Chen Linxuan --- fs/pidfs.c | 115 ++++++++++++++++++++++++++++++++++++++-------------------= ---- 1 file changed, 71 insertions(+), 44 deletions(-) diff --git a/fs/pidfs.c b/fs/pidfs.c index a6a643f15d08..49a1ab0c42f9 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -527,62 +527,67 @@ static bool pidfs_ioctl_valid(unsigned int cmd) return false; } =20 -static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long= arg) +static inline void pidfd_put_task_locked(struct task_struct *task) { - struct task_struct *task __free(put_task) =3D NULL; - struct nsproxy *nsp __free(put_nsproxy) =3D NULL; - struct ns_common *ns_common =3D NULL; - int error; - - if (!pidfs_ioctl_valid(cmd)) - return -ENOIOCTLCMD; - - if (cmd =3D=3D FS_IOC_GETVERSION) { - if (!arg) - return -EINVAL; - - __u32 __user *argp =3D (__u32 __user *)arg; - return put_user(file_inode(file)->i_generation, argp); + if (!IS_ERR_OR_NULL(task)) { + up_read(&task->signal->exec_update_lock); + put_task_struct(task); } +} =20 - /* Extensible IOCTL that does not open namespace FDs, take a shortcut */ - if (_IOC_NR(cmd) =3D=3D _IOC_NR(PIDFD_GET_INFO)) - return pidfd_info(file, cmd, arg); +/* + * Return @pid's task with @task's exec_update_lock held. The ptrace check + * and the callers' task state lookup must be performed while the lock is = held + * so that they cannot race with a concurrent execve(). + */ +static struct task_struct *pidfd_get_task_locked(struct pid *pid, + unsigned long arg) +{ + struct task_struct *task __free(put_task) =3D + get_pid_task(pid, PIDTYPE_PID); + int error; =20 - task =3D get_pid_task(pidfd_pid(file), PIDTYPE_PID); if (!task) - return -ESRCH; + return ERR_PTR(-ESRCH); =20 if (arg) - return -EINVAL; + return ERR_PTR(-EINVAL); =20 - /* - * We're trying to open a file descriptor to the namespace so perform a - * filesystem cred ptrace check. Hold @task's exec_update_lock for the - * duration of the ptrace check and the namespace lookup so that the - * credentials used for the access decision match those of @task at the - * time its namespace is read, preventing a concurrent execve() from - * swapping the task's credentials in between the check and the use. We - * mirror nsfs behavior. - */ error =3D down_read_killable(&task->signal->exec_update_lock); if (error) - return error; + return ERR_PTR(error); =20 if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { - error =3D -EACCES; - goto out_unlock; + up_read(&task->signal->exec_update_lock); + return ERR_PTR(-EACCES); } =20 + return_ptr(task); +} + +DEFINE_CLASS(pidfd_task_locked, struct task_struct *, + pidfd_put_task_locked(_T), + pidfd_get_task_locked(pid, arg), + struct pid *pid, unsigned long arg) + +static struct ns_common *pidfd_get_namespace(struct pid *pid, + unsigned int cmd, + unsigned long arg) +{ + struct nsproxy *nsp __free(put_nsproxy) =3D NULL; + struct ns_common *ns_common =3D NULL; + + CLASS(pidfd_task_locked, task)(pid, arg); + if (IS_ERR(task)) + return ERR_CAST(task); + scoped_guard(task_lock, task) { nsp =3D task->nsproxy; if (nsp) get_nsproxy(nsp); } - if (!nsp) { - error =3D -ESRCH; /* just pretend it didn't exist */ - goto out_unlock; - } + if (!nsp) + return ERR_PTR(-ESRCH); /* just pretend it didn't exist */ =20 switch (cmd) { /* Namespaces that hang of nsproxy. */ @@ -664,16 +669,38 @@ static long pidfd_ioctl(struct file *file, unsigned i= nt cmd, unsigned long arg) #endif break; default: - error =3D -ENOIOCTLCMD; + return ERR_PTR(-ENOIOCTLCMD); } =20 - if (!error && !ns_common) - error =3D -EOPNOTSUPP; + if (!ns_common) + return ERR_PTR(-EOPNOTSUPP); =20 -out_unlock: - up_read(&task->signal->exec_update_lock); - if (error) - return error; + return ns_common; +} + +static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long= arg) +{ + struct ns_common *ns_common =3D NULL; + + if (!pidfs_ioctl_valid(cmd)) + return -ENOIOCTLCMD; + + if (cmd =3D=3D FS_IOC_GETVERSION) { + if (!arg) + return -EINVAL; + + __u32 __user *argp =3D (__u32 __user *)arg; + + return put_user(file_inode(file)->i_generation, argp); + } + + /* Extensible IOCTL that does not open namespace FDs, take a shortcut */ + if (_IOC_NR(cmd) =3D=3D _IOC_NR(PIDFD_GET_INFO)) + return pidfd_info(file, cmd, arg); + + ns_common =3D pidfd_get_namespace(pidfd_pid(file), cmd, arg); + if (IS_ERR(ns_common)) + return PTR_ERR(ns_common); =20 /* open_namespace() unconditionally consumes the reference */ return open_namespace(ns_common); --=20 2.53.0 From nobody Sat Sep 26 20:29:41 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 206FC35C696; Mon, 31 Aug 2026 02:59:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788145152; cv=none; b=B2ArJmQxY4hoEWVTuc0oalGxCLDgiXy5o+wrFv/hdvgs1cvqsEzA9WO9iicCfPQOyALVcspngMiXHIvh25Wr3tkH5ZJK//iKDvoC6tE7clT9IoSiMkQw+PzPOzfSTsFNzmuQkIAFpASvYNK4RBQi3WNVgEQ5QO8SD6obaiSBJxc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788145152; c=relaxed/simple; bh=Smhz1v0S65AWaypnb/b+QGQdSN9Z/8SuckCUr7LAkas=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RZE7w/dDdF2xNcEYyIEHj9Zde1Qd8b+OFhLliqXadjZJSuQyHjDD5uCkGcVhsYb4Lr1dUBySww3rHg3cZFHPEgEehkVJv2l69lGMi+sf2ltOPivWqoWo1SL+bj3T3j5VtKgEs4EAzpIjkCES9cCEiBhAsivG2al2Tq2R9OCZUG4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=NsQ4E4Yt; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="NsQ4E4Yt" Received: by smtp.kernel.org (Postfix) with ESMTPS id C7A88C4AF0B; Mon, 31 Aug 2026 02:59:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1788145151; bh=Smhz1v0S65AWaypnb/b+QGQdSN9Z/8SuckCUr7LAkas=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=NsQ4E4Ythu3E/qH7sO7wDJZIsChxiYTG8DLM7xrEAVG8XSHdq/c6aBwDILQKj8LUP +M/Poc5USsXWrH7uvMsVy2+OngtVnG8qD42NcH5k5KrQdTToRUHe1WaODy9GT25v+U AVlE9OhIZalJ5ncJFAwK0kyYoDga1cZ9zuEgmYnAV1huDBG8KZmmZW2SQ7GtSOC1mO rH8xQS6UHxmqqRplTxONoUJJ41oaXPH5kLsbT1x6i6BjGPV2zx3O70JeHsxovYBB/a h85e5kh5/W5fcYg8hSA1sBpZlGffZ6m7jNC8Em977qs3N/14ytEVNLq/pgnsP5opqU vKymxepX01UFQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF62FC624A5; Mon, 31 Aug 2026 02:59:11 +0000 (UTC) From: Chen Linxuan via B4 Relay Date: Mon, 31 Aug 2026 10:59:08 +0800 Subject: [PATCH v2 3/3] pidfd: Add task path ioctls Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260831-pidfd-get-paths-v2-3-c59ea6a21b72@black-desk.cn> References: <20260831-pidfd-get-paths-v2-0-c59ea6a21b72@black-desk.cn> In-Reply-To: <20260831-pidfd-get-paths-v2-0-c59ea6a21b72@black-desk.cn> To: Alexander Viro , Christian Brauner , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Ingo Molnar , Peter Zijlstra , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , K Prateek Nayak , Kees Cook , John Johansen , Georgia Garcia , Paul Moore , James Morris , "Serge E. Hallyn" Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, apparmor@lists.ubuntu.com, linux-security-module@vger.kernel.org, linux-api@vger.kernel.org, Chen Linxuan X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3678; i=me@black-desk.cn; s=20260831; h=from:subject:message-id; bh=ZADtZNdlB7oE/hBsTTGGqoCz5/1kKnW1D9F4WuU2Sco=; b=owEBbQKS/ZANAwAKAXYe5hQ5ma6LAcsmYgBqlO39Ayt8SEEcYynePriQkVXfWPjAUsBYWbqbX dslGZuXhKOJAjMEAAEKAB0WIQTO1VElAk6xdvy0ZVp2HuYUOZmuiwUCapTt/QAKCRB2HuYUOZmu iyLMD/42sfTAfcQHAYOWOJ+1xkyRw56ENUpVgpNhdtd3yFPnmHrvcsrRE+b8eeBW8lTK1jTZmwh m/b/X7YW+O3DWxXjKeBMihhsiieg2Qjxnuva26Dx82wX5SZBv98ehkyw8pJSdi6Xigi1ChJcTZk wLzpDF0H0qF0bIkVdvgbTgdFyq4GEAksg8fdpq/tzbWs+wM9KDAZ06SgoUsrJULms0Ck61Owig/ ta6YSZh9VJSeqbbSe2efkkQ9lZXouB0uRpUgdfY2iYrb/Orprb/V3WpzlU0l1n8eI5sSRC2I4p4 qxB1Gga1IWS2P5+r3xvZYQo/5LJV//6ca18irPp9HX9lL+trhCEfNLyIrFxmnkODZqFn7mrXm0V u++2ACXeLlIjQ/Bu3dEma/WRfcYF3cUmNCMv8cbKQnZdJS0MtW9XBnLy5mOT8U3UzFZtSfVzsVe yQUopFXBBAUEWdWGLfZuTAbd6RLLbBYOFSsPHlOPsQtUwRGEy2Osh1/BMpL6oszntsPrL8dH4rp KnftSmefkfh0pWnt17qzNceLjHOlTbMLX0SiU2kzTs1w56pW93DWGqfS50H0fmf9+QCGMeqIEzj 7C9QTjehkhz9odNBtcBgvfXk+28gp8cDxlj7ZOJURuE5ZEALFjSQRRPvLcHmj9h9WyWaR5kuObN BcBuQvS2RLXfJpA== X-Developer-Key: i=me@black-desk.cn; a=openpgp; fpr=D818ACDD385CAE92D4BAC01A6269794D24791D21 X-Endpoint-Received: by B4 Relay for me@black-desk.cn/20260831 with auth_id=991 X-Original-From: Chen Linxuan Reply-To: me@black-desk.cn From: Chen Linxuan Add PIDFD_GET_EXE, PIDFD_GET_CWD, and PIDFD_GET_ROOT to return close-on-exec O_PATH file descriptors referencing the target task's executable, working directory, and root directory. The new ioctls use the same PTRACE_MODE_READ_FSCREDS permission check and nonzero-argument rejection as the existing namespace ioctls. The target is sampled while holding exec_update_lock so that the access check and path read cannot race with execve(). This allows userspace to obtain stable path references from a pidfd without requiring procfs. Assisted-by: LLM Signed-off-by: Chen Linxuan --- fs/pidfs.c | 38 ++++++++++++++++++++++++++++++++++++++ include/uapi/linux/pidfd.h | 7 +++++++ 2 files changed, 45 insertions(+) diff --git a/fs/pidfs.c b/fs/pidfs.c index 49a1ab0c42f9..b21374f00002 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -510,6 +511,9 @@ static bool pidfs_ioctl_valid(unsigned int cmd) case PIDFD_GET_UTS_NAMESPACE: case PIDFD_GET_USER_NAMESPACE: case PIDFD_GET_PID_NAMESPACE: + case PIDFD_GET_EXE: + case PIDFD_GET_CWD: + case PIDFD_GET_ROOT: return true; } =20 @@ -678,9 +682,31 @@ static struct ns_common *pidfd_get_namespace(struct pi= d *pid, return ns_common; } =20 +static int pidfd_get_task_path(struct pid *pid, unsigned int cmd, + unsigned long arg, struct path *path) +{ + CLASS(pidfd_task_locked, task)(pid, arg); + + if (IS_ERR(task)) + return PTR_ERR(task); + + switch (cmd) { + case PIDFD_GET_EXE: + return get_task_exe_path(task, path); + case PIDFD_GET_CWD: + return get_task_pwd(task, path); + case PIDFD_GET_ROOT: + return get_task_root(task, path); + } + + return -EINVAL; +} + static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long= arg) { struct ns_common *ns_common =3D NULL; + struct path path __free(path_put) =3D {}; + int error; =20 if (!pidfs_ioctl_valid(cmd)) return -ENOIOCTLCMD; @@ -698,6 +724,18 @@ static long pidfd_ioctl(struct file *file, unsigned in= t cmd, unsigned long arg) if (_IOC_NR(cmd) =3D=3D _IOC_NR(PIDFD_GET_INFO)) return pidfd_info(file, cmd, arg); =20 + switch (cmd) { + case PIDFD_GET_EXE: + case PIDFD_GET_CWD: + case PIDFD_GET_ROOT: + error =3D pidfd_get_task_path(pidfd_pid(file), cmd, arg, &path); + if (error) + return error; + + return FD_ADD(O_CLOEXEC, + dentry_open(&path, O_PATH, current_cred())); + } + ns_common =3D pidfd_get_namespace(pidfd_pid(file), cmd, arg); if (IS_ERR(ns_common)) return PTR_ERR(ns_common); diff --git a/include/uapi/linux/pidfd.h b/include/uapi/linux/pidfd.h index 0919246a1611..95ce1819f423 100644 --- a/include/uapi/linux/pidfd.h +++ b/include/uapi/linux/pidfd.h @@ -121,4 +121,11 @@ struct pidfd_info { #define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10) #define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11,= struct pidfd_info) =20 +/* Return an O_PATH file descriptor for the target task's executable. */ +#define PIDFD_GET_EXE _IO(PIDFS_IOCTL_MAGIC, 12) +/* Return an O_PATH file descriptor for the target task's working director= y. */ +#define PIDFD_GET_CWD _IO(PIDFS_IOCTL_MAGIC, 13) +/* Return an O_PATH file descriptor for the target task's root directory. = */ +#define PIDFD_GET_ROOT _IO(PIDFS_IOCTL_MAGIC, 14) + #endif /* _UAPI_LINUX_PIDFD_H */ --=20 2.53.0