aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/dir.c7
-rw-r--r--kernel/fuse_i.h4
-rw-r--r--kernel/inode.c13
3 files changed, 20 insertions, 4 deletions
diff --git a/kernel/dir.c b/kernel/dir.c
index 87dec6a..36eb3bf 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -505,7 +505,9 @@ static int fuse_revalidate(struct dentry *entry)
if (inode->i_ino == FUSE_ROOT_INO) {
if (!(fc->flags & FUSE_ALLOW_OTHER) &&
- current->fsuid != fc->uid)
+ current->fsuid != fc->uid &&
+ (!(fc->flags & FUSE_ALLOW_ROOT) ||
+ current->fsuid != 0))
return -EACCES;
} else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
return 0;
@@ -517,7 +519,8 @@ static int _fuse_permission(struct inode *inode, int mask)
{
struct fuse_conn *fc = INO_FC(inode);
- if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
+ if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
+ (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
return -EACCES;
else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
int err = vfs_permission(inode, mask);
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 5a4d7e7..8e3b416 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -73,6 +73,10 @@ permission checking is done in the kernel */
/** Bypass the page cache for read and write operations */
#define FUSE_DIRECT_IO (1 << 3)
+/** Allow root and setuid-root programs to access fuse-mounted
+ filesystems */
+#define FUSE_ALLOW_ROOT (1 << 4)
+
/** FUSE specific inode data */
struct fuse_inode {
struct fuse_req *forget_req;
diff --git a/kernel/inode.c b/kernel/inode.c
index 09479e1..8de566c 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -33,7 +33,7 @@ module_param(user_allow_other, int, 0);
MODULE_PARM(user_allow_other, "i");
#endif
-MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" mount option");
+MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options");
#define FUSE_SUPER_MAGIC 0x65735546
@@ -176,6 +176,7 @@ enum { opt_fd,
opt_uid,
opt_default_permissions,
opt_allow_other,
+ opt_allow_root,
opt_kernel_cache,
opt_large_read,
opt_direct_io,
@@ -188,6 +189,7 @@ static match_table_t tokens = {
{opt_uid, "uid=%u"},
{opt_default_permissions, "default_permissions"},
{opt_allow_other, "allow_other"},
+ {opt_allow_root, "allow_root"},
{opt_kernel_cache, "kernel_cache"},
{opt_large_read, "large_read"},
{opt_direct_io, "direct_io"},
@@ -237,6 +239,10 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
d->flags |= FUSE_ALLOW_OTHER;
break;
+ case opt_allow_root:
+ d->flags |= FUSE_ALLOW_ROOT;
+ break;
+
case opt_kernel_cache:
d->flags |= FUSE_KERNEL_CACHE;
break;
@@ -284,6 +290,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
seq_puts(m, ",default_permissions");
if (fc->flags & FUSE_ALLOW_OTHER)
seq_puts(m, ",allow_other");
+ if (fc->flags & FUSE_ALLOW_ROOT)
+ seq_puts(m, ",allow_root");
if (fc->flags & FUSE_KERNEL_CACHE)
seq_puts(m, ",kernel_cache");
#ifndef KERNEL_2_6
@@ -375,7 +383,8 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
if (!parse_fuse_opt((char *) data, &d))
return -EINVAL;
- if (!user_allow_other && (d.flags & FUSE_ALLOW_OTHER) &&
+ if (!user_allow_other &&
+ (d.flags & (FUSE_ALLOW_OTHER | FUSE_ALLOW_ROOT)) &&
current->uid != 0)
return -EPERM;