diff options
author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:38 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:29:15 -0400 |
commit | 18f335aff86913de3c76f88d32c8135c1da62ce6 (patch) | |
tree | bf541547b9774137a161d200bace04ad152e80e3 | |
parent | 9079b1eb1753f217c3de9f1b7dd7fd549cc3f0cf (diff) |
[PATCH] r/o bind mounts: elevate write count for xattr_permission() callers
This basically audits the callers of xattr_permission(), which calls
permission() and can perform writes to the filesystem.
[AV: add missing parts - removexattr() and nfsd posix acls, plug for a leak
spotted by Miklos]
Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/nfsd/nfs4proc.c | 7 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 4 | ||||
-rw-r--r-- | fs/xattr.c | 40 |
3 files changed, 42 insertions, 9 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c593db047d8b..c309c881bd4e 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -658,14 +658,19 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
658 | return status; | 658 | return status; |
659 | } | 659 | } |
660 | } | 660 | } |
661 | status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt); | ||
662 | if (status) | ||
663 | return status; | ||
661 | status = nfs_ok; | 664 | status = nfs_ok; |
662 | if (setattr->sa_acl != NULL) | 665 | if (setattr->sa_acl != NULL) |
663 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 666 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
664 | setattr->sa_acl); | 667 | setattr->sa_acl); |
665 | if (status) | 668 | if (status) |
666 | return status; | 669 | goto out; |
667 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, | 670 | status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, |
668 | 0, (time_t)0); | 671 | 0, (time_t)0); |
672 | out: | ||
673 | mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt); | ||
669 | return status; | 674 | return status; |
670 | } | 675 | } |
671 | 676 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 18a4cc9feeb3..626dfd38528f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -2086,6 +2086,9 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | |||
2086 | } else | 2086 | } else |
2087 | size = 0; | 2087 | size = 0; |
2088 | 2088 | ||
2089 | error = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
2090 | if (error) | ||
2091 | goto getout; | ||
2089 | if (size) | 2092 | if (size) |
2090 | error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); | 2093 | error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); |
2091 | else { | 2094 | else { |
@@ -2097,6 +2100,7 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | |||
2097 | error = 0; | 2100 | error = 0; |
2098 | } | 2101 | } |
2099 | } | 2102 | } |
2103 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
2100 | 2104 | ||
2101 | getout: | 2105 | getout: |
2102 | kfree(value); | 2106 | kfree(value); |
diff --git a/fs/xattr.c b/fs/xattr.c index 3acab1615460..f7062da505d4 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/slab.h> | 11 | #include <linux/slab.h> |
12 | #include <linux/file.h> | 12 | #include <linux/file.h> |
13 | #include <linux/xattr.h> | 13 | #include <linux/xattr.h> |
14 | #include <linux/mount.h> | ||
14 | #include <linux/namei.h> | 15 | #include <linux/namei.h> |
15 | #include <linux/security.h> | 16 | #include <linux/security.h> |
16 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
@@ -32,8 +33,6 @@ xattr_permission(struct inode *inode, const char *name, int mask) | |||
32 | * filesystem or on an immutable / append-only inode. | 33 | * filesystem or on an immutable / append-only inode. |
33 | */ | 34 | */ |
34 | if (mask & MAY_WRITE) { | 35 | if (mask & MAY_WRITE) { |
35 | if (IS_RDONLY(inode)) | ||
36 | return -EROFS; | ||
37 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 36 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
38 | return -EPERM; | 37 | return -EPERM; |
39 | } | 38 | } |
@@ -262,7 +261,11 @@ sys_setxattr(char __user *path, char __user *name, void __user *value, | |||
262 | error = user_path_walk(path, &nd); | 261 | error = user_path_walk(path, &nd); |
263 | if (error) | 262 | if (error) |
264 | return error; | 263 | return error; |
265 | error = setxattr(nd.path.dentry, name, value, size, flags); | 264 | error = mnt_want_write(nd.path.mnt); |
265 | if (!error) { | ||
266 | error = setxattr(nd.path.dentry, name, value, size, flags); | ||
267 | mnt_drop_write(nd.path.mnt); | ||
268 | } | ||
266 | path_put(&nd.path); | 269 | path_put(&nd.path); |
267 | return error; | 270 | return error; |
268 | } | 271 | } |
@@ -277,7 +280,11 @@ sys_lsetxattr(char __user *path, char __user *name, void __user *value, | |||
277 | error = user_path_walk_link(path, &nd); | 280 | error = user_path_walk_link(path, &nd); |
278 | if (error) | 281 | if (error) |
279 | return error; | 282 | return error; |
280 | error = setxattr(nd.path.dentry, name, value, size, flags); | 283 | error = mnt_want_write(nd.path.mnt); |
284 | if (!error) { | ||
285 | error = setxattr(nd.path.dentry, name, value, size, flags); | ||
286 | mnt_drop_write(nd.path.mnt); | ||
287 | } | ||
281 | path_put(&nd.path); | 288 | path_put(&nd.path); |
282 | return error; | 289 | return error; |
283 | } | 290 | } |
@@ -295,7 +302,12 @@ sys_fsetxattr(int fd, char __user *name, void __user *value, | |||
295 | return error; | 302 | return error; |
296 | dentry = f->f_path.dentry; | 303 | dentry = f->f_path.dentry; |
297 | audit_inode(NULL, dentry); | 304 | audit_inode(NULL, dentry); |
298 | error = setxattr(dentry, name, value, size, flags); | 305 | error = mnt_want_write(f->f_path.mnt); |
306 | if (!error) { | ||
307 | error = setxattr(dentry, name, value, size, flags); | ||
308 | mnt_drop_write(f->f_path.mnt); | ||
309 | } | ||
310 | out_fput: | ||
299 | fput(f); | 311 | fput(f); |
300 | return error; | 312 | return error; |
301 | } | 313 | } |
@@ -482,7 +494,11 @@ sys_removexattr(char __user *path, char __user *name) | |||
482 | error = user_path_walk(path, &nd); | 494 | error = user_path_walk(path, &nd); |
483 | if (error) | 495 | if (error) |
484 | return error; | 496 | return error; |
485 | error = removexattr(nd.path.dentry, name); | 497 | error = mnt_want_write(nd.path.mnt); |
498 | if (!error) { | ||
499 | error = removexattr(nd.path.dentry, name); | ||
500 | mnt_drop_write(nd.path.mnt); | ||
501 | } | ||
486 | path_put(&nd.path); | 502 | path_put(&nd.path); |
487 | return error; | 503 | return error; |
488 | } | 504 | } |
@@ -496,7 +512,11 @@ sys_lremovexattr(char __user *path, char __user *name) | |||
496 | error = user_path_walk_link(path, &nd); | 512 | error = user_path_walk_link(path, &nd); |
497 | if (error) | 513 | if (error) |
498 | return error; | 514 | return error; |
499 | error = removexattr(nd.path.dentry, name); | 515 | error = mnt_want_write(nd.path.mnt); |
516 | if (!error) { | ||
517 | error = removexattr(nd.path.dentry, name); | ||
518 | mnt_drop_write(nd.path.mnt); | ||
519 | } | ||
500 | path_put(&nd.path); | 520 | path_put(&nd.path); |
501 | return error; | 521 | return error; |
502 | } | 522 | } |
@@ -513,7 +533,11 @@ sys_fremovexattr(int fd, char __user *name) | |||
513 | return error; | 533 | return error; |
514 | dentry = f->f_path.dentry; | 534 | dentry = f->f_path.dentry; |
515 | audit_inode(NULL, dentry); | 535 | audit_inode(NULL, dentry); |
516 | error = removexattr(dentry, name); | 536 | error = mnt_want_write(f->f_path.mnt); |
537 | if (!error) { | ||
538 | error = removexattr(dentry, name); | ||
539 | mnt_drop_write(f->f_path.mnt); | ||
540 | } | ||
517 | fput(f); | 541 | fput(f); |
518 | return error; | 542 | return error; |
519 | } | 543 | } |