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 { | |||
83 | #define EA_NEW 0x0004 | 83 | #define EA_NEW 0x0004 |
84 | #define EA_MALLOC 0x0008 | 84 | #define EA_MALLOC 0x0008 |
85 | 85 | ||
86 | /* Namespaces */ | ||
87 | #define XATTR_SYSTEM_PREFIX "system." | ||
88 | #define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1) | ||
89 | |||
90 | #define XATTR_USER_PREFIX "user." | ||
91 | #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) | ||
92 | |||
93 | #define XATTR_OS2_PREFIX "os2." | ||
94 | #define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1) | ||
95 | |||
96 | /* XATTR_SECURITY_PREFIX is defined in include/linux/xattr.h */ | ||
97 | #define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) | ||
98 | |||
99 | #define XATTR_TRUSTED_PREFIX "trusted." | ||
100 | #define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) | ||
101 | 86 | ||
102 | /* | 87 | /* |
103 | * These three routines are used to recognize on-disk extended attributes | 88 | * 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 @@ | |||
20 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
21 | 21 | ||
22 | 22 | ||
23 | /* | ||
24 | * Check permissions for extended attribute access. This is a bit complicated | ||
25 | * because different namespaces have very different rules. | ||
26 | */ | ||
27 | static int | ||
28 | xattr_permission(struct inode *inode, const char *name, int mask) | ||
29 | { | ||
30 | /* | ||
31 | * We can never set or remove an extended attribute on a read-only | ||
32 | * filesystem or on an immutable / append-only inode. | ||
33 | */ | ||
34 | if (mask & MAY_WRITE) { | ||
35 | if (IS_RDONLY(inode)) | ||
36 | return -EROFS; | ||
37 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
38 | return -EPERM; | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * No restriction for security.* and system.* from the VFS. Decision | ||
43 | * on these is left to the underlying filesystem / security module. | ||
44 | */ | ||
45 | if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || | ||
46 | !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
47 | return 0; | ||
48 | |||
49 | /* | ||
50 | * The trusted.* namespace can only accessed by a privilegued user. | ||
51 | */ | ||
52 | if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
53 | return (capable(CAP_SYS_ADMIN) ? 0 : -EPERM); | ||
54 | |||
55 | if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { | ||
56 | if (!S_ISREG(inode->i_mode) && | ||
57 | (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) | ||
58 | return -EPERM; | ||
59 | } | ||
60 | |||
61 | return permission(inode, mask, NULL); | ||
62 | } | ||
63 | |||
23 | int | 64 | int |
24 | vfs_setxattr(struct dentry *dentry, char *name, void *value, | 65 | vfs_setxattr(struct dentry *dentry, char *name, void *value, |
25 | size_t size, int flags) | 66 | size_t size, int flags) |
@@ -27,6 +68,10 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value, | |||
27 | struct inode *inode = dentry->d_inode; | 68 | struct inode *inode = dentry->d_inode; |
28 | int error; | 69 | int error; |
29 | 70 | ||
71 | error = xattr_permission(inode, name, MAY_WRITE); | ||
72 | if (error) | ||
73 | return error; | ||
74 | |||
30 | mutex_lock(&inode->i_mutex); | 75 | mutex_lock(&inode->i_mutex); |
31 | error = security_inode_setxattr(dentry, name, value, size, flags); | 76 | error = security_inode_setxattr(dentry, name, value, size, flags); |
32 | if (error) | 77 | if (error) |
@@ -40,8 +85,8 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value, | |||
40 | size, flags); | 85 | size, flags); |
41 | } | 86 | } |
42 | } else if (!strncmp(name, XATTR_SECURITY_PREFIX, | 87 | } else if (!strncmp(name, XATTR_SECURITY_PREFIX, |
43 | sizeof XATTR_SECURITY_PREFIX - 1)) { | 88 | XATTR_SECURITY_PREFIX_LEN)) { |
44 | const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1; | 89 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
45 | error = security_inode_setsecurity(inode, suffix, value, | 90 | error = security_inode_setsecurity(inode, suffix, value, |
46 | size, flags); | 91 | size, flags); |
47 | if (!error) | 92 | if (!error) |
@@ -59,6 +104,10 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size) | |||
59 | struct inode *inode = dentry->d_inode; | 104 | struct inode *inode = dentry->d_inode; |
60 | int error; | 105 | int error; |
61 | 106 | ||
107 | error = xattr_permission(inode, name, MAY_READ); | ||
108 | if (error) | ||
109 | return error; | ||
110 | |||
62 | error = security_inode_getxattr(dentry, name); | 111 | error = security_inode_getxattr(dentry, name); |
63 | if (error) | 112 | if (error) |
64 | return error; | 113 | return error; |
@@ -69,8 +118,8 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size) | |||
69 | error = -EOPNOTSUPP; | 118 | error = -EOPNOTSUPP; |
70 | 119 | ||
71 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 120 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
72 | sizeof XATTR_SECURITY_PREFIX - 1)) { | 121 | XATTR_SECURITY_PREFIX_LEN)) { |
73 | const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1; | 122 | const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; |
74 | int ret = security_inode_getsecurity(inode, suffix, value, | 123 | int ret = security_inode_getsecurity(inode, suffix, value, |
75 | size, error); | 124 | size, error); |
76 | /* | 125 | /* |
@@ -94,6 +143,10 @@ vfs_removexattr(struct dentry *dentry, char *name) | |||
94 | if (!inode->i_op->removexattr) | 143 | if (!inode->i_op->removexattr) |
95 | return -EOPNOTSUPP; | 144 | return -EOPNOTSUPP; |
96 | 145 | ||
146 | error = xattr_permission(inode, name, MAY_WRITE); | ||
147 | if (error) | ||
148 | return error; | ||
149 | |||
97 | error = security_inode_removexattr(dentry, name); | 150 | error = security_inode_removexattr(dentry, name); |
98 | if (error) | 151 | if (error) |
99 | return error; | 152 | 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 @@ | |||
13 | #define XATTR_CREATE 0x1 /* set value, fail if attr already exists */ | 13 | #define XATTR_CREATE 0x1 /* set value, fail if attr already exists */ |
14 | #define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ | 14 | #define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ |
15 | 15 | ||
16 | /* Namespaces */ | ||
17 | #define XATTR_OS2_PREFIX "os2." | ||
18 | #define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1) | ||
19 | |||
16 | #define XATTR_SECURITY_PREFIX "security." | 20 | #define XATTR_SECURITY_PREFIX "security." |
21 | #define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1) | ||
22 | |||
23 | #define XATTR_SYSTEM_PREFIX "system." | ||
24 | #define XATTR_SYSTEM_PREFIX_LEN (sizeof (XATTR_SYSTEM_PREFIX) - 1) | ||
25 | |||
26 | #define XATTR_TRUSTED_PREFIX "trusted." | ||
27 | #define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1) | ||
28 | |||
29 | #define XATTR_USER_PREFIX "user." | ||
30 | #define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1) | ||
31 | |||
17 | 32 | ||
18 | struct xattr_handler { | 33 | struct xattr_handler { |
19 | char *prefix; | 34 | char *prefix; |