diff options
Diffstat (limited to 'fs/xattr.c')
-rw-r--r-- | fs/xattr.c | 88 |
1 files changed, 56 insertions, 32 deletions
diff --git a/fs/xattr.c b/fs/xattr.c index 6acd5c63da91..f6e00c0e114f 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -51,20 +51,29 @@ setxattr(struct dentry *d, char __user *name, void __user *value, | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | down(&d->d_inode->i_sem); | ||
55 | error = security_inode_setxattr(d, kname, kvalue, size, flags); | ||
56 | if (error) | ||
57 | goto out; | ||
54 | error = -EOPNOTSUPP; | 58 | error = -EOPNOTSUPP; |
55 | if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { | 59 | if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { |
56 | down(&d->d_inode->i_sem); | 60 | error = d->d_inode->i_op->setxattr(d, kname, kvalue, |
57 | error = security_inode_setxattr(d, kname, kvalue, size, flags); | 61 | size, flags); |
58 | if (error) | ||
59 | goto out; | ||
60 | error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); | ||
61 | if (!error) { | 62 | if (!error) { |
62 | fsnotify_xattr(d); | 63 | fsnotify_xattr(d); |
63 | security_inode_post_setxattr(d, kname, kvalue, size, flags); | 64 | security_inode_post_setxattr(d, kname, kvalue, |
65 | size, flags); | ||
64 | } | 66 | } |
65 | out: | 67 | } else if (!strncmp(kname, XATTR_SECURITY_PREFIX, |
66 | up(&d->d_inode->i_sem); | 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); | ||
67 | } | 74 | } |
75 | out: | ||
76 | up(&d->d_inode->i_sem); | ||
68 | if (kvalue) | 77 | if (kvalue) |
69 | kfree(kvalue); | 78 | kfree(kvalue); |
70 | return error; | 79 | return error; |
@@ -134,25 +143,34 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size) | |||
134 | if (size) { | 143 | if (size) { |
135 | if (size > XATTR_SIZE_MAX) | 144 | if (size > XATTR_SIZE_MAX) |
136 | size = XATTR_SIZE_MAX; | 145 | size = XATTR_SIZE_MAX; |
137 | kvalue = kmalloc(size, GFP_KERNEL); | 146 | kvalue = kzalloc(size, GFP_KERNEL); |
138 | if (!kvalue) | 147 | if (!kvalue) |
139 | return -ENOMEM; | 148 | return -ENOMEM; |
140 | } | 149 | } |
141 | 150 | ||
151 | error = security_inode_getxattr(d, kname); | ||
152 | if (error) | ||
153 | goto out; | ||
142 | error = -EOPNOTSUPP; | 154 | error = -EOPNOTSUPP; |
143 | if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { | 155 | if (d->d_inode->i_op && d->d_inode->i_op->getxattr) |
144 | error = security_inode_getxattr(d, kname); | ||
145 | if (error) | ||
146 | goto out; | ||
147 | error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); | 156 | error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); |
148 | if (error > 0) { | 157 | |
149 | if (size && copy_to_user(value, kvalue, error)) | 158 | if (!strncmp(kname, XATTR_SECURITY_PREFIX, |
150 | error = -EFAULT; | 159 | sizeof XATTR_SECURITY_PREFIX - 1)) { |
151 | } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { | 160 | const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1; |
152 | /* The file system tried to returned a value bigger | 161 | int rv = security_inode_getsecurity(d->d_inode, suffix, kvalue, |
153 | than XATTR_SIZE_MAX bytes. Not possible. */ | 162 | size, error); |
154 | error = -E2BIG; | 163 | /* Security module active: overwrite error value */ |
155 | } | 164 | if (rv != -EOPNOTSUPP) |
165 | error = rv; | ||
166 | } | ||
167 | if (error > 0) { | ||
168 | if (size && copy_to_user(value, kvalue, error)) | ||
169 | error = -EFAULT; | ||
170 | } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { | ||
171 | /* The file system tried to returned a value bigger | ||
172 | than XATTR_SIZE_MAX bytes. Not possible. */ | ||
173 | error = -E2BIG; | ||
156 | } | 174 | } |
157 | out: | 175 | out: |
158 | if (kvalue) | 176 | if (kvalue) |
@@ -221,20 +239,24 @@ listxattr(struct dentry *d, char __user *list, size_t size) | |||
221 | return -ENOMEM; | 239 | return -ENOMEM; |
222 | } | 240 | } |
223 | 241 | ||
242 | error = security_inode_listxattr(d); | ||
243 | if (error) | ||
244 | goto out; | ||
224 | error = -EOPNOTSUPP; | 245 | error = -EOPNOTSUPP; |
225 | if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { | 246 | if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { |
226 | error = security_inode_listxattr(d); | ||
227 | if (error) | ||
228 | goto out; | ||
229 | error = d->d_inode->i_op->listxattr(d, klist, size); | 247 | error = d->d_inode->i_op->listxattr(d, klist, size); |
230 | if (error > 0) { | 248 | } else { |
231 | if (size && copy_to_user(list, klist, error)) | 249 | error = security_inode_listsecurity(d->d_inode, klist, size); |
232 | error = -EFAULT; | 250 | if (size && error >= size) |
233 | } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { | 251 | error = -ERANGE; |
234 | /* The file system tried to returned a list bigger | 252 | } |
235 | than XATTR_LIST_MAX bytes. Not possible. */ | 253 | if (error > 0) { |
236 | error = -E2BIG; | 254 | if (size && copy_to_user(list, klist, error)) |
237 | } | 255 | error = -EFAULT; |
256 | } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { | ||
257 | /* The file system tried to returned a list bigger | ||
258 | than XATTR_LIST_MAX bytes. Not possible. */ | ||
259 | error = -E2BIG; | ||
238 | } | 260 | } |
239 | out: | 261 | out: |
240 | if (klist) | 262 | if (klist) |
@@ -307,6 +329,8 @@ removexattr(struct dentry *d, char __user *name) | |||
307 | down(&d->d_inode->i_sem); | 329 | down(&d->d_inode->i_sem); |
308 | error = d->d_inode->i_op->removexattr(d, kname); | 330 | error = d->d_inode->i_op->removexattr(d, kname); |
309 | up(&d->d_inode->i_sem); | 331 | up(&d->d_inode->i_sem); |
332 | if (!error) | ||
333 | fsnotify_xattr(d); | ||
310 | } | 334 | } |
311 | out: | 335 | out: |
312 | return error; | 336 | return error; |