FAILED: patch "[PATCH] proc: protect ptrace_may_access() with exec_update_lock (FD" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 6255da28d4bb5349fe18e84cb043ccd394eba75d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026071447-twitter-wick-5966@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 6255da28d4bb5349fe18e84cb043ccd394eba75d Mon Sep 17 00:00:00 2001
From: Jann Horn <[email protected]>
Date: Mon, 18 May 2026 18:35:16 +0200
Subject: [PATCH] proc: protect ptrace_may_access() with exec_update_lock (FD
links)
proc_pid_get_link() and proc_pid_readlink() currently look up the task from the pid once, then do the ptrace access check on that task, then look up the task from the pid a second time to do the actual access. That's racy in several ways.
To fix it, pass the task to the ->proc_get_link() handler, and instead of proc_fd_access_allowed(), introduce a new helper call_proc_get_link() that looks up and locks the task, does the access check, and calls ->proc_get_link().
fs/proc/base.c +47 -72
@@ -218,33 +218,24 @@ static int get_task_root(struct task_struct *task, struct path *root)return result; } -static int proc_cwd_link (struct dentry *dentry,struct path *path) +static int proc_cwd_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task =get_proc_task (d_inode (dentry));int result = -ENOENT ; -if (task) { -task_lock (task); -if (task->fs) { -get_fs_pwd (task->fs, path); - result =0 ; - } -task_unlock (task); -put_task_struct (task); +task_lock (task); +if (task->fs) { +get_fs_pwd (task->fs, path); + result =0 ; } +task_unlock (task);return result; } -static int proc_root_link (struct dentry *dentry,struct path *path) +static int proc_root_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task =get_proc_task (d_inode (dentry)); -int result = -ENOENT ; - -if (task) { - result =get_task_root (task, path); -put_task_struct (task); - } -return result; +return get_task_root (task, path); }/*
@@ -710,23 +701,6 @@ static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns,/* Here the fs part begins */ /************************************************************************/ -/* permission checks */ -static bool proc_fd_access_allowed (struct inode *inode) -{ -struct task_struct *task; -bool allowed = false; -/* Allow access to a task's file descriptors if it is us or we -* may use ptrace attach to the process and find out that -* information. -*/ - task =get_proc_task (inode); -if (task) { - allowed =ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS ); -put_task_struct (task); - } -return allowed; -} -int proc_nochmod_setattr (struct mnt_idmap *idmap,struct dentry *dentry,struct iattr *attr) {
@@ -1783,16 +1757,12 @@ static const struct file_operations proc_pid_set_comm_operations = { .release = single_release, }; -static int proc_exe_link (struct dentry *dentry,struct path *exe_path) +static int proc_exe_link (struct dentry *dentry,struct path *exe_path, +struct task_struct *task) { -struct task_struct *task;struct file *exe_file; - task =get_proc_task (d_inode (dentry)); -if (!task) -return -ENOENT ; exe_file =get_task_exe_file (task); -put_task_struct (task);if (exe_file) { *exe_path = exe_file->f_path;path_get (&exe_file->f_path);
@@ -1802,26 +1772,42 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)return -ENOENT ; } +static int call_proc_get_link (struct dentry *dentry,struct inode *inode,struct path *path_out) +{ +struct task_struct *task; +int ret; + + task =get_proc_task (inode); +if (!task) +return -ENOENT ; + ret =down_read_killable (&task->signal->exec_update_lock); +if (ret) + goto out_put_task; +if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { + ret = -EACCES ; + goto out; + } + ret =PROC_I (inode)->op.proc_get_link (dentry, path_out, task); + +out: +up_read (&task->signal->exec_update_lock); +out_put_task: +put_task_struct (task); +return ret; +} +static const char *proc_pid_get_link (struct dentry *dentry,struct inode *inode,struct delayed_call *done) {struct path path; -int error = -EACCES ; +int error;if (!dentry)return ERR_PTR (-ECHILD ); - -/* Are we allowed to snoop on the tasks file descriptors? */ -if (!proc_fd_access_allowed (inode)) - goto out; - - error =PROC_I (inode)->op.proc_get_link (dentry, &path); -if (error) - goto out; - - error =nd_jump_link (&path); -out: + error =call_proc_get_link (dentry, inode, &path); +if (!error) + error =nd_jump_link (&path);return ERR_PTR (error); }
@@ -1855,17 +1841,11 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int bstruct inode *inode =d_inode (dentry);struct path path; -/* Are we allowed to snoop on the tasks file descriptors? */ -if (!proc_fd_access_allowed (inode)) - goto out; - - error =PROC_I (inode)->op.proc_get_link (dentry, &path); -if (error) - goto out; - - error =do_proc_readlink (&path, buffer, buflen); -path_put (&path); -out: + error =call_proc_get_link (dentry, inode, &path); +if (!error) { + error =do_proc_readlink (&path, buffer, buflen); +path_put (&path); + }return error; }
@@ -2256,21 +2236,16 @@ static const struct dentry_operations tid_map_files_dentry_operations = { .d_delete = pid_delete_dentry, }; -static int map_files_get_link (struct dentry *dentry,struct path *path) +static int map_files_get_link (struct dentry *dentry,struct path *path, +struct task_struct *task) {unsigned long vm_start, vm_end;struct vm_area_struct *vma; -struct task_struct *task;struct mm_struct *mm;int rc; rc = -ENOENT ; - task =get_proc_task (d_inode (dentry)); -if (!task) - goto out; - mm =get_task_mm (task); -put_task_struct (task);if (!mm) goto out;
fs/proc/fd.c +10 -15
@@ -171,24 +171,19 @@ static const struct dentry_operations tid_fd_dentry_operations = { .d_delete = pid_delete_dentry, }; -static int proc_fd_link (struct dentry *dentry,struct path *path) +static int proc_fd_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task;int ret = -ENOENT ; +unsigned int fd =proc_fd (d_inode (dentry)); +struct file *fd_file; - task =get_proc_task (d_inode (dentry)); -if (task) { -unsigned int fd =proc_fd (d_inode (dentry)); -struct file *fd_file; - - fd_file =fget_task (task, fd); -if (fd_file) { - *path = fd_file->f_path; -path_get (&fd_file->f_path); - ret =0 ; -fput (fd_file); - } -put_task_struct (task); + fd_file =fget_task (task, fd); +if (fd_file) { + *path = fd_file->f_path; +path_get (&fd_file->f_path); + ret =0 ; +fput (fd_file); }return ret;
fs/proc/internal.h +1 -1
@@ -110,7 +110,7 @@ extern struct kmem_cache *proc_dir_entry_cache;void pde_free (struct proc_dir_entry *pde);union proc_op { -int (*proc_get_link)(struct dentry *,struct path *); +int (*proc_get_link)(struct dentry *,struct path *,struct task_struct *);int (*proc_show)(struct seq_file *m,struct pid_namespace *ns,struct pid *pid,struct task_struct *task);
Sasha Levin
maintainerPATCH 1/4 proc: use generic setattr() for /proc/$PID/net
From: Thomas Weißschuh <[email protected]>
[ Upstream commit 18e66ae67673f2c8df6f02428798b1355691f2a9 ]
All other files in /proc/$PID/ use proc_setattr().
Not using it allows the usage of chmod() on /proc/$PID/net, even on other processes owned by the same user.
The same would probably also be true for other attributes to be changed.
As this technically represents an ABI change it is not marked for stable so any unlikely regressions are caught during a full release cycle.
Message-Id: <[email protected]>
Stable-dep-of: 6255da28d4bb ("proc: protect ptrace_may_access() with exec_update_lock (FD links)")
--- fs/proc/proc_net.c | 1 + 1 file changed, 1 insertion(+)
fs/proc/proc_net.c +1 -0
@@ -311,6 +311,7 @@ static int proc_tgid_net_getattr(struct user_namespace *mnt_userns,const struct inode_operations proc_net_inode_operations = { .lookup = proc_tgid_net_lookup, .getattr = proc_tgid_net_getattr, + .setattr = proc_setattr, };static int proc_tgid_net_readdir (struct file *file,struct dir_context *ctx)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/4 proc: Move fdinfo PTRACE_MODE_READ check into the inode .permission operation
From: "Tyler Hicks (Microsoft)" <[email protected]>
[ Upstream commit 0a960ba49869ebe8ff859d000351504dd6b93b68 ]
The following commits loosened the permissions of /proc/<PID>/fdinfo/ directory, as well as the files within it, from 0500 to 0555 while also introducing a PTRACE_MODE_READ check between the current task and <PID>'s task:
- commit 7bc3fa0172a4 ("procfs: allow reading fdinfo with PTRACE_MODE_READ")
- commit 1927e498aee1 ("procfs: prevent unprivileged processes accessing fdinfo dir")
Before those changes, inode based system calls like inotify_add_watch(2) would fail when the current task didn't have sufficient read permissions:
[...]
lstat("/proc/1/task/1/fdinfo", {st_mode=S_IFDIR|0500, st_size=0, ...}) = 0 inotify_add_watch(64, "/proc/1/task/1/fdinfo",
IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE| IN_ONLYDIR|IN_DONT_FOLLOW|IN_EXCL_UNLINK) = -1 EACCES (Permission denied)
[...]
This matches the documented behavior in the inotify_add_watch(2) man page:
ERRORS
EACCES Read access to the given file is not permitted.
After those changes, inotify_add_watch(2) started succeeding despite the current task not having PTRACE_MODE_READ privileges on the target task:
[...]
lstat("/proc/1/task/1/fdinfo", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 inotify_add_watch(64, "/proc/1/task/1/fdinfo",
IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE| IN_ONLYDIR|IN_DONT_FOLLOW|IN_EXCL_UNLINK) = 1757
openat(AT_FDCWD, "/proc/1/task/1/fdinfo",
O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 EACCES (Permission denied)
[...]
This change in behavior broke .NET prior to v7. See the github link below for the v7 commit that inadvertently/quietly (?) fixed .NET after the kernel changes mentioned above.
Return to the old behavior by moving the PTRACE_MODE_READ check out of the file .open operation and into the inode .permission operation:
[...]
lstat("/proc/1/task/1/fdinfo", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 inotify_add_watch(64, "/proc/1/task/1/fdinfo",
IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_CREATE|IN_DELETE| IN_ONLYDIR|IN_DONT_FOLLOW|IN_EXCL_UNLINK) = -1 EACCES (Permission denied)
[...]
Stable-dep-of: 6255da28d4bb ("proc: protect ptrace_may_access() with exec_update_lock (FD links)")
--- fs/proc/fd.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-)
fs/proc/fd.c +20 -22
@@ -72,7 +72,18 @@ static int seq_show(struct seq_file *m, void *v)return 0 ; } -static int proc_fdinfo_access_allowed (struct inode *inode) +static int seq_fdinfo_open (struct inode *inode,struct file *file) +{ +return single_open (file, seq_show, inode); +} + +/** +* Shared /proc/pid/fdinfo and /proc/pid/fdinfo/fd permission helper to ensure +* that the current task has PTRACE_MODE_READ in addition to the normal +* POSIX-like checks. +*/ +static int proc_fdinfo_permission (struct mnt_idmap *idmap,struct inode *inode, +int mask) {bool allowed = false;struct task_struct *task =get_proc_task (inode);
@@ -86,18 +97,13 @@ static int proc_fdinfo_access_allowed(struct inode *inode)if (!allowed)return -EACCES ; -return 0 ; +return generic_permission (idmap, inode, mask); } -static int seq_fdinfo_open (struct inode *inode,struct file *file) -{ -int ret =proc_fdinfo_access_allowed (inode); - -if (ret) -return ret; - -return single_open (file, seq_show, inode); -} +static const struct inode_operations proc_fdinfo_file_inode_operations = { + .permission = proc_fdinfo_permission, + .setattr = proc_setattr, +};static const struct file_operations proc_fdinfo_file_operations = { .open = seq_fdinfo_open,
@@ -339,6 +345,8 @@ static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry, ei =PROC_I (inode); ei->fd = data->fd; + inode->i_op = &proc_fdinfo_file_inode_operations; + inode->i_fop = &proc_fdinfo_file_operations;tid_fd_update_inode (task, inode,0 );
@@ -358,23 +366,13 @@ static int proc_readfdinfo(struct file *file, struct dir_context *ctx) proc_fdinfo_instantiate); } -static int proc_open_fdinfo (struct inode *inode,struct file *file) -{ -int ret =proc_fdinfo_access_allowed (inode); - -if (ret) -return ret; - -return 0 ; -} -const struct inode_operations proc_fdinfo_inode_operations = { .lookup = proc_lookupfdinfo, + .permission = proc_fdinfo_permission, .setattr = proc_setattr, };const struct file_operations proc_fdinfo_operations = { - .open = proc_open_fdinfo, .read = generic_read_dir, .iterate_shared = proc_readfdinfo, .llseek = generic_file_llseek,
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/4 proc: rename proc_setattr to proc_nochmod_setattr
In reply to Sasha LevinFrom: Christoph Hellwig <[email protected]>
[ Upstream commit 690005b0b1e6b567c88b7790e6d90d4d6c9e09cc ]
What is currently proc_setattr is a special version added after the more general procfs ->seattr in commit 6d76fa58b050 ("Don't allow chmod() on the /proc/<pid>/ files"). Give it a name that reflects that to free the proc_setattr name and better describe what is doing.
Stable-dep-of: 6255da28d4bb ("proc: protect ptrace_may_access() with exec_update_lock (FD links)")
--- fs/proc/base.c | 22 +++++++++++----------- fs/proc/fd.c | 12 ++++++------ fs/proc/internal.h | 4 ++-- fs/proc/namespaces.c | 4 ++-- fs/proc/proc_net.c | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-)
fs/proc/base.c +11 -11
@@ -721,7 +721,7 @@ static int proc_fd_access_allowed(struct inode *inode)return allowed; } -int proc_setattr (struct user_namespace *mnt_userns,struct dentry *dentry, +int proc_nochmod_setattr (struct user_namespace *mnt_userns,struct dentry *dentry,struct iattr *attr) {int error;
@@ -795,7 +795,7 @@ static int proc_pid_permission(struct user_namespace *mnt_userns,static const struct inode_operations proc_def_inode_operations = { - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };static int proc_single_show (struct seq_file *m,void *v)
@@ -1868,7 +1868,7 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int bconst struct inode_operations proc_pid_link_inode_operations = { .readlink = proc_pid_readlink, .get_link = proc_pid_get_link, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };
@@ -2316,7 +2316,7 @@ proc_map_files_get_link(struct dentry *dentry,static const struct inode_operations proc_map_files_link_inode_operations = { .readlink = proc_pid_readlink, .get_link = proc_map_files_get_link, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *
@@ -2395,7 +2395,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,static const struct inode_operations proc_map_files_inode_operations = { .lookup = proc_map_files_lookup, .permission = proc_fd_permission, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static int
@@ -2887,7 +2887,7 @@ static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \ static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \ .lookup = proc_##LSM##_attr_dir_lookup, \ .getattr = pid_getattr, \ - .setattr = proc_setattr, \ + .setattr = proc_nochmod_setattr, \ }#ifdef CONFIG_SECURITY_SMACK
@@ -2946,7 +2946,7 @@ static struct dentry *proc_attr_dir_lookup(struct inode *dir,static const struct inode_operations proc_attr_dir_inode_operations = { .lookup = proc_attr_dir_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };#endif
@@ -3403,7 +3403,7 @@ static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *destatic const struct inode_operations proc_tgid_base_inode_operations = { .lookup = proc_tgid_base_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, .permission = proc_pid_permission, };
@@ -3603,7 +3603,7 @@ static int proc_tid_comm_permission(struct user_namespace *mnt_userns, }static const struct inode_operations proc_tid_comm_inode_operations = { - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, .permission = proc_tid_comm_permission, };
@@ -3730,7 +3730,7 @@ static const struct file_operations proc_tid_base_operations = {static const struct inode_operations proc_tid_base_inode_operations = { .lookup = proc_tid_base_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *proc_task_instantiate(struct dentry *dentry,
@@ -3926,7 +3926,7 @@ static int proc_task_getattr(struct user_namespace *mnt_userns,static const struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, .getattr = proc_task_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, .permission = proc_pid_permission, };
fs/proc/fd.c +6 -6
@@ -82,8 +82,8 @@ static int seq_fdinfo_open(struct inode *inode, struct file *file)* that the current task has PTRACE_MODE_READ in addition to the normal * POSIX-like checks. */ -static int proc_fdinfo_permission (struct mnt_idmap *idmap,struct inode *inode, -int mask) +static int proc_fdinfo_permission (struct user_namespace *mnt_userns, +struct inode *inode,int mask) {bool allowed = false;struct task_struct *task =get_proc_task (inode);
@@ -97,12 +97,12 @@ static int proc_fdinfo_permission(struct mnt_idmap *idmap, struct inode *inode,if (!allowed)return -EACCES ; -return generic_permission (idmap, inode, mask); +return generic_permission (mnt_userns, inode, mask); }static const struct inode_operations proc_fdinfo_file_inode_operations = { .permission = proc_fdinfo_permission, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };static const struct file_operations proc_fdinfo_file_operations = {
@@ -328,7 +328,7 @@ int proc_fd_permission(struct user_namespace *mnt_userns,const struct inode_operations proc_fd_inode_operations = { .lookup = proc_lookupfd, .permission = proc_fd_permission, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry,
@@ -369,7 +369,7 @@ static int proc_readfdinfo(struct file *file, struct dir_context *ctx)const struct inode_operations proc_fdinfo_inode_operations = { .lookup = proc_lookupfdinfo, .permission = proc_fdinfo_permission, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };const struct file_operations proc_fdinfo_operations = {
fs/proc/internal.h +2 -2
@@ -178,8 +178,8 @@ extern int proc_pid_statm(struct seq_file *, struct pid_namespace *,extern const struct dentry_operations pid_dentry_operations;extern int pid_getattr (struct user_namespace *,const struct path *,struct kstat *,u32 ,unsigned int ); -extern int proc_setattr (struct user_namespace *,struct dentry *, -struct iattr *); +int proc_nochmod_setattr (struct user_namespace *mnt_userns,struct dentry *dentry, +struct iattr *attr);extern void proc_pid_evict_inode (struct proc_inode *);extern struct inode *proc_pid_make_inode (struct super_block *,struct task_struct *,umode_t );extern void pid_update_inode (struct task_struct *,struct inode *);
fs/proc/namespaces.c +2 -2
@@ -92,7 +92,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflstatic const struct inode_operations proc_ns_link_inode_operations = { .readlink = proc_ns_readlink, .get_link = proc_ns_get_link, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, }; static struct dentry *proc_ns_instantiate(struct dentry *dentry,
@@ -179,5 +179,5 @@ static struct dentry *proc_ns_dir_lookup(struct inode *dir,const struct inode_operations proc_ns_dir_inode_operations = { .lookup = proc_ns_dir_lookup, .getattr = pid_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };
fs/proc/proc_net.c +1 -1
@@ -311,7 +311,7 @@ static int proc_tgid_net_getattr(struct user_namespace *mnt_userns,const struct inode_operations proc_net_inode_operations = { .lookup = proc_tgid_net_lookup, .getattr = proc_tgid_net_getattr, - .setattr = proc_setattr, + .setattr = proc_nochmod_setattr, };static int proc_tgid_net_readdir (struct file *file,struct dir_context *ctx)
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/4 proc: protect ptrace_may_access() with exec_update_lock (FD links)
In reply to Sasha LevinFrom: Jann Horn <[email protected]>
[ Upstream commit 6255da28d4bb5349fe18e84cb043ccd394eba75d ]
proc_pid_get_link() and proc_pid_readlink() currently look up the task from the pid once, then do the ptrace access check on that task, then look up the task from the pid a second time to do the actual access. That's racy in several ways.
To fix it, pass the task to the ->proc_get_link() handler, and instead of proc_fd_access_allowed(), introduce a new helper call_proc_get_link() that looks up and locks the task, does the access check, and calls ->proc_get_link().
--- fs/proc/base.c | 119 ++++++++++++++++++--------------------------- fs/proc/fd.c | 27 +++++----- fs/proc/internal.h | 2 +- 3 files changed, 59 insertions(+), 89 deletions(-)
fs/proc/base.c +47 -72
@@ -218,33 +218,24 @@ static int get_task_root(struct task_struct *task, struct path *root)return result; } -static int proc_cwd_link (struct dentry *dentry,struct path *path) +static int proc_cwd_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task =get_proc_task (d_inode (dentry));int result = -ENOENT ; -if (task) { -task_lock (task); -if (task->fs) { -get_fs_pwd (task->fs, path); - result =0 ; - } -task_unlock (task); -put_task_struct (task); +task_lock (task); +if (task->fs) { +get_fs_pwd (task->fs, path); + result =0 ; } +task_unlock (task);return result; } -static int proc_root_link (struct dentry *dentry,struct path *path) +static int proc_root_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task =get_proc_task (d_inode (dentry)); -int result = -ENOENT ; - -if (task) { - result =get_task_root (task, path); -put_task_struct (task); - } -return result; +return get_task_root (task, path); }/*
@@ -704,23 +695,6 @@ static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns,/* Here the fs part begins */ /************************************************************************/ -/* permission checks */ -static int proc_fd_access_allowed (struct inode *inode) -{ -struct task_struct *task; -int allowed =0 ; -/* Allow access to a task's file descriptors if it is us or we -* may use ptrace attach to the process and find out that -* information. -*/ - task =get_proc_task (inode); -if (task) { - allowed =ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS ); -put_task_struct (task); - } -return allowed; -} -int proc_nochmod_setattr (struct user_namespace *mnt_userns,struct dentry *dentry,struct iattr *attr) {
@@ -1779,16 +1753,12 @@ static const struct file_operations proc_pid_set_comm_operations = { .release = single_release, }; -static int proc_exe_link (struct dentry *dentry,struct path *exe_path) +static int proc_exe_link (struct dentry *dentry,struct path *exe_path, +struct task_struct *task) { -struct task_struct *task;struct file *exe_file; - task =get_proc_task (d_inode (dentry)); -if (!task) -return -ENOENT ; exe_file =get_task_exe_file (task); -put_task_struct (task);if (exe_file) { *exe_path = exe_file->f_path;path_get (&exe_file->f_path);
@@ -1798,26 +1768,42 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)return -ENOENT ; } +static int call_proc_get_link (struct dentry *dentry,struct inode *inode,struct path *path_out) +{ +struct task_struct *task; +int ret; + + task =get_proc_task (inode); +if (!task) +return -ENOENT ; + ret =down_read_killable (&task->signal->exec_update_lock); +if (ret) + goto out_put_task; +if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { + ret = -EACCES ; + goto out; + } + ret =PROC_I (inode)->op.proc_get_link (dentry, path_out, task); + +out: +up_read (&task->signal->exec_update_lock); +out_put_task: +put_task_struct (task); +return ret; +} +static const char *proc_pid_get_link (struct dentry *dentry,struct inode *inode,struct delayed_call *done) {struct path path; -int error = -EACCES ; +int error;if (!dentry)return ERR_PTR (-ECHILD ); - -/* Are we allowed to snoop on the tasks file descriptors? */ -if (!proc_fd_access_allowed (inode)) - goto out; - - error =PROC_I (inode)->op.proc_get_link (dentry, &path); -if (error) - goto out; - - error =nd_jump_link (&path); -out: + error =call_proc_get_link (dentry, inode, &path); +if (!error) + error =nd_jump_link (&path);return ERR_PTR (error); }
@@ -1851,17 +1837,11 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int bstruct inode *inode =d_inode (dentry);struct path path; -/* Are we allowed to snoop on the tasks file descriptors? */ -if (!proc_fd_access_allowed (inode)) - goto out; - - error =PROC_I (inode)->op.proc_get_link (dentry, &path); -if (error) - goto out; - - error =do_proc_readlink (&path, buffer, buflen); -path_put (&path); -out: + error =call_proc_get_link (dentry, inode, &path); +if (!error) { + error =do_proc_readlink (&path, buffer, buflen); +path_put (&path); + }return error; }
@@ -2247,21 +2227,16 @@ static const struct dentry_operations tid_map_files_dentry_operations = { .d_delete = pid_delete_dentry, }; -static int map_files_get_link (struct dentry *dentry,struct path *path) +static int map_files_get_link (struct dentry *dentry,struct path *path, +struct task_struct *task) {unsigned long vm_start, vm_end;struct vm_area_struct *vma; -struct task_struct *task;struct mm_struct *mm;int rc; rc = -ENOENT ; - task =get_proc_task (d_inode (dentry)); -if (!task) - goto out; - mm =get_task_mm (task); -put_task_struct (task);if (!mm) goto out;
fs/proc/fd.c +11 -16
@@ -170,24 +170,19 @@ static const struct dentry_operations tid_fd_dentry_operations = { .d_delete = pid_delete_dentry, }; -static int proc_fd_link (struct dentry *dentry,struct path *path) +static int proc_fd_link (struct dentry *dentry,struct path *path, +struct task_struct *task) { -struct task_struct *task;int ret = -ENOENT ; - - task =get_proc_task (d_inode (dentry)); -if (task) { -unsigned int fd =proc_fd (d_inode (dentry)); -struct file *fd_file; - - fd_file =fget_task (task, fd); -if (fd_file) { - *path = fd_file->f_path; -path_get (&fd_file->f_path); - ret =0 ; -fput (fd_file); - } -put_task_struct (task); +unsigned int fd =proc_fd (d_inode (dentry)); +struct file *fd_file; + + fd_file =fget_task (task, fd); +if (fd_file) { + *path = fd_file->f_path; +path_get (&fd_file->f_path); + ret =0 ; +fput (fd_file); }return ret;
fs/proc/internal.h +1 -1
@@ -97,7 +97,7 @@ extern struct kmem_cache *proc_dir_entry_cache;void pde_free (struct proc_dir_entry *pde);union proc_op { -int (*proc_get_link)(struct dentry *,struct path *); +int (*proc_get_link)(struct dentry *,struct path *,struct task_struct *);int (*proc_show)(struct seq_file *m,struct pid_namespace *ns,struct pid *pid,struct task_struct *task);
Signature · 1 line
2.53.0