RK3368 DDR: new ddr change freq method
[firefly-linux-kernel-4.4.55.git] / kernel / user_namespace.c
index 78009bd5efe6920db34c91e1082e1c4716a956cf..3f2fb33d291aa8739ab09a2f63d090695787c765 100644 (file)
@@ -100,6 +100,11 @@ int create_user_ns(struct cred *new)
        ns->owner = owner;
        ns->group = group;
 
+       /* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
+       mutex_lock(&userns_state_mutex);
+       ns->flags = parent_ns->flags;
+       mutex_unlock(&userns_state_mutex);
+
        set_cred_user_ns(new, ns);
 
        update_mnt_policy(ns);
@@ -809,6 +814,11 @@ static bool new_idmap_permitted(const struct file *file,
                        kuid_t uid = make_kuid(ns->parent, id);
                        if (uid_eq(uid, cred->euid))
                                return true;
+               } else if (cap_setid == CAP_SETGID) {
+                       kgid_t gid = make_kgid(ns->parent, id);
+                       if (!(ns->flags & USERNS_SETGROUPS_ALLOWED) &&
+                           gid_eq(gid, cred->egid))
+                               return true;
                }
        }
 
@@ -827,6 +837,84 @@ static bool new_idmap_permitted(const struct file *file,
        return false;
 }
 
+int proc_setgroups_show(struct seq_file *seq, void *v)
+{
+       struct user_namespace *ns = seq->private;
+       unsigned long userns_flags = ACCESS_ONCE(ns->flags);
+
+       seq_printf(seq, "%s\n",
+                  (userns_flags & USERNS_SETGROUPS_ALLOWED) ?
+                  "allow" : "deny");
+       return 0;
+}
+
+ssize_t proc_setgroups_write(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       struct seq_file *seq = file->private_data;
+       struct user_namespace *ns = seq->private;
+       char kbuf[8], *pos;
+       bool setgroups_allowed;
+       ssize_t ret;
+
+       /* Only allow a very narrow range of strings to be written */
+       ret = -EINVAL;
+       if ((*ppos != 0) || (count >= sizeof(kbuf)))
+               goto out;
+
+       /* What was written? */
+       ret = -EFAULT;
+       if (copy_from_user(kbuf, buf, count))
+               goto out;
+       kbuf[count] = '\0';
+       pos = kbuf;
+
+       /* What is being requested? */
+       ret = -EINVAL;
+       if (strncmp(pos, "allow", 5) == 0) {
+               pos += 5;
+               setgroups_allowed = true;
+       }
+       else if (strncmp(pos, "deny", 4) == 0) {
+               pos += 4;
+               setgroups_allowed = false;
+       }
+       else
+               goto out;
+
+       /* Verify there is not trailing junk on the line */
+       pos = skip_spaces(pos);
+       if (*pos != '\0')
+               goto out;
+
+       ret = -EPERM;
+       mutex_lock(&userns_state_mutex);
+       if (setgroups_allowed) {
+               /* Enabling setgroups after setgroups has been disabled
+                * is not allowed.
+                */
+               if (!(ns->flags & USERNS_SETGROUPS_ALLOWED))
+                       goto out_unlock;
+       } else {
+               /* Permanently disabling setgroups after setgroups has
+                * been enabled by writing the gid_map is not allowed.
+                */
+               if (ns->gid_map.nr_extents != 0)
+                       goto out_unlock;
+               ns->flags &= ~USERNS_SETGROUPS_ALLOWED;
+       }
+       mutex_unlock(&userns_state_mutex);
+
+       /* Report a successful write */
+       *ppos = count;
+       ret = count;
+out:
+       return ret;
+out_unlock:
+       mutex_unlock(&userns_state_mutex);
+       goto out;
+}
+
 bool userns_may_setgroups(const struct user_namespace *ns)
 {
        bool allowed;
@@ -836,6 +924,8 @@ bool userns_may_setgroups(const struct user_namespace *ns)
         * the user namespace has been established.
         */
        allowed = ns->gid_map.nr_extents != 0;
+       /* Is setgroups allowed? */
+       allowed = allowed && (ns->flags & USERNS_SETGROUPS_ALLOWED);
        mutex_unlock(&userns_state_mutex);
 
        return allowed;