|
@@ -19,6 +19,96 @@
|
|
|
#include <linux/fsnotify.h>
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
|
+
|
|
|
+int
|
|
|
+vfs_setxattr(struct dentry *dentry, char *name, void *value,
|
|
|
+ size_t size, int flags)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
+ error = security_inode_setxattr(dentry, name, value, size, flags);
|
|
|
+ if (error)
|
|
|
+ goto out;
|
|
|
+ error = -EOPNOTSUPP;
|
|
|
+ if (inode->i_op->setxattr) {
|
|
|
+ error = inode->i_op->setxattr(dentry, name, value, size, flags);
|
|
|
+ if (!error) {
|
|
|
+ fsnotify_xattr(dentry);
|
|
|
+ security_inode_post_setxattr(dentry, name, value,
|
|
|
+ size, flags);
|
|
|
+ }
|
|
|
+ } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
|
|
|
+ sizeof XATTR_SECURITY_PREFIX - 1)) {
|
|
|
+ const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
|
|
|
+ error = security_inode_setsecurity(inode, suffix, value,
|
|
|
+ size, flags);
|
|
|
+ if (!error)
|
|
|
+ fsnotify_xattr(dentry);
|
|
|
+ }
|
|
|
+out:
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(vfs_setxattr);
|
|
|
+
|
|
|
+ssize_t
|
|
|
+vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ error = security_inode_getxattr(dentry, name);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ if (inode->i_op->getxattr)
|
|
|
+ error = inode->i_op->getxattr(dentry, name, value, size);
|
|
|
+ else
|
|
|
+ error = -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (!strncmp(name, XATTR_SECURITY_PREFIX,
|
|
|
+ sizeof XATTR_SECURITY_PREFIX - 1)) {
|
|
|
+ const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
|
|
|
+ int ret = security_inode_getsecurity(inode, suffix, value,
|
|
|
+ size, error);
|
|
|
+ /*
|
|
|
+ * Only overwrite the return value if a security module
|
|
|
+ * is actually active.
|
|
|
+ */
|
|
|
+ if (ret != -EOPNOTSUPP)
|
|
|
+ error = ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return error;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(vfs_getxattr);
|
|
|
+
|
|
|
+int
|
|
|
+vfs_removexattr(struct dentry *dentry, char *name)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ if (!inode->i_op->removexattr)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ error = security_inode_removexattr(dentry, name);
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
+ error = inode->i_op->removexattr(dentry, name);
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
+
|
|
|
+ if (!error)
|
|
|
+ fsnotify_xattr(dentry);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(vfs_removexattr);
|
|
|
+
|
|
|
+
|
|
|
/*
|
|
|
* Extended attribute SET operations
|
|
|
*/
|
|
@@ -51,29 +141,7 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- mutex_lock(&d->d_inode->i_mutex);
|
|
|
- error = security_inode_setxattr(d, kname, kvalue, size, flags);
|
|
|
- if (error)
|
|
|
- goto out;
|
|
|
- error = -EOPNOTSUPP;
|
|
|
- if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
|
|
|
- error = d->d_inode->i_op->setxattr(d, kname, kvalue,
|
|
|
- size, flags);
|
|
|
- if (!error) {
|
|
|
- fsnotify_xattr(d);
|
|
|
- security_inode_post_setxattr(d, kname, kvalue,
|
|
|
- size, flags);
|
|
|
- }
|
|
|
- } else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
|
|
|
- sizeof XATTR_SECURITY_PREFIX - 1)) {
|
|
|
- const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
|
|
|
- error = security_inode_setsecurity(d->d_inode, suffix, kvalue,
|
|
|
- size, flags);
|
|
|
- if (!error)
|
|
|
- fsnotify_xattr(d);
|
|
|
- }
|
|
|
-out:
|
|
|
- mutex_unlock(&d->d_inode->i_mutex);
|
|
|
+ error = vfs_setxattr(d, kname, kvalue, size, flags);
|
|
|
kfree(kvalue);
|
|
|
return error;
|
|
|
}
|
|
@@ -147,22 +215,7 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- error = security_inode_getxattr(d, kname);
|
|
|
- if (error)
|
|
|
- goto out;
|
|
|
- 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);
|
|
|
-
|
|
|
- if (!strncmp(kname, XATTR_SECURITY_PREFIX,
|
|
|
- sizeof XATTR_SECURITY_PREFIX - 1)) {
|
|
|
- const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
|
|
|
- int rv = security_inode_getsecurity(d->d_inode, suffix, kvalue,
|
|
|
- size, error);
|
|
|
- /* Security module active: overwrite error value */
|
|
|
- if (rv != -EOPNOTSUPP)
|
|
|
- error = rv;
|
|
|
- }
|
|
|
+ error = vfs_getxattr(d, kname, kvalue, size);
|
|
|
if (error > 0) {
|
|
|
if (size && copy_to_user(value, kvalue, error))
|
|
|
error = -EFAULT;
|
|
@@ -171,7 +224,6 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
|
|
|
than XATTR_SIZE_MAX bytes. Not possible. */
|
|
|
error = -E2BIG;
|
|
|
}
|
|
|
-out:
|
|
|
kfree(kvalue);
|
|
|
return error;
|
|
|
}
|
|
@@ -318,19 +370,7 @@ removexattr(struct dentry *d, char __user *name)
|
|
|
if (error < 0)
|
|
|
return error;
|
|
|
|
|
|
- error = -EOPNOTSUPP;
|
|
|
- if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
|
|
|
- error = security_inode_removexattr(d, kname);
|
|
|
- if (error)
|
|
|
- goto out;
|
|
|
- mutex_lock(&d->d_inode->i_mutex);
|
|
|
- error = d->d_inode->i_op->removexattr(d, kname);
|
|
|
- mutex_unlock(&d->d_inode->i_mutex);
|
|
|
- if (!error)
|
|
|
- fsnotify_xattr(d);
|
|
|
- }
|
|
|
-out:
|
|
|
- return error;
|
|
|
+ return vfs_removexattr(d, kname);
|
|
|
}
|
|
|
|
|
|
asmlinkage long
|