aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/vfs.c125
-rw-r--r--fs/xattr.c146
-rw-r--r--include/linux/xattr.h4
3 files changed, 145 insertions, 130 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index bb36b4304491..eef0576a7785 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -48,8 +48,8 @@
48#include <linux/fsnotify.h> 48#include <linux/fsnotify.h>
49#include <linux/posix_acl.h> 49#include <linux/posix_acl.h>
50#include <linux/posix_acl_xattr.h> 50#include <linux/posix_acl_xattr.h>
51#ifdef CONFIG_NFSD_V4
52#include <linux/xattr.h> 51#include <linux/xattr.h>
52#ifdef CONFIG_NFSD_V4
53#include <linux/nfs4.h> 53#include <linux/nfs4.h>
54#include <linux/nfs4_acl.h> 54#include <linux/nfs4_acl.h>
55#include <linux/nfsd_idmap.h> 55#include <linux/nfsd_idmap.h>
@@ -365,8 +365,30 @@ out_nfserr:
365 goto out; 365 goto out;
366} 366}
367 367
368#if defined(CONFIG_NFSD_V4) 368#if defined(CONFIG_NFSD_V2_ACL) || \
369 defined(CONFIG_NFSD_V3_ACL) || \
370 defined(CONFIG_NFSD_V4)
371static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
372{
373 ssize_t buflen;
374 int error;
375
376 buflen = vfs_getxattr(dentry, key, NULL, 0);
377 if (buflen <= 0)
378 return buflen;
369 379
380 *buf = kmalloc(buflen, GFP_KERNEL);
381 if (!*buf)
382 return -ENOMEM;
383
384 error = vfs_getxattr(dentry, key, *buf, buflen);
385 if (error < 0)
386 return error;
387 return buflen;
388}
389#endif
390
391#if defined(CONFIG_NFSD_V4)
370static int 392static int
371set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key) 393set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
372{ 394{
@@ -374,7 +396,6 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
374 size_t buflen; 396 size_t buflen;
375 char *buf = NULL; 397 char *buf = NULL;
376 int error = 0; 398 int error = 0;
377 struct inode *inode = dentry->d_inode;
378 399
379 buflen = posix_acl_xattr_size(pacl->a_count); 400 buflen = posix_acl_xattr_size(pacl->a_count);
380 buf = kmalloc(buflen, GFP_KERNEL); 401 buf = kmalloc(buflen, GFP_KERNEL);
@@ -388,15 +409,7 @@ set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
388 goto out; 409 goto out;
389 } 410 }
390 411
391 error = -EOPNOTSUPP; 412 error = vfs_setxattr(dentry, key, buf, len, 0);
392 if (inode->i_op && inode->i_op->setxattr) {
393 mutex_lock(&inode->i_mutex);
394 security_inode_setxattr(dentry, key, buf, len, 0);
395 error = inode->i_op->setxattr(dentry, key, buf, len, 0);
396 if (!error)
397 security_inode_post_setxattr(dentry, key, buf, len, 0);
398 mutex_unlock(&inode->i_mutex);
399 }
400out: 413out:
401 kfree(buf); 414 kfree(buf);
402 return error; 415 return error;
@@ -455,44 +468,19 @@ out_nfserr:
455static struct posix_acl * 468static struct posix_acl *
456_get_posix_acl(struct dentry *dentry, char *key) 469_get_posix_acl(struct dentry *dentry, char *key)
457{ 470{
458 struct inode *inode = dentry->d_inode; 471 void *buf = NULL;
459 char *buf = NULL;
460 int buflen, error = 0;
461 struct posix_acl *pacl = NULL; 472 struct posix_acl *pacl = NULL;
473 int buflen;
462 474
463 error = -EOPNOTSUPP; 475 buflen = nfsd_getxattr(dentry, key, &buf);
464 if (inode->i_op == NULL) 476 if (!buflen)
465 goto out_err; 477 buflen = -ENODATA;
466 if (inode->i_op->getxattr == NULL) 478 if (buflen <= 0)
467 goto out_err; 479 return ERR_PTR(buflen);
468
469 error = security_inode_getxattr(dentry, key);
470 if (error)
471 goto out_err;
472
473 buflen = inode->i_op->getxattr(dentry, key, NULL, 0);
474 if (buflen <= 0) {
475 error = buflen < 0 ? buflen : -ENODATA;
476 goto out_err;
477 }
478
479 buf = kmalloc(buflen, GFP_KERNEL);
480 if (buf == NULL) {
481 error = -ENOMEM;
482 goto out_err;
483 }
484
485 error = inode->i_op->getxattr(dentry, key, buf, buflen);
486 if (error < 0)
487 goto out_err;
488 480
489 pacl = posix_acl_from_xattr(buf, buflen); 481 pacl = posix_acl_from_xattr(buf, buflen);
490 out:
491 kfree(buf); 482 kfree(buf);
492 return pacl; 483 return pacl;
493 out_err:
494 pacl = ERR_PTR(error);
495 goto out;
496} 484}
497 485
498int 486int
@@ -1884,39 +1872,25 @@ nfsd_get_posix_acl(struct svc_fh *fhp, int type)
1884 ssize_t size; 1872 ssize_t size;
1885 struct posix_acl *acl; 1873 struct posix_acl *acl;
1886 1874
1887 if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr) 1875 if (!IS_POSIXACL(inode))
1876 return ERR_PTR(-EOPNOTSUPP);
1877
1878 switch (type) {
1879 case ACL_TYPE_ACCESS:
1880 name = POSIX_ACL_XATTR_ACCESS;
1881 break;
1882 case ACL_TYPE_DEFAULT:
1883 name = POSIX_ACL_XATTR_DEFAULT;
1884 break;
1885 default:
1888 return ERR_PTR(-EOPNOTSUPP); 1886 return ERR_PTR(-EOPNOTSUPP);
1889 switch(type) {
1890 case ACL_TYPE_ACCESS:
1891 name = POSIX_ACL_XATTR_ACCESS;
1892 break;
1893 case ACL_TYPE_DEFAULT:
1894 name = POSIX_ACL_XATTR_DEFAULT;
1895 break;
1896 default:
1897 return ERR_PTR(-EOPNOTSUPP);
1898 } 1887 }
1899 1888
1900 size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0); 1889 size = nfsd_getxattr(fhp->fh_dentry, name, &value);
1890 if (size < 0)
1891 return ERR_PTR(size);
1901 1892
1902 if (size < 0) {
1903 acl = ERR_PTR(size);
1904 goto getout;
1905 } else if (size > 0) {
1906 value = kmalloc(size, GFP_KERNEL);
1907 if (!value) {
1908 acl = ERR_PTR(-ENOMEM);
1909 goto getout;
1910 }
1911 size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
1912 if (size < 0) {
1913 acl = ERR_PTR(size);
1914 goto getout;
1915 }
1916 }
1917 acl = posix_acl_from_xattr(value, size); 1893 acl = posix_acl_from_xattr(value, size);
1918
1919getout:
1920 kfree(value); 1894 kfree(value);
1921 return acl; 1895 return acl;
1922} 1896}
@@ -1957,16 +1931,13 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
1957 } else 1931 } else
1958 size = 0; 1932 size = 0;
1959 1933
1960 if (!fhp->fh_locked)
1961 fh_lock(fhp); /* unlocking is done automatically */
1962 if (size) 1934 if (size)
1963 error = inode->i_op->setxattr(fhp->fh_dentry, name, 1935 error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
1964 value, size, 0);
1965 else { 1936 else {
1966 if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT) 1937 if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
1967 error = 0; 1938 error = 0;
1968 else { 1939 else {
1969 error = inode->i_op->removexattr(fhp->fh_dentry, name); 1940 error = vfs_removexattr(fhp->fh_dentry, name);
1970 if (error == -ENODATA) 1941 if (error == -ENODATA)
1971 error = 0; 1942 error = 0;
1972 } 1943 }
diff --git a/fs/xattr.c b/fs/xattr.c
index 386a532ee5a9..fee804e69a9a 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -19,6 +19,96 @@
19#include <linux/fsnotify.h> 19#include <linux/fsnotify.h>
20#include <asm/uaccess.h> 20#include <asm/uaccess.h>
21 21
22
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
22/* 112/*
23 * Extended attribute SET operations 113 * Extended attribute SET operations
24 */ 114 */
@@ -51,29 +141,7 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
51 } 141 }
52 } 142 }
53 143
54 mutex_lock(&d->d_inode->i_mutex); 144 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 mutex_unlock(&d->d_inode->i_mutex);
77 kfree(kvalue); 145 kfree(kvalue);
78 return error; 146 return error;
79} 147}
@@ -147,22 +215,7 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
147 return -ENOMEM; 215 return -ENOMEM;
148 } 216 }
149 217
150 error = security_inode_getxattr(d, kname); 218 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) { 219 if (error > 0) {
167 if (size && copy_to_user(value, kvalue, error)) 220 if (size && copy_to_user(value, kvalue, error))
168 error = -EFAULT; 221 error = -EFAULT;
@@ -171,7 +224,6 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
171 than XATTR_SIZE_MAX bytes. Not possible. */ 224 than XATTR_SIZE_MAX bytes. Not possible. */
172 error = -E2BIG; 225 error = -E2BIG;
173 } 226 }
174out:
175 kfree(kvalue); 227 kfree(kvalue);
176 return error; 228 return error;
177} 229}
@@ -318,19 +370,7 @@ removexattr(struct dentry *d, char __user *name)
318 if (error < 0) 370 if (error < 0)
319 return error; 371 return error;
320 372
321 error = -EOPNOTSUPP; 373 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 mutex_lock(&d->d_inode->i_mutex);
327 error = d->d_inode->i_op->removexattr(d, kname);
328 mutex_unlock(&d->d_inode->i_mutex);
329 if (!error)
330 fsnotify_xattr(d);
331 }
332out:
333 return error;
334} 374}
335 375
336asmlinkage long 376asmlinkage long
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 23f9c61d9546..366f0ab4219f 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -25,6 +25,10 @@ struct xattr_handler {
25 size_t size, int flags); 25 size_t size, int flags);
26}; 26};
27 27
28ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
29int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
30int vfs_removexattr(struct dentry *, char *);
31
28ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size); 32ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
29ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); 33ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
30int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); 34int generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags);