if (size) {
                if (size > XATTR_SIZE_MAX)
                        size = XATTR_SIZE_MAX;
-               kvalue = kmalloc(size, GFP_KERNEL);
+               kvalue = kzalloc(size, GFP_KERNEL);
                if (!kvalue)
                        return -ENOMEM;
        }
        error = -EOPNOTSUPP;
        if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
                error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
-       else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
-                         sizeof XATTR_SECURITY_PREFIX - 1)) {
+
+       if (!strncmp(kname, XATTR_SECURITY_PREFIX,
+                    sizeof XATTR_SECURITY_PREFIX - 1)) {
                const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
-               error = security_inode_getsecurity(d->d_inode, suffix, kvalue,
-                                                  size);
+               int rv = security_inode_getsecurity(d->d_inode, suffix, kvalue,
+                                                   size, error);
+               /* Security module active: overwrite error value */
+               if (rv != -EOPNOTSUPP)
+                       error = rv;
        }
        if (error > 0) {
                if (size && copy_to_user(value, kvalue, error))
 
  *     NULL to request the size of the buffer required.  @size indicates
  *     the size of @buffer in bytes.  Note that @name is the remainder
  *     of the attribute name after the security. prefix has been removed.
+ *     @err is the return value from the preceding fs getxattr call,
+ *     and can be used by the security module to determine whether it
+ *     should try and canonicalize the attribute value.
  *     Return number of bytes used/required on success.
  * @inode_setsecurity:
  *     Set the security label associated with @name for @inode from the
        int (*inode_getxattr) (struct dentry *dentry, char *name);
        int (*inode_listxattr) (struct dentry *dentry);
        int (*inode_removexattr) (struct dentry *dentry, char *name);
-       int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size);
+       int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size, int err);
        int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
        int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
 
        return security_ops->inode_removexattr (dentry, name);
 }
 
-static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
+static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
        if (unlikely (IS_PRIVATE (inode)))
                return 0;
-       return security_ops->inode_getsecurity(inode, name, buffer, size);
+       return security_ops->inode_getsecurity(inode, name, buffer, size, err);
 }
 
 static inline int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
        return cap_inode_removexattr(dentry, name);
 }
 
-static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
+static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
        return -EOPNOTSUPP;
 }
 
        return 0;
 }
 
-static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
+static int dummy_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
        return -EOPNOTSUPP;
 }
 
        struct inode *inode = dentry->d_inode;
        struct superblock_security_struct *sbsec = inode->i_sb->s_security;
 
-       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
-               return -EOPNOTSUPP;
-
        return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
 }
 
        return -EACCES;
 }
 
-static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
+/*
+ * 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.
+ *
+ * Permission check is handled by selinux_inode_getxattr hook.
+ */
+static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
        struct inode_security_struct *isec = inode->i_security;
        char *context;
        unsigned len;
        int rc;
 
-       /* Permission check handled by selinux_inode_getxattr hook.*/
-
-       if (strcmp(name, XATTR_SELINUX_SUFFIX))
-               return -EOPNOTSUPP;
+       if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
+               rc = -EOPNOTSUPP;
+               goto out;
+       }
 
        rc = security_sid_to_context(isec->sid, &context, &len);
        if (rc)
-               return rc;
+               goto out;
 
+       /* Probe for required buffer size */
        if (!buffer || !size) {
-               kfree(context);
-               return len;
+               rc = len;
+               goto out_free;
        }
+
        if (size < len) {
-               kfree(context);
-               return -ERANGE;
+               rc = -ERANGE;
+               goto out_free;
+       }
+
+       if (err > 0) {
+               if ((len == err) && !(memcmp(context, buffer, len))) {
+                       /* Don't need to canonicalize value */
+                       rc = err;
+                       goto out_free;
+               }
+               memset(buffer, 0, size);
        }
        memcpy(buffer, context, len);
+       rc = len;
+out_free:
        kfree(context);
-       return len;
+out:
+       return rc;
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,