aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2005-09-09 16:10:34 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 17:03:46 -0400
commit87729a5514e855ce2c71e3e33833a106b8caf2ae (patch)
treedd2e7a9fd96b2dd3ebc3951fef2d682e83aa6bb4
parentdb50b96c0f28a21c5a4a19ecaba12d0972aab06a (diff)
[PATCH] FUSE: tighten check for processes allowed access
This patch tightens the check for allowing processes to access non-privileged mounts. The rational is that the filesystem implementation can control the behavior or get otherwise unavailable information of the filesystem user. If the filesystem user process has the same uid, gid, and is not suid or sgid application, then access is safe. Otherwise access is not allowed unless the "allow_other" mount option is given (for which policy is controlled by the userspace mount utility). Thanks to everyone linux-fsdevel, especially Martin Mares who helped uncover problems with the previous approach. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/fuse/dir.c40
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/inode.c12
3 files changed, 49 insertions, 6 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index f127625543b4..65da6e1b6de5 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -411,17 +411,45 @@ int fuse_do_getattr(struct inode *inode)
411 return err; 411 return err;
412} 412}
413 413
414/*
415 * Calling into a user-controlled filesystem gives the filesystem
416 * daemon ptrace-like capabilities over the requester process. This
417 * means, that the filesystem daemon is able to record the exact
418 * filesystem operations performed, and can also control the behavior
419 * of the requester process in otherwise impossible ways. For example
420 * it can delay the operation for arbitrary length of time allowing
421 * DoS against the requester.
422 *
423 * For this reason only those processes can call into the filesystem,
424 * for which the owner of the mount has ptrace privilege. This
425 * excludes processes started by other users, suid or sgid processes.
426 */
427static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
428{
429 if (fc->flags & FUSE_ALLOW_OTHER)
430 return 1;
431
432 if (task->euid == fc->user_id &&
433 task->suid == fc->user_id &&
434 task->uid == fc->user_id &&
435 task->egid == fc->group_id &&
436 task->sgid == fc->group_id &&
437 task->gid == fc->group_id)
438 return 1;
439
440 return 0;
441}
442
414static int fuse_revalidate(struct dentry *entry) 443static int fuse_revalidate(struct dentry *entry)
415{ 444{
416 struct inode *inode = entry->d_inode; 445 struct inode *inode = entry->d_inode;
417 struct fuse_inode *fi = get_fuse_inode(inode); 446 struct fuse_inode *fi = get_fuse_inode(inode);
418 struct fuse_conn *fc = get_fuse_conn(inode); 447 struct fuse_conn *fc = get_fuse_conn(inode);
419 448
420 if (get_node_id(inode) == FUSE_ROOT_ID) { 449 if (!fuse_allow_task(fc, current))
421 if (!(fc->flags & FUSE_ALLOW_OTHER) && 450 return -EACCES;
422 current->fsuid != fc->user_id) 451 if (get_node_id(inode) != FUSE_ROOT_ID &&
423 return -EACCES; 452 time_before_eq(jiffies, fi->i_time))
424 } else if (time_before_eq(jiffies, fi->i_time))
425 return 0; 453 return 0;
426 454
427 return fuse_do_getattr(inode); 455 return fuse_do_getattr(inode);
@@ -431,7 +459,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
431{ 459{
432 struct fuse_conn *fc = get_fuse_conn(inode); 460 struct fuse_conn *fc = get_fuse_conn(inode);
433 461
434 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id) 462 if (!fuse_allow_task(fc, current))
435 return -EACCES; 463 return -EACCES;
436 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { 464 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
437 int err = generic_permission(inode, mask, NULL); 465 int err = generic_permission(inode, mask, NULL);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index aff3a01ea02b..3ec2aff3fdb5 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -198,6 +198,9 @@ struct fuse_conn {
198 /** The user id for this mount */ 198 /** The user id for this mount */
199 uid_t user_id; 199 uid_t user_id;
200 200
201 /** The group id for this mount */
202 gid_t group_id;
203
201 /** The fuse mount flags for this mount */ 204 /** The fuse mount flags for this mount */
202 unsigned flags; 205 unsigned flags;
203 206
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 0b75c73386e9..c8e54c0658f1 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -31,6 +31,7 @@ struct fuse_mount_data {
31 int fd; 31 int fd;
32 unsigned rootmode; 32 unsigned rootmode;
33 unsigned user_id; 33 unsigned user_id;
34 unsigned group_id;
34 unsigned flags; 35 unsigned flags;
35 unsigned max_read; 36 unsigned max_read;
36}; 37};
@@ -199,6 +200,7 @@ static void fuse_put_super(struct super_block *sb)
199 spin_lock(&fuse_lock); 200 spin_lock(&fuse_lock);
200 fc->mounted = 0; 201 fc->mounted = 0;
201 fc->user_id = 0; 202 fc->user_id = 0;
203 fc->group_id = 0;
202 fc->flags = 0; 204 fc->flags = 0;
203 /* Flush all readers on this fs */ 205 /* Flush all readers on this fs */
204 wake_up_all(&fc->waitq); 206 wake_up_all(&fc->waitq);
@@ -248,6 +250,7 @@ enum {
248 OPT_FD, 250 OPT_FD,
249 OPT_ROOTMODE, 251 OPT_ROOTMODE,
250 OPT_USER_ID, 252 OPT_USER_ID,
253 OPT_GROUP_ID,
251 OPT_DEFAULT_PERMISSIONS, 254 OPT_DEFAULT_PERMISSIONS,
252 OPT_ALLOW_OTHER, 255 OPT_ALLOW_OTHER,
253 OPT_KERNEL_CACHE, 256 OPT_KERNEL_CACHE,
@@ -259,6 +262,7 @@ static match_table_t tokens = {
259 {OPT_FD, "fd=%u"}, 262 {OPT_FD, "fd=%u"},
260 {OPT_ROOTMODE, "rootmode=%o"}, 263 {OPT_ROOTMODE, "rootmode=%o"},
261 {OPT_USER_ID, "user_id=%u"}, 264 {OPT_USER_ID, "user_id=%u"},
265 {OPT_GROUP_ID, "group_id=%u"},
262 {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, 266 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
263 {OPT_ALLOW_OTHER, "allow_other"}, 267 {OPT_ALLOW_OTHER, "allow_other"},
264 {OPT_KERNEL_CACHE, "kernel_cache"}, 268 {OPT_KERNEL_CACHE, "kernel_cache"},
@@ -300,6 +304,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
300 d->user_id = value; 304 d->user_id = value;
301 break; 305 break;
302 306
307 case OPT_GROUP_ID:
308 if (match_int(&args[0], &value))
309 return 0;
310 d->group_id = value;
311 break;
312
303 case OPT_DEFAULT_PERMISSIONS: 313 case OPT_DEFAULT_PERMISSIONS:
304 d->flags |= FUSE_DEFAULT_PERMISSIONS; 314 d->flags |= FUSE_DEFAULT_PERMISSIONS;
305 break; 315 break;
@@ -333,6 +343,7 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
333 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb); 343 struct fuse_conn *fc = get_fuse_conn_super(mnt->mnt_sb);
334 344
335 seq_printf(m, ",user_id=%u", fc->user_id); 345 seq_printf(m, ",user_id=%u", fc->user_id);
346 seq_printf(m, ",group_id=%u", fc->group_id);
336 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) 347 if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
337 seq_puts(m, ",default_permissions"); 348 seq_puts(m, ",default_permissions");
338 if (fc->flags & FUSE_ALLOW_OTHER) 349 if (fc->flags & FUSE_ALLOW_OTHER)
@@ -465,6 +476,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
465 476
466 fc->flags = d.flags; 477 fc->flags = d.flags;
467 fc->user_id = d.user_id; 478 fc->user_id = d.user_id;
479 fc->group_id = d.group_id;
468 fc->max_read = d.max_read; 480 fc->max_read = d.max_read;
469 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) 481 if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages)
470 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; 482 fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE;