SELinux: enable processes with mac_admin to get the raw inode contexts
[pandora-kernel.git] / security / selinux / hooks.c
index 4be1563..91b666a 100644 (file)
@@ -2754,9 +2754,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
 }
 
 /*
- * Copy the in-core inode security context value to the user.  If the
- * getxattr() prior to this succeeded, check to see if we need to
- * canonicalize the value to be finally returned to the user.
+ * Copy the inode security context value to the user.
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
@@ -2765,12 +2763,33 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
        u32 size;
        int error;
        char *context = NULL;
+       struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec = inode->i_security;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
-       error = security_sid_to_context(isec->sid, &context, &size);
+       /*
+        * If the caller has CAP_MAC_ADMIN, then get the raw context
+        * value even if it is not defined by current policy; otherwise,
+        * use the in-core value under current policy.
+        * Use the non-auditing forms of the permission checks since
+        * getxattr may be called by unprivileged processes commonly
+        * and lack of permission just means that we fall back to the
+        * in-core context value, not a denial.
+        */
+       error = secondary_ops->capable(current, CAP_MAC_ADMIN);
+       if (!error)
+               error = avc_has_perm_noaudit(tsec->sid, tsec->sid,
+                                            SECCLASS_CAPABILITY2,
+                                            CAPABILITY2__MAC_ADMIN,
+                                            0,
+                                            NULL);
+       if (!error)
+               error = security_sid_to_context_force(isec->sid, &context,
+                                                     &size);
+       else
+               error = security_sid_to_context(isec->sid, &context, &size);
        if (error)
                return error;
        error = size;