blob: fee804e69a9a40206fd55ca81dc3c31ace876eca [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 File: fs/xattr.c
3
4 Extended attribute handling.
5
6 Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
7 Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
8 Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
9 */
10#include <linux/fs.h>
11#include <linux/slab.h>
12#include <linux/smp_lock.h>
13#include <linux/file.h>
14#include <linux/xattr.h>
15#include <linux/namei.h>
16#include <linux/security.h>
17#include <linux/syscalls.h>
18#include <linux/module.h>
Robert Love0eeca282005-07-12 17:06:03 -040019#include <linux/fsnotify.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/uaccess.h>
21
Christoph Hellwig5be196e2006-01-09 20:51:55 -080022
23int
24vfs_setxattr(struct dentry *dentry, char *name, void *value,
25 size_t size, int flags)
26{
27 struct inode *inode = dentry->d_inode;
28 int error;
29
30 mutex_lock(&inode->i_mutex);
31 error = security_inode_setxattr(dentry, name, value, size, flags);
32 if (error)
33 goto out;
34 error = -EOPNOTSUPP;
35 if (inode->i_op->setxattr) {
36 error = inode->i_op->setxattr(dentry, name, value, size, flags);
37 if (!error) {
38 fsnotify_xattr(dentry);
39 security_inode_post_setxattr(dentry, name, value,
40 size, flags);
41 }
42 } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
43 sizeof XATTR_SECURITY_PREFIX - 1)) {
44 const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
45 error = security_inode_setsecurity(inode, suffix, value,
46 size, flags);
47 if (!error)
48 fsnotify_xattr(dentry);
49 }
50out:
51 mutex_unlock(&inode->i_mutex);
52 return error;
53}
54EXPORT_SYMBOL_GPL(vfs_setxattr);
55
56ssize_t
57vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
58{
59 struct inode *inode = dentry->d_inode;
60 int error;
61
62 error = security_inode_getxattr(dentry, name);
63 if (error)
64 return error;
65
66 if (inode->i_op->getxattr)
67 error = inode->i_op->getxattr(dentry, name, value, size);
68 else
69 error = -EOPNOTSUPP;
70
71 if (!strncmp(name, XATTR_SECURITY_PREFIX,
72 sizeof XATTR_SECURITY_PREFIX - 1)) {
73 const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
74 int ret = security_inode_getsecurity(inode, suffix, value,
75 size, error);
76 /*
77 * Only overwrite the return value if a security module
78 * is actually active.
79 */
80 if (ret != -EOPNOTSUPP)
81 error = ret;
82 }
83
84 return error;
85}
86EXPORT_SYMBOL_GPL(vfs_getxattr);
87
88int
89vfs_removexattr(struct dentry *dentry, char *name)
90{
91 struct inode *inode = dentry->d_inode;
92 int error;
93
94 if (!inode->i_op->removexattr)
95 return -EOPNOTSUPP;
96
97 error = security_inode_removexattr(dentry, name);
98 if (error)
99 return error;
100
101 mutex_lock(&inode->i_mutex);
102 error = inode->i_op->removexattr(dentry, name);
103 mutex_unlock(&inode->i_mutex);
104
105 if (!error)
106 fsnotify_xattr(dentry);
107 return error;
108}
109EXPORT_SYMBOL_GPL(vfs_removexattr);
110
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112/*
113 * Extended attribute SET operations
114 */
115static long
116setxattr(struct dentry *d, char __user *name, void __user *value,
117 size_t size, int flags)
118{
119 int error;
120 void *kvalue = NULL;
121 char kname[XATTR_NAME_MAX + 1];
122
123 if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
124 return -EINVAL;
125
126 error = strncpy_from_user(kname, name, sizeof(kname));
127 if (error == 0 || error == sizeof(kname))
128 error = -ERANGE;
129 if (error < 0)
130 return error;
131
132 if (size) {
133 if (size > XATTR_SIZE_MAX)
134 return -E2BIG;
135 kvalue = kmalloc(size, GFP_KERNEL);
136 if (!kvalue)
137 return -ENOMEM;
138 if (copy_from_user(kvalue, value, size)) {
139 kfree(kvalue);
140 return -EFAULT;
141 }
142 }
143
Christoph Hellwig5be196e2006-01-09 20:51:55 -0800144 error = vfs_setxattr(d, kname, kvalue, size, flags);
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800145 kfree(kvalue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return error;
147}
148
149asmlinkage long
150sys_setxattr(char __user *path, char __user *name, void __user *value,
151 size_t size, int flags)
152{
153 struct nameidata nd;
154 int error;
155
156 error = user_path_walk(path, &nd);
157 if (error)
158 return error;
159 error = setxattr(nd.dentry, name, value, size, flags);
160 path_release(&nd);
161 return error;
162}
163
164asmlinkage long
165sys_lsetxattr(char __user *path, char __user *name, void __user *value,
166 size_t size, int flags)
167{
168 struct nameidata nd;
169 int error;
170
171 error = user_path_walk_link(path, &nd);
172 if (error)
173 return error;
174 error = setxattr(nd.dentry, name, value, size, flags);
175 path_release(&nd);
176 return error;
177}
178
179asmlinkage long
180sys_fsetxattr(int fd, char __user *name, void __user *value,
181 size_t size, int flags)
182{
183 struct file *f;
184 int error = -EBADF;
185
186 f = fget(fd);
187 if (!f)
188 return error;
189 error = setxattr(f->f_dentry, name, value, size, flags);
190 fput(f);
191 return error;
192}
193
194/*
195 * Extended attribute GET operations
196 */
197static ssize_t
198getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
199{
200 ssize_t error;
201 void *kvalue = NULL;
202 char kname[XATTR_NAME_MAX + 1];
203
204 error = strncpy_from_user(kname, name, sizeof(kname));
205 if (error == 0 || error == sizeof(kname))
206 error = -ERANGE;
207 if (error < 0)
208 return error;
209
210 if (size) {
211 if (size > XATTR_SIZE_MAX)
212 size = XATTR_SIZE_MAX;
James Morrisd381d8a2005-10-30 14:59:22 -0800213 kvalue = kzalloc(size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 if (!kvalue)
215 return -ENOMEM;
216 }
217
Christoph Hellwig5be196e2006-01-09 20:51:55 -0800218 error = vfs_getxattr(d, kname, kvalue, size);
Stephen Smalleyf549d6c2005-09-03 15:55:18 -0700219 if (error > 0) {
220 if (size && copy_to_user(value, kvalue, error))
221 error = -EFAULT;
222 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
223 /* The file system tried to returned a value bigger
224 than XATTR_SIZE_MAX bytes. Not possible. */
225 error = -E2BIG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 }
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800227 kfree(kvalue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 return error;
229}
230
231asmlinkage ssize_t
232sys_getxattr(char __user *path, char __user *name, void __user *value,
233 size_t size)
234{
235 struct nameidata nd;
236 ssize_t error;
237
238 error = user_path_walk(path, &nd);
239 if (error)
240 return error;
241 error = getxattr(nd.dentry, name, value, size);
242 path_release(&nd);
243 return error;
244}
245
246asmlinkage ssize_t
247sys_lgetxattr(char __user *path, char __user *name, void __user *value,
248 size_t size)
249{
250 struct nameidata nd;
251 ssize_t error;
252
253 error = user_path_walk_link(path, &nd);
254 if (error)
255 return error;
256 error = getxattr(nd.dentry, name, value, size);
257 path_release(&nd);
258 return error;
259}
260
261asmlinkage ssize_t
262sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
263{
264 struct file *f;
265 ssize_t error = -EBADF;
266
267 f = fget(fd);
268 if (!f)
269 return error;
270 error = getxattr(f->f_dentry, name, value, size);
271 fput(f);
272 return error;
273}
274
275/*
276 * Extended attribute LIST operations
277 */
278static ssize_t
279listxattr(struct dentry *d, char __user *list, size_t size)
280{
281 ssize_t error;
282 char *klist = NULL;
283
284 if (size) {
285 if (size > XATTR_LIST_MAX)
286 size = XATTR_LIST_MAX;
287 klist = kmalloc(size, GFP_KERNEL);
288 if (!klist)
289 return -ENOMEM;
290 }
291
Stephen Smalleyf549d6c2005-09-03 15:55:18 -0700292 error = security_inode_listxattr(d);
293 if (error)
294 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 error = -EOPNOTSUPP;
296 if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 error = d->d_inode->i_op->listxattr(d, klist, size);
Stephen Smalleyf549d6c2005-09-03 15:55:18 -0700298 } else {
299 error = security_inode_listsecurity(d->d_inode, klist, size);
Daniel Drake894ec872005-12-12 00:37:08 -0800300 if (size && error > size)
Stephen Smalleyf549d6c2005-09-03 15:55:18 -0700301 error = -ERANGE;
302 }
303 if (error > 0) {
304 if (size && copy_to_user(list, klist, error))
305 error = -EFAULT;
306 } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
307 /* The file system tried to returned a list bigger
308 than XATTR_LIST_MAX bytes. Not possible. */
309 error = -E2BIG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311out:
Jesper Juhlf99d49a2005-11-07 01:01:34 -0800312 kfree(klist);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 return error;
314}
315
316asmlinkage ssize_t
317sys_listxattr(char __user *path, char __user *list, size_t size)
318{
319 struct nameidata nd;
320 ssize_t error;
321
322 error = user_path_walk(path, &nd);
323 if (error)
324 return error;
325 error = listxattr(nd.dentry, list, size);
326 path_release(&nd);
327 return error;
328}
329
330asmlinkage ssize_t
331sys_llistxattr(char __user *path, char __user *list, size_t size)
332{
333 struct nameidata nd;
334 ssize_t error;
335
336 error = user_path_walk_link(path, &nd);
337 if (error)
338 return error;
339 error = listxattr(nd.dentry, list, size);
340 path_release(&nd);
341 return error;
342}
343
344asmlinkage ssize_t
345sys_flistxattr(int fd, char __user *list, size_t size)
346{
347 struct file *f;
348 ssize_t error = -EBADF;
349
350 f = fget(fd);
351 if (!f)
352 return error;
353 error = listxattr(f->f_dentry, list, size);
354 fput(f);
355 return error;
356}
357
358/*
359 * Extended attribute REMOVE operations
360 */
361static long
362removexattr(struct dentry *d, char __user *name)
363{
364 int error;
365 char kname[XATTR_NAME_MAX + 1];
366
367 error = strncpy_from_user(kname, name, sizeof(kname));
368 if (error == 0 || error == sizeof(kname))
369 error = -ERANGE;
370 if (error < 0)
371 return error;
372
Christoph Hellwig5be196e2006-01-09 20:51:55 -0800373 return vfs_removexattr(d, kname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374}
375
376asmlinkage long
377sys_removexattr(char __user *path, char __user *name)
378{
379 struct nameidata nd;
380 int error;
381
382 error = user_path_walk(path, &nd);
383 if (error)
384 return error;
385 error = removexattr(nd.dentry, name);
386 path_release(&nd);
387 return error;
388}
389
390asmlinkage long
391sys_lremovexattr(char __user *path, char __user *name)
392{
393 struct nameidata nd;
394 int error;
395
396 error = user_path_walk_link(path, &nd);
397 if (error)
398 return error;
399 error = removexattr(nd.dentry, name);
400 path_release(&nd);
401 return error;
402}
403
404asmlinkage long
405sys_fremovexattr(int fd, char __user *name)
406{
407 struct file *f;
408 int error = -EBADF;
409
410 f = fget(fd);
411 if (!f)
412 return error;
413 error = removexattr(f->f_dentry, name);
414 fput(f);
415 return error;
416}
417
418
419static const char *
420strcmp_prefix(const char *a, const char *a_prefix)
421{
422 while (*a_prefix && *a == *a_prefix) {
423 a++;
424 a_prefix++;
425 }
426 return *a_prefix ? NULL : a;
427}
428
429/*
430 * In order to implement different sets of xattr operations for each xattr
431 * prefix with the generic xattr API, a filesystem should create a
432 * null-terminated array of struct xattr_handler (one for each prefix) and
433 * hang a pointer to it off of the s_xattr field of the superblock.
434 *
435 * The generic_fooxattr() functions will use this list to dispatch xattr
436 * operations to the correct xattr_handler.
437 */
438#define for_each_xattr_handler(handlers, handler) \
439 for ((handler) = *(handlers)++; \
440 (handler) != NULL; \
441 (handler) = *(handlers)++)
442
443/*
444 * Find the xattr_handler with the matching prefix.
445 */
446static struct xattr_handler *
447xattr_resolve_name(struct xattr_handler **handlers, const char **name)
448{
449 struct xattr_handler *handler;
450
451 if (!*name)
452 return NULL;
453
454 for_each_xattr_handler(handlers, handler) {
455 const char *n = strcmp_prefix(*name, handler->prefix);
456 if (n) {
457 *name = n;
458 break;
459 }
460 }
461 return handler;
462}
463
464/*
465 * Find the handler for the prefix and dispatch its get() operation.
466 */
467ssize_t
468generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
469{
470 struct xattr_handler *handler;
471 struct inode *inode = dentry->d_inode;
472
473 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
474 if (!handler)
475 return -EOPNOTSUPP;
476 return handler->get(inode, name, buffer, size);
477}
478
479/*
480 * Combine the results of the list() operation from every xattr_handler in the
481 * list.
482 */
483ssize_t
484generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
485{
486 struct inode *inode = dentry->d_inode;
487 struct xattr_handler *handler, **handlers = inode->i_sb->s_xattr;
488 unsigned int size = 0;
489
490 if (!buffer) {
491 for_each_xattr_handler(handlers, handler)
492 size += handler->list(inode, NULL, 0, NULL, 0);
493 } else {
494 char *buf = buffer;
495
496 for_each_xattr_handler(handlers, handler) {
497 size = handler->list(inode, buf, buffer_size, NULL, 0);
498 if (size > buffer_size)
499 return -ERANGE;
500 buf += size;
501 buffer_size -= size;
502 }
503 size = buf - buffer;
504 }
505 return size;
506}
507
508/*
509 * Find the handler for the prefix and dispatch its set() operation.
510 */
511int
512generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
513{
514 struct xattr_handler *handler;
515 struct inode *inode = dentry->d_inode;
516
517 if (size == 0)
518 value = ""; /* empty EA, do not remove */
519 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
520 if (!handler)
521 return -EOPNOTSUPP;
522 return handler->set(inode, name, value, size, flags);
523}
524
525/*
526 * Find the handler for the prefix and dispatch its set() operation to remove
527 * any associated extended attribute.
528 */
529int
530generic_removexattr(struct dentry *dentry, const char *name)
531{
532 struct xattr_handler *handler;
533 struct inode *inode = dentry->d_inode;
534
535 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
536 if (!handler)
537 return -EOPNOTSUPP;
538 return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
539}
540
541EXPORT_SYMBOL(generic_getxattr);
542EXPORT_SYMBOL(generic_listxattr);
543EXPORT_SYMBOL(generic_setxattr);
544EXPORT_SYMBOL(generic_removexattr);