ARM64: dts: rockchip: rk3399: set dummy_cpll and dummy_vpll as fixed clk
[firefly-linux-kernel-4.4.55.git] / kernel / capability.c
index f6c2ce5701e1c3c723d03e3d917c62f584c3a074..4984e1f552ebfb97fa460b527b35c67ebd0f324d 100644 (file)
@@ -7,6 +7,8 @@
  * 30 May 2002:        Cleanup, Robert M. Love <rml@tech9.net>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/audit.h>
 #include <linux/capability.h>
 #include <linux/mm.h>
@@ -22,7 +24,6 @@
  */
 
 const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
-
 EXPORT_SYMBOL(__cap_empty_set);
 
 int file_caps_enabled = 1;
@@ -34,6 +35,7 @@ static int __init file_caps_disable(char *str)
 }
 __setup("no_file_caps", file_caps_disable);
 
+#ifdef CONFIG_MULTIUSER
 /*
  * More recent versions of libcap are available from:
  *
@@ -42,15 +44,10 @@ __setup("no_file_caps", file_caps_disable);
 
 static void warn_legacy_capability_use(void)
 {
-       static int warned;
-       if (!warned) {
-               char name[sizeof(current->comm)];
-
-               printk(KERN_INFO "warning: `%s' uses 32-bit capabilities"
-                      " (legacy support in use)\n",
-                      get_task_comm(name, current));
-               warned = 1;
-       }
+       char name[sizeof(current->comm)];
+
+       pr_info_once("warning: `%s' uses 32-bit capabilities (legacy support in use)\n",
+                    get_task_comm(name, current));
 }
 
 /*
@@ -71,16 +68,10 @@ static void warn_legacy_capability_use(void)
 
 static void warn_deprecated_v2(void)
 {
-       static int warned;
-
-       if (!warned) {
-               char name[sizeof(current->comm)];
+       char name[sizeof(current->comm)];
 
-               printk(KERN_INFO "warning: `%s' uses deprecated v2"
-                      " capabilities in a way that may be insecure.\n",
-                      get_task_comm(name, current));
-               warned = 1;
-       }
+       pr_info_once("warning: `%s' uses deprecated v2 capabilities in a way that may be insecure\n",
+                    get_task_comm(name, current));
 }
 
 /*
@@ -198,7 +189,7 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
                 *
                 * An alternative would be to return an error here
                 * (-ERANGE), but that causes legacy applications to
-                * unexpectidly fail; the capget/modify/capset aborts
+                * unexpectedly fail; the capget/modify/capset aborts
                 * before modification is attempted and the application
                 * fails.
                 */
@@ -268,6 +259,10 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
                i++;
        }
 
+       effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+       permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+       inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+
        new = prepare_creds();
        if (!new)
                return -ENOMEM;
@@ -277,7 +272,7 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
        if (ret < 0)
                goto error;
 
-       audit_log_capset(pid, new, current_cred());
+       audit_log_capset(new, current_cred());
 
        return commit_creds(new);
 
@@ -366,6 +361,24 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
        return has_ns_capability_noaudit(t, &init_user_ns, cap);
 }
 
+static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
+{
+       int capable;
+
+       if (unlikely(!cap_valid(cap))) {
+               pr_crit("capable() called with invalid cap=%u\n", cap);
+               BUG();
+       }
+
+       capable = audit ? security_capable(current_cred(), ns, cap) :
+                         security_capable_noaudit(current_cred(), ns, cap);
+       if (capable == 0) {
+               current->flags |= PF_SUPERPRIV;
+               return true;
+       }
+       return false;
+}
+
 /**
  * ns_capable - Determine if the current task has a superior capability in effect
  * @ns:  The usernamespace we want the capability in
@@ -379,19 +392,45 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
  */
 bool ns_capable(struct user_namespace *ns, int cap)
 {
-       if (unlikely(!cap_valid(cap))) {
-               printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
-               BUG();
-       }
-
-       if (security_capable(current_cred(), ns, cap) == 0) {
-               current->flags |= PF_SUPERPRIV;
-               return true;
-       }
-       return false;
+       return ns_capable_common(ns, cap, true);
 }
 EXPORT_SYMBOL(ns_capable);
 
+/**
+ * ns_capable_noaudit - Determine if the current task has a superior capability
+ * (unaudited) in effect
+ * @ns:  The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool ns_capable_noaudit(struct user_namespace *ns, int cap)
+{
+       return ns_capable_common(ns, cap, false);
+}
+EXPORT_SYMBOL(ns_capable_noaudit);
+
+/**
+ * capable - Determine if the current task has a superior capability in effect
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool capable(int cap)
+{
+       return ns_capable(&init_user_ns, cap);
+}
+EXPORT_SYMBOL(capable);
+#endif /* CONFIG_MULTIUSER */
+
 /**
  * file_ns_capable - Determine if the file's opener had a capability in effect
  * @file:  The file we want to check
@@ -404,7 +443,8 @@ EXPORT_SYMBOL(ns_capable);
  * This does not set PF_SUPERPRIV because the caller may not
  * actually be privileged.
  */
-bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap)
+bool file_ns_capable(const struct file *file, struct user_namespace *ns,
+                    int cap)
 {
        if (WARN_ON_ONCE(!cap_valid(cap)))
                return false;
@@ -417,50 +457,51 @@ bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap
 EXPORT_SYMBOL(file_ns_capable);
 
 /**
- * capable - Determine if the current task has a superior capability in effect
- * @cap: The capability to be tested for
- *
- * Return true if the current task has the given superior capability currently
- * available for use, false if not.
+ * privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode?
+ * @ns: The user namespace in question
+ * @inode: The inode in question
  *
- * This sets PF_SUPERPRIV on the task if the capability is available on the
- * assumption that it's about to be used.
+ * Return true if the inode uid and gid are within the namespace.
  */
-bool capable(int cap)
+bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode)
 {
-       return ns_capable(&init_user_ns, cap);
+       return kuid_has_mapping(ns, inode->i_uid) &&
+               kgid_has_mapping(ns, inode->i_gid);
 }
-EXPORT_SYMBOL(capable);
 
 /**
- * nsown_capable - Check superior capability to one's own user_ns
+ * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
+ * @inode: The inode in question
  * @cap: The capability in question
  *
- * Return true if the current task has the given superior capability
- * targeted at its own user namespace.
+ * Return true if the current task has the given capability targeted at
+ * its own user namespace and that the given inode's uid and gid are
+ * mapped into the current user namespace.
  */
-bool nsown_capable(int cap)
+bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
 {
-       return ns_capable(current_user_ns(), cap);
+       struct user_namespace *ns = current_user_ns();
+
+       return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
 }
+EXPORT_SYMBOL(capable_wrt_inode_uidgid);
 
 /**
- * inode_capable - Check superior capability over inode
- * @inode: The inode in question
- * @cap: The capability in question
- *
- * Return true if the current task has the given superior capability
- * targeted at it's own user namespace and that the given inode is owned
- * by the current user namespace or a child namespace.
- *
- * Currently we check to see if an inode is owned by the current
- * user namespace by seeing if the inode's owner maps into the
- * current user namespace.
+ * ptracer_capable - Determine if the ptracer holds CAP_SYS_PTRACE in the namespace
+ * @tsk: The task that may be ptraced
+ * @ns: The user namespace to search for CAP_SYS_PTRACE in
  *
+ * Return true if the task that is ptracing the current task had CAP_SYS_PTRACE
+ * in the specified user namespace.
  */
-bool inode_capable(const struct inode *inode, int cap)
+bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
 {
-       struct user_namespace *ns = current_user_ns();
-
-       return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid);
+       int ret = 0;  /* An absent tracer adds no restrictions */
+       const struct cred *cred;
+       rcu_read_lock();
+       cred = rcu_dereference(tsk->ptracer_cred);
+       if (cred)
+               ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE);
+       rcu_read_unlock();
+       return (ret == 0);
 }