Skip to content

Commit 0a960ba

Browse files
tyhicksbrauner
authored andcommitted
proc: Move fdinfo PTRACE_MODE_READ check into the inode .permission operation
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 7bc3fa0 ("procfs: allow reading fdinfo with PTRACE_MODE_READ") - commit 1927e49 ("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) [...] Reported-by: Kevin Parsons (Microsoft) <[email protected]> Link: dotnet/runtime@89e5469 Link: https://stackoverflow.com/questions/75379065/start-self-contained-net6-build-exe-as-service-on-raspbian-system-unauthorizeda Fixes: 7bc3fa0 ("procfs: allow reading fdinfo with PTRACE_MODE_READ") Cc: [email protected] Cc: Christian Brauner <[email protected]> Cc: Christian König <[email protected]> Cc: Jann Horn <[email protected]> Cc: Kalesh Singh <[email protected]> Cc: Hardik Garg <[email protected]> Cc: Allen Pais <[email protected]> Signed-off-by: Tyler Hicks (Microsoft) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 55394d2 commit 0a960ba

File tree

1 file changed

+20
-22
lines changed

1 file changed

+20
-22
lines changed

fs/proc/fd.c

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,18 @@ static int seq_show(struct seq_file *m, void *v)
7474
return 0;
7575
}
7676

77-
static int proc_fdinfo_access_allowed(struct inode *inode)
77+
static int seq_fdinfo_open(struct inode *inode, struct file *file)
78+
{
79+
return single_open(file, seq_show, inode);
80+
}
81+
82+
/**
83+
* Shared /proc/pid/fdinfo and /proc/pid/fdinfo/fd permission helper to ensure
84+
* that the current task has PTRACE_MODE_READ in addition to the normal
85+
* POSIX-like checks.
86+
*/
87+
static int proc_fdinfo_permission(struct mnt_idmap *idmap, struct inode *inode,
88+
int mask)
7889
{
7990
bool allowed = false;
8091
struct task_struct *task = get_proc_task(inode);
@@ -88,18 +99,13 @@ static int proc_fdinfo_access_allowed(struct inode *inode)
8899
if (!allowed)
89100
return -EACCES;
90101

91-
return 0;
102+
return generic_permission(idmap, inode, mask);
92103
}
93104

94-
static int seq_fdinfo_open(struct inode *inode, struct file *file)
95-
{
96-
int ret = proc_fdinfo_access_allowed(inode);
97-
98-
if (ret)
99-
return ret;
100-
101-
return single_open(file, seq_show, inode);
102-
}
105+
static const struct inode_operations proc_fdinfo_file_inode_operations = {
106+
.permission = proc_fdinfo_permission,
107+
.setattr = proc_setattr,
108+
};
103109

104110
static const struct file_operations proc_fdinfo_file_operations = {
105111
.open = seq_fdinfo_open,
@@ -388,6 +394,8 @@ static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry,
388394
ei = PROC_I(inode);
389395
ei->fd = data->fd;
390396

397+
inode->i_op = &proc_fdinfo_file_inode_operations;
398+
391399
inode->i_fop = &proc_fdinfo_file_operations;
392400
tid_fd_update_inode(task, inode, 0);
393401

@@ -407,23 +415,13 @@ static int proc_readfdinfo(struct file *file, struct dir_context *ctx)
407415
proc_fdinfo_instantiate);
408416
}
409417

410-
static int proc_open_fdinfo(struct inode *inode, struct file *file)
411-
{
412-
int ret = proc_fdinfo_access_allowed(inode);
413-
414-
if (ret)
415-
return ret;
416-
417-
return 0;
418-
}
419-
420418
const struct inode_operations proc_fdinfo_inode_operations = {
421419
.lookup = proc_lookupfdinfo,
420+
.permission = proc_fdinfo_permission,
422421
.setattr = proc_setattr,
423422
};
424423

425424
const struct file_operations proc_fdinfo_operations = {
426-
.open = proc_open_fdinfo,
427425
.read = generic_read_dir,
428426
.iterate_shared = proc_readfdinfo,
429427
.llseek = generic_file_llseek,

0 commit comments

Comments
 (0)