On Thu, Dec 03, 2020 at 04:02:12PM -0800, Stephen Brennan wrote: > -void pid_update_inode(struct task_struct *task, struct inode *inode) > +static int do_pid_update_inode(struct task_struct *task, struct inode *inode, > + unsigned int flags) I'm really nitpicking here, but this function only _updates_ the inode if flags says it should. So I was thinking something like this (compile tested only). I'd really appreocate feedback from someone like Casey or Stephen on what they need for their security modules. diff --git a/fs/proc/base.c b/fs/proc/base.c index b362523a9829..771f330bfce7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1968,6 +1968,25 @@ void pid_update_inode(struct task_struct *task, struct inode *inode) security_task_to_inode(task, inode); } +/* See if we can avoid the above call. Assumes RCU lock held */ +static bool inode_needs_pid_update(struct task_struct *task, + const struct inode *inode) +{ + kuid_t uid; + kgid_t gid; + + if (inode->i_mode & (S_ISUID | S_ISGID)) + return true; + task_dump_owner(task, inode->i_mode, &uid, &gid); + if (!uid_eq(uid, inode->i_uid) || !gid_eq(gid, inode->i_gid)) + return true; + /* + * XXX: Do we need to call the security system here to see if + * there's a pending update? + */ + return false; +} + /* * Rewrite the inode's ownerships here because the owning task may have * performed a setuid(), etc. @@ -1978,8 +1997,15 @@ static int pid_revalidate(struct dentry *dentry, unsigned int flags) struct inode *inode; struct task_struct *task; - if (flags & LOOKUP_RCU) + if (flags & LOOKUP_RCU) { + inode = d_inode_rcu(dentry); + task = pid_task(proc_pid(inode), PIDTYPE_PID); + if (!task) + return 0; + if (!inode_needs_pid_update(task, inode)) + return 1; return -ECHILD; + } inode = d_inode(dentry); task = get_proc_task(inode);