aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2006-01-09 23:51:55 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-10 11:01:29 -0500
commit5be196e5f925dab2309530fabce69c2e562b9791 (patch)
tree4249d808c38b6f13e899ac936585c1fbb48e5b3b
parenta7e670d828e85ef9aacb7fa1cd221525c408110f (diff)
[PATCH] add vfs_* helpers for xattr operations
Add vfs_getxattr, vfs_setxattr and vfs_removexattr helpers for common checks around invocation of the xattr methods. NFSD already was missing some of the checks and there will be more soon. Signed-off-by: Christoph Hellwig <hch@lst.de> Cc: James Morris <jmorris@namei.org> (James, I haven't touched selinux yet because it's doing various odd things and I'm not sure how it would interact with the security attribute fallbacks you added. Could you investigate whether it could use vfs_getxattr or if not add a __vfs_getxattr helper to share the bits it is fine with?) For NFSv4: instead of just converting it add an nfsd_getxattr helper for the code shared by NFSv2/3 and NFSv4 ACLs. In fact that code isn't even NFS-specific, but I'll wait for more users to pop up first before moving it to common code. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Dave Kleikamp <shaggy@austin.ibm.com> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Neil Brown <neilb@suse.de> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-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);