On Sat, Jul 10, 2021 at 11:21 AM Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote: > > On Thu, Jul 8, 2021 at 8:57 AM Kalesh Singh <kaleshsingh@xxxxxxxxxx> wrote: > > > > The file permissions on the fdinfo dir from were changed from > > S_IRUSR|S_IXUSR to S_IRUGO|S_IXUGO, and a PTRACE_MODE_READ check was > > added for opening the fdinfo files [1]. However, the ptrace permission > > check was not added to the directory, allowing anyone to get the open FD > > numbers by reading the fdinfo directory. > > > > Add the missing ptrace permission check for opening the fdinfo directory. > > The more I look at this, the more I feel like we should look at > instead changing how "get_proc_task()" works. > > That's one of the core functions for /proc, and I wonder if we > couldn't just make it refuse to look up a task that has gone through a > suid execve() since the proc inode was opened. > > I don't think it's basically ever ok to open something for one thread, > and then use it after the thread has gone through a suid thing. > > In fact, I wonder if we could make it even stricter, and go "any exec > at all", but I think a suid exec might be the minimum we should do. > > Then the logic really becomes very simple: we did the permission > checks at open time (like UNIX permission checks should be done), and > "get_proc_task()" basically verifies that "yeah, that open-time > decision is still valid". > > Wouldn't that make a lot of sense? I think checking that the last open is after the last exec works, but there are a few cases I’m not clear on: Process A opens /proc/A/*/<file>. (Given it has the required permissions - checked in open()) Process A Start exec time = T1 Proc inode open time /proc/A/*/<file> = T2 T2 > T1: --> Process A can access /proc/A/*/<file> (FD 4) -- OK Process A does a fork and exec Process B Process B Start exec time = T3 Proc inode open time /proc/A/*/<file> = T2 T2 < T3: --> Process B can’t access /proc/A/*/<file> (by the copied FD 4) -- OK Process B opens /proc/B/*/<file> (Given it has the required permissions - checked in open()) Process B Start exec time = T3 Proc inode open time /proc/B/*/<file> = T4. T4 > T3: --> Process B can access /proc/B/*/<file> (FD 5) -- OK Process A opens /proc/A/*/<file> (Given it has the required permissions - checked in open()) Process A Start exec time = T1 Proc inode open time /proc/A/*/<file> = T5. T5 > T1: --> Process A can access /proc/A/*/<file> (FD 5) -- OK But, Process B Start exec time = T3 Proc inode open time /proc/A/*/<file> = T5. T5 > T3: --> Process B can access /proc/A/*/<file> (by the copied FD 4) -- NOT OK I think for the case above we could add a map to track the inode open times per task at the cost of some added complexity. For tracking the last exec times, I thought we could maybe reuse the task_struct -> struct sched_entity se -> u64 exec_start / sum_exec_runtime as indicators. These are relative to the task and set to 0 on fork. But the inode open time needs to be comparable across tasks in the case of a fork-exec as above. As I understand, we may need a per-task field like last_exec_time, but I’m not sure we want to incur the extra memory overhead for adding more fields to task_struct? Please let me know if my understanding is not correct or if there is something I overlooked here. Thanks, Kalesh > > Linus