aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xattr.c')
-rw-r--r--fs/xattr.c199
1 files changed, 146 insertions, 53 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index bcc2156d4d28..80eca7d3d69f 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -19,6 +19,149 @@
19#include <linux/fsnotify.h> 19#include <linux/fsnotify.h>
20#include <asm/uaccess.h> 20#include <asm/uaccess.h>
21 21
22
23/*
24 * Check permissions for extended attribute access. This is a bit complicated
25 * because different namespaces have very different rules.
26 */
27static int
28xattr_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
64int
65vfs_setxattr(struct dentry *dentry, char *name, void *value,
66 size_t size, int flags)
67{
68 struct inode *inode = dentry->d_inode;
69 int error;
70
71 error = xattr_permission(inode, name, MAY_WRITE);
72 if (error)
73 return error;
74
75 mutex_lock(&inode->i_mutex);
76 error = security_inode_setxattr(dentry, name, value, size, flags);
77 if (error)
78 goto out;
79 error = -EOPNOTSUPP;
80 if (inode->i_op->setxattr) {
81 error = inode->i_op->setxattr(dentry, name, value, size, flags);
82 if (!error) {
83 fsnotify_xattr(dentry);
84 security_inode_post_setxattr(dentry, name, value,
85 size, flags);
86 }
87 } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
88 XATTR_SECURITY_PREFIX_LEN)) {
89 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
90 error = security_inode_setsecurity(inode, suffix, value,
91 size, flags);
92 if (!error)
93 fsnotify_xattr(dentry);
94 }
95out:
96 mutex_unlock(&inode->i_mutex);
97 return error;
98}
99EXPORT_SYMBOL_GPL(vfs_setxattr);
100
101ssize_t
102vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
103{
104 struct inode *inode = dentry->d_inode;
105 int error;
106
107 error = xattr_permission(inode, name, MAY_READ);
108 if (error)
109 return error;
110
111 error = security_inode_getxattr(dentry, name);
112 if (error)
113 return error;
114
115 if (inode->i_op->getxattr)
116 error = inode->i_op->getxattr(dentry, name, value, size);
117 else
118 error = -EOPNOTSUPP;
119
120 if (!strncmp(name, XATTR_SECURITY_PREFIX,
121 XATTR_SECURITY_PREFIX_LEN)) {
122 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
123 int ret = security_inode_getsecurity(inode, suffix, value,
124 size, error);
125 /*
126 * Only overwrite the return value if a security module
127 * is actually active.
128 */
129 if (ret != -EOPNOTSUPP)
130 error = ret;
131 }
132
133 return error;
134}
135EXPORT_SYMBOL_GPL(vfs_getxattr);
136
137int
138vfs_removexattr(struct dentry *dentry, char *name)
139{
140 struct inode *inode = dentry->d_inode;
141 int error;
142
143 if (!inode->i_op->removexattr)
144 return -EOPNOTSUPP;
145
146 error = xattr_permission(inode, name, MAY_WRITE);
147 if (error)
148 return error;
149
150 error = security_inode_removexattr(dentry, name);
151 if (error)
152 return error;
153
154 mutex_lock(&inode->i_mutex);
155 error = inode->i_op->removexattr(dentry, name);
156 mutex_unlock(&inode->i_mutex);
157
158 if (!error)
159 fsnotify_xattr(dentry);
160 return error;
161}
162EXPORT_SYMBOL_GPL(vfs_removexattr);
163
164
22/* 165/*
23 * Extended attribute SET operations 166 * Extended attribute SET operations
24 */ 167 */
@@ -51,29 +194,7 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
51 } 194 }
52 } 195 }
53 196
54 down(&d->d_inode->i_sem); 197 error = vfs_setxattr(d, kname, kvalue, size, flags);
55 error = security_inode_setxattr(d, kname, kvalue, size, flags);
56 if (error)
57 goto out;
58 error = -EOPNOTSUPP;
59 if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
60 error = d->d_inode->i_op->setxattr(d, kname, kvalue,
61 size, flags);
62 if (!error) {
63 fsnotify_xattr(d);
64 security_inode_post_setxattr(d, kname, kvalue,
65 size, flags);
66 }
67 } else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
68 sizeof XATTR_SECURITY_PREFIX - 1)) {
69 const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
70 error = security_inode_setsecurity(d->d_inode, suffix, kvalue,
71 size, flags);
72 if (!error)
73 fsnotify_xattr(d);
74 }
75out:
76 up(&d->d_inode->i_sem);
77 kfree(kvalue); 198 kfree(kvalue);
78 return error; 199 return error;
79} 200}
@@ -147,22 +268,7 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
147 return -ENOMEM; 268 return -ENOMEM;
148 } 269 }
149 270
150 error = security_inode_getxattr(d, kname); 271 error = vfs_getxattr(d, kname, kvalue, size);
151 if (error)
152 goto out;
153 error = -EOPNOTSUPP;
154 if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
155 error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
156
157 if (!strncmp(kname, XATTR_SECURITY_PREFIX,
158 sizeof XATTR_SECURITY_PREFIX - 1)) {
159 const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
160 int rv = security_inode_getsecurity(d->d_inode, suffix, kvalue,
161 size, error);
162 /* Security module active: overwrite error value */
163 if (rv != -EOPNOTSUPP)
164 error = rv;
165 }
166 if (error > 0) { 272 if (error > 0) {
167 if (size && copy_to_user(value, kvalue, error)) 273 if (size && copy_to_user(value, kvalue, error))
168 error = -EFAULT; 274 error = -EFAULT;
@@ -171,7 +277,6 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
171 than XATTR_SIZE_MAX bytes. Not possible. */ 277 than XATTR_SIZE_MAX bytes. Not possible. */
172 error = -E2BIG; 278 error = -E2BIG;
173 } 279 }
174out:
175 kfree(kvalue); 280 kfree(kvalue);
176 return error; 281 return error;
177} 282}
@@ -318,19 +423,7 @@ removexattr(struct dentry *d, char __user *name)
318 if (error < 0) 423 if (error < 0)
319 return error; 424 return error;
320 425
321 error = -EOPNOTSUPP; 426 return vfs_removexattr(d, kname);
322 if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
323 error = security_inode_removexattr(d, kname);
324 if (error)
325 goto out;
326 down(&d->d_inode->i_sem);
327 error = d->d_inode->i_op->removexattr(d, kname);
328 up(&d->d_inode->i_sem);
329 if (!error)
330 fsnotify_xattr(d);
331 }
332out:
333 return error;
334} 427}
335 428
336asmlinkage long 429asmlinkage long