diff options
-rw-r--r-- | fs/fuse/dir.c | 40 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
-rw-r--r-- | fs/fuse/inode.c | 12 |
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 | */ | ||
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); |
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; |