aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xattr.c')
-rw-r--r--fs/xattr.c239
1 files changed, 209 insertions, 30 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index 107f457143c3..1780f062dbaf 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -20,6 +20,7 @@
20#include <linux/fsnotify.h> 20#include <linux/fsnotify.h>
21#include <linux/audit.h> 21#include <linux/audit.h>
22#include <linux/vmalloc.h> 22#include <linux/vmalloc.h>
23#include <linux/posix_acl_xattr.h>
23 24
24#include <asm/uaccess.h> 25#include <asm/uaccess.h>
25 26
@@ -349,6 +350,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
349 error = -EFAULT; 350 error = -EFAULT;
350 goto out; 351 goto out;
351 } 352 }
353 if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
354 (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
355 posix_acl_fix_xattr_from_user(kvalue, size);
352 } 356 }
353 357
354 error = vfs_setxattr(d, kname, kvalue, size, flags); 358 error = vfs_setxattr(d, kname, kvalue, size, flags);
@@ -401,22 +405,20 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
401SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, 405SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
402 const void __user *,value, size_t, size, int, flags) 406 const void __user *,value, size_t, size, int, flags)
403{ 407{
404 int fput_needed; 408 struct fd f = fdget(fd);
405 struct file *f;
406 struct dentry *dentry; 409 struct dentry *dentry;
407 int error = -EBADF; 410 int error = -EBADF;
408 411
409 f = fget_light(fd, &fput_needed); 412 if (!f.file)
410 if (!f)
411 return error; 413 return error;
412 dentry = f->f_path.dentry; 414 dentry = f.file->f_path.dentry;
413 audit_inode(NULL, dentry); 415 audit_inode(NULL, dentry);
414 error = mnt_want_write_file(f); 416 error = mnt_want_write_file(f.file);
415 if (!error) { 417 if (!error) {
416 error = setxattr(dentry, name, value, size, flags); 418 error = setxattr(dentry, name, value, size, flags);
417 mnt_drop_write_file(f); 419 mnt_drop_write_file(f.file);
418 } 420 }
419 fput_light(f, fput_needed); 421 fdput(f);
420 return error; 422 return error;
421} 423}
422 424
@@ -452,6 +454,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
452 454
453 error = vfs_getxattr(d, kname, kvalue, size); 455 error = vfs_getxattr(d, kname, kvalue, size);
454 if (error > 0) { 456 if (error > 0) {
457 if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
458 (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
459 posix_acl_fix_xattr_to_user(kvalue, size);
455 if (size && copy_to_user(value, kvalue, error)) 460 if (size && copy_to_user(value, kvalue, error))
456 error = -EFAULT; 461 error = -EFAULT;
457 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { 462 } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
@@ -497,16 +502,14 @@ SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
497SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name, 502SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
498 void __user *, value, size_t, size) 503 void __user *, value, size_t, size)
499{ 504{
500 int fput_needed; 505 struct fd f = fdget(fd);
501 struct file *f;
502 ssize_t error = -EBADF; 506 ssize_t error = -EBADF;
503 507
504 f = fget_light(fd, &fput_needed); 508 if (!f.file)
505 if (!f)
506 return error; 509 return error;
507 audit_inode(NULL, f->f_path.dentry); 510 audit_inode(NULL, f.file->f_path.dentry);
508 error = getxattr(f->f_path.dentry, name, value, size); 511 error = getxattr(f.file->f_path.dentry, name, value, size);
509 fput_light(f, fput_needed); 512 fdput(f);
510 return error; 513 return error;
511} 514}
512 515
@@ -578,16 +581,14 @@ SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
578 581
579SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size) 582SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
580{ 583{
581 int fput_needed; 584 struct fd f = fdget(fd);
582 struct file *f;
583 ssize_t error = -EBADF; 585 ssize_t error = -EBADF;
584 586
585 f = fget_light(fd, &fput_needed); 587 if (!f.file)
586 if (!f)
587 return error; 588 return error;
588 audit_inode(NULL, f->f_path.dentry); 589 audit_inode(NULL, f.file->f_path.dentry);
589 error = listxattr(f->f_path.dentry, list, size); 590 error = listxattr(f.file->f_path.dentry, list, size);
590 fput_light(f, fput_needed); 591 fdput(f);
591 return error; 592 return error;
592} 593}
593 594
@@ -647,22 +648,20 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
647 648
648SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) 649SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
649{ 650{
650 int fput_needed; 651 struct fd f = fdget(fd);
651 struct file *f;
652 struct dentry *dentry; 652 struct dentry *dentry;
653 int error = -EBADF; 653 int error = -EBADF;
654 654
655 f = fget_light(fd, &fput_needed); 655 if (!f.file)
656 if (!f)
657 return error; 656 return error;
658 dentry = f->f_path.dentry; 657 dentry = f.file->f_path.dentry;
659 audit_inode(NULL, dentry); 658 audit_inode(NULL, dentry);
660 error = mnt_want_write_file(f); 659 error = mnt_want_write_file(f.file);
661 if (!error) { 660 if (!error) {
662 error = removexattr(dentry, name); 661 error = removexattr(dentry, name);
663 mnt_drop_write_file(f); 662 mnt_drop_write_file(f.file);
664 } 663 }
665 fput_light(f, fput_needed); 664 fdput(f);
666 return error; 665 return error;
667} 666}
668 667
@@ -793,3 +792,183 @@ EXPORT_SYMBOL(generic_getxattr);
793EXPORT_SYMBOL(generic_listxattr); 792EXPORT_SYMBOL(generic_listxattr);
794EXPORT_SYMBOL(generic_setxattr); 793EXPORT_SYMBOL(generic_setxattr);
795EXPORT_SYMBOL(generic_removexattr); 794EXPORT_SYMBOL(generic_removexattr);
795
796/*
797 * Allocate new xattr and copy in the value; but leave the name to callers.
798 */
799struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
800{
801 struct simple_xattr *new_xattr;
802 size_t len;
803
804 /* wrap around? */
805 len = sizeof(*new_xattr) + size;
806 if (len <= sizeof(*new_xattr))
807 return NULL;
808
809 new_xattr = kmalloc(len, GFP_KERNEL);
810 if (!new_xattr)
811 return NULL;
812
813 new_xattr->size = size;
814 memcpy(new_xattr->value, value, size);
815 return new_xattr;
816}
817
818/*
819 * xattr GET operation for in-memory/pseudo filesystems
820 */
821int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
822 void *buffer, size_t size)
823{
824 struct simple_xattr *xattr;
825 int ret = -ENODATA;
826
827 spin_lock(&xattrs->lock);
828 list_for_each_entry(xattr, &xattrs->head, list) {
829 if (strcmp(name, xattr->name))
830 continue;
831
832 ret = xattr->size;
833 if (buffer) {
834 if (size < xattr->size)
835 ret = -ERANGE;
836 else
837 memcpy(buffer, xattr->value, xattr->size);
838 }
839 break;
840 }
841 spin_unlock(&xattrs->lock);
842 return ret;
843}
844
845static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
846 const void *value, size_t size, int flags)
847{
848 struct simple_xattr *xattr;
849 struct simple_xattr *uninitialized_var(new_xattr);
850 int err = 0;
851
852 /* value == NULL means remove */
853 if (value) {
854 new_xattr = simple_xattr_alloc(value, size);
855 if (!new_xattr)
856 return -ENOMEM;
857
858 new_xattr->name = kstrdup(name, GFP_KERNEL);
859 if (!new_xattr->name) {
860 kfree(new_xattr);
861 return -ENOMEM;
862 }
863 }
864
865 spin_lock(&xattrs->lock);
866 list_for_each_entry(xattr, &xattrs->head, list) {
867 if (!strcmp(name, xattr->name)) {
868 if (flags & XATTR_CREATE) {
869 xattr = new_xattr;
870 err = -EEXIST;
871 } else if (new_xattr) {
872 list_replace(&xattr->list, &new_xattr->list);
873 } else {
874 list_del(&xattr->list);
875 }
876 goto out;
877 }
878 }
879 if (flags & XATTR_REPLACE) {
880 xattr = new_xattr;
881 err = -ENODATA;
882 } else {
883 list_add(&new_xattr->list, &xattrs->head);
884 xattr = NULL;
885 }
886out:
887 spin_unlock(&xattrs->lock);
888 if (xattr) {
889 kfree(xattr->name);
890 kfree(xattr);
891 }
892 return err;
893
894}
895
896/**
897 * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
898 * @xattrs: target simple_xattr list
899 * @name: name of the new extended attribute
900 * @value: value of the new xattr. If %NULL, will remove the attribute
901 * @size: size of the new xattr
902 * @flags: %XATTR_{CREATE|REPLACE}
903 *
904 * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
905 * with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist;
906 * otherwise, fails with -ENODATA.
907 *
908 * Returns 0 on success, -errno on failure.
909 */
910int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
911 const void *value, size_t size, int flags)
912{
913 if (size == 0)
914 value = ""; /* empty EA, do not remove */
915 return __simple_xattr_set(xattrs, name, value, size, flags);
916}
917
918/*
919 * xattr REMOVE operation for in-memory/pseudo filesystems
920 */
921int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
922{
923 return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
924}
925
926static bool xattr_is_trusted(const char *name)
927{
928 return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
929}
930
931/*
932 * xattr LIST operation for in-memory/pseudo filesystems
933 */
934ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
935 size_t size)
936{
937 bool trusted = capable(CAP_SYS_ADMIN);
938 struct simple_xattr *xattr;
939 size_t used = 0;
940
941 spin_lock(&xattrs->lock);
942 list_for_each_entry(xattr, &xattrs->head, list) {
943 size_t len;
944
945 /* skip "trusted." attributes for unprivileged callers */
946 if (!trusted && xattr_is_trusted(xattr->name))
947 continue;
948
949 len = strlen(xattr->name) + 1;
950 used += len;
951 if (buffer) {
952 if (size < used) {
953 used = -ERANGE;
954 break;
955 }
956 memcpy(buffer, xattr->name, len);
957 buffer += len;
958 }
959 }
960 spin_unlock(&xattrs->lock);
961
962 return used;
963}
964
965/*
966 * Adds an extended attribute to the list
967 */
968void simple_xattr_list_add(struct simple_xattrs *xattrs,
969 struct simple_xattr *new_xattr)
970{
971 spin_lock(&xattrs->lock);
972 list_add(&new_xattr->list, &xattrs->head);
973 spin_unlock(&xattrs->lock);
974}