diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 40 |
1 files changed, 34 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 | */ | ||
427 | static 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 | |||
414 | static int fuse_revalidate(struct dentry *entry) | 443 | static 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); |