diff options
-rw-r--r-- | fs/jfs/xattr.c | 15 | ||||
-rw-r--r-- | fs/xattr.c | 61 | ||||
-rw-r--r-- | include/linux/xattr.h | 15 |
3 files changed, 72 insertions, 19 deletions
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 23aa5066b5a4..9dde36a1eb5d 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c @@ -83,21 +83,6 @@ struct ea_buffer { #define EA_NEW 0x0004 #define EA_MALLOC 0x0008 -/* Namespaces */ -#define XATTR_SYSTEM_PREFIX "system." -#define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1) - -#define XATTR_USER_PREFIX "user." -#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) - -#define XATTR_OS2_PREFIX "os2." -#define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1) - -/* XATTR_SECURITY_PREFIX is defined in include/linux/xattr.h */ -#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) - -#define XATTR_TRUSTED_PREFIX "trusted." -#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) /* * These three routines are used to recognize on-disk extended attributes diff --git a/fs/xattr.c b/fs/xattr.c index fee804e69a9a..80eca7d3d69f 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -20,6 +20,47 @@ #include <asm/uaccess.h> +/* + * Check permissions for extended attribute access. This is a bit complicated + * because different namespaces have very different rules. + */ +static int +xattr_permission(struct inode *inode, const char *name, int mask) +{ + /* + * We can never set or remove an extended attribute on a read-only + * filesystem or on an immutable / append-only inode. + */ + if (mask & MAY_WRITE) { + if (IS_RDONLY(inode)) + return -EROFS; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + return -EPERM; + } + + /* + * No restriction for security.* and system.* from the VFS. Decision + * on these is left to the underlying filesystem / security module. + */ + if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || + !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) + return 0; + + /* + * The trusted.* namespace can only accessed by a privilegued user. + */ + if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) + return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM); + + if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { + if (!S_ISREG(inode->i_mode) && + (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) + return -EPERM; + } + + return permission(inode, mask, NULL); +} + int vfs_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags) @@ -27,6 +68,10 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value, struct inode *inode = dentry->d_inode; int error; + error = xattr_permission(inode, name, MAY_WRITE); + if (error) + return error; + mutex_lock(&inode->i_mutex); error = security_inode_setxattr(dentry, name, value, size, flags); if (error) @@ -40,8 +85,8 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value, size, flags); } } else if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof XATTR_SECURITY_PREFIX - 1)) { - const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1; + XATTR_SECURITY_PREFIX_LEN)) { + const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; error = security_inode_setsecurity(inode, suffix, value, size, flags); if (!error) @@ -59,6 +104,10 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size) struct inode *inode = dentry->d_inode; int error; + error = xattr_permission(inode, name, MAY_READ); + if (error) + return error; + error = security_inode_getxattr(dentry, name); if (error) return error; @@ -69,8 +118,8 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size) error = -EOPNOTSUPP; if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof XATTR_SECURITY_PREFIX - 1)) { - const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1; + XATTR_SECURITY_PREFIX_LEN)) { + const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; int ret = security_inode_getsecurity(inode, suffix, value, size, error); /* @@ -94,6 +143,10 @@ vfs_removexattr(struct dentry *dentry, char *name) if (!inode->i_op->removexattr) return -EOPNOTSUPP; + error = xattr_permission(inode, name, MAY_WRITE); + if (error) + return error; + error = security_inode_removexattr(dentry, name); if (error) return error; diff --git a/include/linux/xattr.h b/include/linux/xattr.h index 366f0ab4219f..cda8a96e2fa0 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h @@ -13,7 +13,22 @@ #define XATTR_CREATE 0x1 /* set value, fail if attr already exists */ #define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ +/* Namespaces */ +#define XATTR_OS2_PREFIX "os2." +#define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1) + #define XATTR_SECURITY_PREFIX "security." +#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) + +#define XATTR_SYSTEM_PREFIX "system." +#define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1) + +#define XATTR_TRUSTED_PREFIX "trusted." +#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) + +#define XATTR_USER_PREFIX "user." +#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) + struct xattr_handler { char *prefix; |