Merge tag 'v3.10.64' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / proc / base.c
index 1caa60e5271e76f687f88faae669ad74b0198169..4b6f38b759c66bc687424ee73c4fabff2535a604 100644 (file)
@@ -2648,6 +2648,57 @@ static const struct file_operations proc_projid_map_operations = {
        .llseek         = seq_lseek,
        .release        = proc_id_map_release,
 };
        .llseek         = seq_lseek,
        .release        = proc_id_map_release,
 };
+
+static int proc_setgroups_open(struct inode *inode, struct file *file)
+{
+       struct user_namespace *ns = NULL;
+       struct task_struct *task;
+       int ret;
+
+       ret = -ESRCH;
+       task = get_proc_task(inode);
+       if (task) {
+               rcu_read_lock();
+               ns = get_user_ns(task_cred_xxx(task, user_ns));
+               rcu_read_unlock();
+               put_task_struct(task);
+       }
+       if (!ns)
+               goto err;
+
+       if (file->f_mode & FMODE_WRITE) {
+               ret = -EACCES;
+               if (!ns_capable(ns, CAP_SYS_ADMIN))
+                       goto err_put_ns;
+       }
+
+       ret = single_open(file, &proc_setgroups_show, ns);
+       if (ret)
+               goto err_put_ns;
+
+       return 0;
+err_put_ns:
+       put_user_ns(ns);
+err:
+       return ret;
+}
+
+static int proc_setgroups_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq = file->private_data;
+       struct user_namespace *ns = seq->private;
+       int ret = single_release(inode, file);
+       put_user_ns(ns);
+       return ret;
+}
+
+static const struct file_operations proc_setgroups_operations = {
+       .open           = proc_setgroups_open,
+       .write          = proc_setgroups_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = proc_setgroups_release,
+};
 #endif /* CONFIG_USER_NS */
 
 static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
 #endif /* CONFIG_USER_NS */
 
 static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
@@ -2756,6 +2807,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
        REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
        REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
        REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
        REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
        REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
+       REG("setgroups",  S_IRUGO|S_IWUSR, proc_setgroups_operations),
 #endif
 #ifdef CONFIG_CHECKPOINT_RESTORE
        REG("timers",     S_IRUGO, proc_timers_operations),
 #endif
 #ifdef CONFIG_CHECKPOINT_RESTORE
        REG("timers",     S_IRUGO, proc_timers_operations),
@@ -3109,6 +3161,7 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
        REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
        REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
        REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
        REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
        REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
+       REG("setgroups",  S_IRUGO|S_IWUSR, proc_setgroups_operations),
 #endif
 };
 
 #endif
 };