|
@@ -631,6 +631,50 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * May current process learn task's sched/cmdline info (for hide_pid_min=1)
|
|
|
+ * or euid/egid (for hide_pid_min=2)?
|
|
|
+ */
|
|
|
+static bool has_pid_permissions(struct pid_namespace *pid,
|
|
|
+ struct task_struct *task,
|
|
|
+ int hide_pid_min)
|
|
|
+{
|
|
|
+ if (pid->hide_pid < hide_pid_min)
|
|
|
+ return true;
|
|
|
+ if (in_group_p(pid->pid_gid))
|
|
|
+ return true;
|
|
|
+ return ptrace_may_access(task, PTRACE_MODE_READ);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int proc_pid_permission(struct inode *inode, int mask)
|
|
|
+{
|
|
|
+ struct pid_namespace *pid = inode->i_sb->s_fs_info;
|
|
|
+ struct task_struct *task;
|
|
|
+ bool has_perms;
|
|
|
+
|
|
|
+ task = get_proc_task(inode);
|
|
|
+ has_perms = has_pid_permissions(pid, task, 1);
|
|
|
+ put_task_struct(task);
|
|
|
+
|
|
|
+ if (!has_perms) {
|
|
|
+ if (pid->hide_pid == 2) {
|
|
|
+ /*
|
|
|
+ * Let's make getdents(), stat(), and open()
|
|
|
+ * consistent with each other. If a process
|
|
|
+ * may not stat() a file, it shouldn't be seen
|
|
|
+ * in procfs at all.
|
|
|
+ */
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -EPERM;
|
|
|
+ }
|
|
|
+ return generic_permission(inode, mask);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
static const struct inode_operations proc_def_inode_operations = {
|
|
|
.setattr = proc_setattr,
|
|
|
};
|
|
@@ -1615,6 +1659,7 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|
|
struct inode *inode = dentry->d_inode;
|
|
|
struct task_struct *task;
|
|
|
const struct cred *cred;
|
|
|
+ struct pid_namespace *pid = dentry->d_sb->s_fs_info;
|
|
|
|
|
|
generic_fillattr(inode, stat);
|
|
|
|
|
@@ -1623,6 +1668,14 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|
|
stat->gid = 0;
|
|
|
task = pid_task(proc_pid(inode), PIDTYPE_PID);
|
|
|
if (task) {
|
|
|
+ if (!has_pid_permissions(pid, task, 2)) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ /*
|
|
|
+ * This doesn't prevent learning whether PID exists,
|
|
|
+ * it only makes getattr() consistent with readdir().
|
|
|
+ */
|
|
|
+ return -ENOENT;
|
|
|
+ }
|
|
|
if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
|
|
|
task_dumpable(task)) {
|
|
|
cred = __task_cred(task);
|
|
@@ -3119,6 +3172,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
|
|
|
.lookup = proc_tgid_base_lookup,
|
|
|
.getattr = pid_getattr,
|
|
|
.setattr = proc_setattr,
|
|
|
+ .permission = proc_pid_permission,
|
|
|
};
|
|
|
|
|
|
static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
|
|
@@ -3322,6 +3376,12 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi
|
|
|
proc_pid_instantiate, iter.task, NULL);
|
|
|
}
|
|
|
|
|
|
+static int fake_filldir(void *buf, const char *name, int namelen,
|
|
|
+ loff_t offset, u64 ino, unsigned d_type)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/* for the /proc/ directory itself, after non-process stuff has been done */
|
|
|
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
|
{
|
|
@@ -3329,6 +3389,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
|
struct task_struct *reaper;
|
|
|
struct tgid_iter iter;
|
|
|
struct pid_namespace *ns;
|
|
|
+ filldir_t __filldir;
|
|
|
|
|
|
if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET)
|
|
|
goto out_no_task;
|
|
@@ -3350,8 +3411,13 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
|
|
|
for (iter = next_tgid(ns, iter);
|
|
|
iter.task;
|
|
|
iter.tgid += 1, iter = next_tgid(ns, iter)) {
|
|
|
+ if (has_pid_permissions(ns, iter.task, 2))
|
|
|
+ __filldir = filldir;
|
|
|
+ else
|
|
|
+ __filldir = fake_filldir;
|
|
|
+
|
|
|
filp->f_pos = iter.tgid + TGID_OFFSET;
|
|
|
- if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) {
|
|
|
+ if (proc_pid_fill_cache(filp, dirent, __filldir, iter) < 0) {
|
|
|
put_task_struct(iter.task);
|
|
|
goto out;
|
|
|
}
|
|
@@ -3686,6 +3752,7 @@ static const struct inode_operations proc_task_inode_operations = {
|
|
|
.lookup = proc_task_lookup,
|
|
|
.getattr = proc_task_getattr,
|
|
|
.setattr = proc_setattr,
|
|
|
+ .permission = proc_pid_permission,
|
|
|
};
|
|
|
|
|
|
static const struct file_operations proc_task_operations = {
|