Linux 6.9-rc1
[linux-2.6-microblaze.git] / kernel / capability.c
index 765194f..dac4df7 100644 (file)
 #include <linux/user_namespace.h>
 #include <linux/uaccess.h>
 
-/*
- * Leveraged for setting/resetting capabilities
- */
-
-const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
-EXPORT_SYMBOL(__cap_empty_set);
-
 int file_caps_enabled = 1;
 
 static int __init file_caps_disable(char *str)
@@ -119,7 +112,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
        int ret;
 
        if (pid && (pid != task_pid_vnr(current))) {
-               struct task_struct *target;
+               const struct task_struct *target;
 
                rcu_read_lock();
 
@@ -151,6 +144,7 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
        pid_t pid;
        unsigned tocopy;
        kernel_cap_t pE, pI, pP;
+       struct __user_cap_data_struct kdata[2];
 
        ret = cap_validate_magic(header, &tocopy);
        if ((dataptr == NULL) || (ret != 0))
@@ -163,42 +157,46 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
                return -EINVAL;
 
        ret = cap_get_target_pid(pid, &pE, &pI, &pP);
-       if (!ret) {
-               struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
-               unsigned i;
-
-               for (i = 0; i < tocopy; i++) {
-                       kdata[i].effective = pE.cap[i];
-                       kdata[i].permitted = pP.cap[i];
-                       kdata[i].inheritable = pI.cap[i];
-               }
-
-               /*
-                * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S,
-                * we silently drop the upper capabilities here. This
-                * has the effect of making older libcap
-                * implementations implicitly drop upper capability
-                * bits when they perform a: capget/modify/capset
-                * sequence.
-                *
-                * This behavior is considered fail-safe
-                * behavior. Upgrading the application to a newer
-                * version of libcap will enable access to the newer
-                * capabilities.
-                *
-                * An alternative would be to return an error here
-                * (-ERANGE), but that causes legacy applications to
-                * unexpectedly fail; the capget/modify/capset aborts
-                * before modification is attempted and the application
-                * fails.
-                */
-               if (copy_to_user(dataptr, kdata, tocopy
-                                * sizeof(struct __user_cap_data_struct))) {
-                       return -EFAULT;
-               }
-       }
+       if (ret)
+               return ret;
 
-       return ret;
+       /*
+        * Annoying legacy format with 64-bit capabilities exposed
+        * as two sets of 32-bit fields, so we need to split the
+        * capability values up.
+        */
+       kdata[0].effective   = pE.val; kdata[1].effective   = pE.val >> 32;
+       kdata[0].permitted   = pP.val; kdata[1].permitted   = pP.val >> 32;
+       kdata[0].inheritable = pI.val; kdata[1].inheritable = pI.val >> 32;
+
+       /*
+        * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S,
+        * we silently drop the upper capabilities here. This
+        * has the effect of making older libcap
+        * implementations implicitly drop upper capability
+        * bits when they perform a: capget/modify/capset
+        * sequence.
+        *
+        * This behavior is considered fail-safe
+        * behavior. Upgrading the application to a newer
+        * version of libcap will enable access to the newer
+        * capabilities.
+        *
+        * An alternative would be to return an error here
+        * (-ERANGE), but that causes legacy applications to
+        * unexpectedly fail; the capget/modify/capset aborts
+        * before modification is attempted and the application
+        * fails.
+        */
+       if (copy_to_user(dataptr, kdata, tocopy * sizeof(kdata[0])))
+               return -EFAULT;
+
+       return 0;
+}
+
+static kernel_cap_t mk_kernel_cap(u32 low, u32 high)
+{
+       return (kernel_cap_t) { (low | ((u64)high << 32)) & CAP_VALID_MASK };
 }
 
 /**
@@ -221,8 +219,8 @@ SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
  */
 SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
 {
-       struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
-       unsigned i, tocopy, copybytes;
+       struct __user_cap_data_struct kdata[2] = { { 0, }, };
+       unsigned tocopy, copybytes;
        kernel_cap_t inheritable, permitted, effective;
        struct cred *new;
        int ret;
@@ -246,21 +244,9 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
        if (copy_from_user(&kdata, data, copybytes))
                return -EFAULT;
 
-       for (i = 0; i < tocopy; i++) {
-               effective.cap[i] = kdata[i].effective;
-               permitted.cap[i] = kdata[i].permitted;
-               inheritable.cap[i] = kdata[i].inheritable;
-       }
-       while (i < _KERNEL_CAPABILITY_U32S) {
-               effective.cap[i] = 0;
-               permitted.cap[i] = 0;
-               inheritable.cap[i] = 0;
-               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;
+       effective   = mk_kernel_cap(kdata[0].effective,   kdata[1].effective);
+       permitted   = mk_kernel_cap(kdata[0].permitted,   kdata[1].permitted);
+       inheritable = mk_kernel_cap(kdata[0].inheritable, kdata[1].inheritable);
 
        new = prepare_creds();
        if (!new)
@@ -481,20 +467,22 @@ EXPORT_SYMBOL(file_ns_capable);
 /**
  * privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode?
  * @ns: The user namespace in question
+ * @idmap: idmap of the mount @inode was found from
  * @inode: The inode in question
  *
  * Return true if the inode uid and gid are within the namespace.
  */
 bool privileged_wrt_inode_uidgid(struct user_namespace *ns,
-                                struct user_namespace *mnt_userns,
+                                struct mnt_idmap *idmap,
                                 const struct inode *inode)
 {
-       return kuid_has_mapping(ns, i_uid_into_mnt(mnt_userns, inode)) &&
-              kgid_has_mapping(ns, i_gid_into_mnt(mnt_userns, inode));
+       return vfsuid_has_mapping(ns, i_uid_into_vfsuid(idmap, inode)) &&
+              vfsgid_has_mapping(ns, i_gid_into_vfsgid(idmap, inode));
 }
 
 /**
  * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
+ * @idmap: idmap of the mount @inode was found from
  * @inode: The inode in question
  * @cap: The capability in question
  *
@@ -502,13 +490,13 @@ bool privileged_wrt_inode_uidgid(struct user_namespace *ns,
  * its own user namespace and that the given inode's uid and gid are
  * mapped into the current user namespace.
  */
-bool capable_wrt_inode_uidgid(struct user_namespace *mnt_userns,
+bool capable_wrt_inode_uidgid(struct mnt_idmap *idmap,
                              const struct inode *inode, int cap)
 {
        struct user_namespace *ns = current_user_ns();
 
        return ns_capable(ns, cap) &&
-              privileged_wrt_inode_uidgid(ns, mnt_userns, inode);
+              privileged_wrt_inode_uidgid(ns, idmap, inode);
 }
 EXPORT_SYMBOL(capable_wrt_inode_uidgid);