From: Miklos Szeredi Date: Thu, 13 Jan 2005 12:11:49 +0000 (+0000) Subject: fix X-Git-Tag: fuse_2_2_pre4~5 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=9ed69ba6898c5b1bdceddcf96bf3d92ba943892d;p=qemu-gpiodev%2Flibfuse.git fix --- diff --git a/ChangeLog b/ChangeLog index 34fe25c..ace122c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2005-01-13 Miklos Szeredi + + * Remove 'mount_max' and 'user_allow_other' module options. These + are now checked by fusermount, and can be set in /etc/fuse.conf + + * KERNEL: change check for fsid == 0 to capable(CAP_DAC_OVERRIDE) + 2005-01-11 Miklos Szeredi * KERNEL: fix possible inode allocation problem, where diff --git a/kernel/dir.c b/kernel/dir.c index e07ea79..6d968ed 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -438,7 +438,7 @@ static int fuse_revalidate(struct dentry *entry) if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id && (!(fc->flags & FUSE_ALLOW_ROOT) || - current->fsuid != 0)) + !capable(CAP_DAC_OVERRIDE))) return -EACCES; } else if (time_before_eq(jiffies, fi->i_time)) return 0; @@ -451,7 +451,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) struct fuse_conn *fc = get_fuse_conn(inode); if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id && - (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0)) + (!(fc->flags & FUSE_ALLOW_ROOT) || !capable(CAP_DAC_OVERRIDE))) return -EACCES; else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { #ifdef KERNEL_2_6_10_PLUS diff --git a/kernel/inode.c b/kernel/inode.c index a3a709b..a82a62a 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -16,11 +16,9 @@ #include #include #ifdef KERNEL_2_6 -#include #include #include #else -#include #include "compat/parser.h" #endif @@ -32,23 +30,6 @@ MODULE_LICENSE("GPL"); spinlock_t fuse_lock; static kmem_cache_t *fuse_inode_cachep; -static int mount_count; - -static int user_allow_other; -#ifdef KERNEL_2_6 -module_param(user_allow_other, int, 0644); -#else -MODULE_PARM(user_allow_other, "i"); -#endif -MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options"); - -static int mount_max = 1000; -#ifdef KERNEL_2_6 -module_param(mount_max, int, 0644); -#else -MODULE_PARM(mount_max, "i"); -#endif -MODULE_PARM_DESC(mount_max, "Maximum number of FUSE mounts allowed, if -1 then unlimited (default: 1000)"); #define FUSE_SUPER_MAGIC 0x65735546 @@ -277,7 +258,6 @@ static void fuse_put_super(struct super_block *sb) struct fuse_conn *fc = get_fuse_conn_super(sb); spin_lock(&fuse_lock); - mount_count --; fc->sb = NULL; fc->user_id = 0; fc->flags = 0; @@ -609,17 +589,6 @@ static struct super_operations fuse_super_operations = { .show_options = fuse_show_options, }; -static int inc_mount_count(void) -{ - int success = 0; - spin_lock(&fuse_lock); - mount_count ++; - if (mount_max == -1 || mount_count <= mount_max) - success = 1; - spin_unlock(&fuse_lock); - return success; -} - static int fuse_fill_super(struct super_block *sb, void *data, int silent) { struct fuse_conn *fc; @@ -631,11 +600,6 @@ static int fuse_fill_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 | FUSE_ALLOW_ROOT)) && - current->uid != 0) - return -EPERM; - sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = FUSE_SUPER_MAGIC; @@ -665,10 +629,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) *get_fuse_conn_super_p(sb) = fc; - err = -ENFILE; - if (!inc_mount_count() && current->uid != 0) - goto err; - err = -ENOMEM; root = get_root_inode(sb, d.rootmode); if (root == NULL) @@ -684,7 +644,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err: spin_lock(&fuse_lock); - mount_count --; fc->sb = NULL; fuse_release_conn(fc); spin_unlock(&fuse_lock); diff --git a/util/fusermount.c b/util/fusermount.c index 259d0f7..9e39dbd 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -40,10 +40,14 @@ #define FUSE_DEV_OLD "/proc/fs/fuse/dev" #define FUSE_DEV_NEW "/dev/fuse" #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version" +#define FUSE_CONF "/etc/fuse.conf" #define FUSE_MAJOR 10 #define FUSE_MINOR 229 -const char *progname; +static const char *progname; + +static int user_allow_other = 0; +static int mount_max = 1000; static const char *get_user_name() { @@ -156,9 +160,9 @@ static int lock_mtab() if (mtablock >= 0) { res = lockf(mtablock, F_LOCK, 0); if (res < 0) - perror("error getting lock"); + fprintf(stderr, "%s: error getting lock", progname); } else - fprintf(stderr, "unable to open fuse lock file, continuing anyway\n"); + fprintf(stderr, "%s: unable to open fuse lock file\n", progname); return mtablock; } @@ -215,14 +219,14 @@ static int remove_mount(const char *mnt, int quiet, const char *mtab, fp = setmntent(mtab, "r"); if (fp == NULL) { - fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab, + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab, strerror(errno)); return -1; } newfp = setmntent(mtab_new, "w"); if (newfp == NULL) { - fprintf(stderr, "%s failed to open %s: %s\n", progname, mtab_new, + fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab_new, strerror(errno)); return -1; } @@ -272,6 +276,24 @@ static int remove_mount(const char *mnt, int quiet, const char *mtab, return 0; } +static int count_fuse_fs() +{ + struct mntent *entp; + int count = 0; + const char *mtab = _PATH_MOUNTED; + FILE *fp = setmntent(mtab, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: faild to open %s: %s\n", progname, mtab, + strerror(errno)); + return -1; + } + while ((entp = getmntent(fp)) != NULL) { + if (strcmp(entp->mnt_type, "fuse") == 0) + count ++; + } + endmntent(fp); + return count; +} static int do_unmount(const char *mnt, int quiet, int lazy, const char *mtab, const char *mtab_new) @@ -321,6 +343,32 @@ static int unmount_fuse(const char *mnt, int quiet, int lazy) } #endif /* USE_UCLIBC */ +static void read_conf(void) +{ + FILE *fp = fopen(FUSE_CONF, "r"); + if (fp != NULL) { + char line[256]; + int isnewline = 1; + while (fgets(line, sizeof(line), fp) != NULL) { + if (isnewline) { + int tmp; + if (strcmp(line, "user_allow_other\n") == 0) + user_allow_other = 1; + else if (sscanf(line, "mount_max = %i\n", &tmp) == 1) + mount_max = tmp; + } + if(line[strlen(line)-1] == '\n') + isnewline = 1; + else + isnewline = 0; + } + fclose(fp); + } else if (errno != ENOENT) { + fprintf(stderr, "%s: failed to open %s: %s\n", progname, FUSE_CONF, + strerror(errno)); + } +} + static int begins_with(const char *s, const char *beg) { if (strncmp(s, beg, strlen(beg)) == 0) @@ -424,6 +472,14 @@ static int get_mnt_opts(int flags, char *opts, char **mnt_optsp) return 0; } +static int opt_eq(const char *s, unsigned len, const char *opt) +{ + if(strlen(opt) == len && strncmp(s, opt, len) == 0) + return 1; + else + return 0; +} + static int do_mount(const char *mnt, const char *type, mode_t rootmode, int fd, const char *opts, const char *dev, char **fsnamep, char **mnt_optsp) @@ -464,9 +520,7 @@ static int do_mount(const char *mnt, const char *type, mode_t rootmode, int on; int flag; int skip_option = 0; - const char *large_read_opt = "large_read"; - if (len == strlen(large_read_opt) && - strncmp(large_read_opt, s, len) == 0) { + if (opt_eq(s, len, "large_read")) { struct utsname utsname; unsigned kmaj, kmin; res = uname(&utsname); @@ -477,6 +531,13 @@ static int do_mount(const char *mnt, const char *type, mode_t rootmode, skip_option = 1; } } + if (getuid() != 0 && !user_allow_other && + (opt_eq(s, len, "allow_other") || + opt_eq(s, len, "allow_root"))) { + fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in /etc/fuse.conf\n", progname, len, s); + free(optbuf); + return -1; + } if (!skip_option) { if (find_mount_flag(s, len, &on, &flag)) { if (on) @@ -713,7 +774,8 @@ static int open_fuse_device(char **devp) if (fd >= 0) return fd; - fprintf(stderr, "fuse device not found, try 'modprobe fuse' first\n"); + fprintf(stderr, "%s: fuse device not found, try 'modprobe fuse' first\n", + progname); return -1; } @@ -729,15 +791,45 @@ static int mount_fuse(const char *mnt, const char *opts) char *mnt_opts; const char *real_mnt = mnt; int currdir_fd = -1; + int mtablock = -1; fd = open_fuse_device(&dev); if (fd == -1) return -1; - + +#ifndef USE_UCLIBC + if (geteuid() == 0) { + mtablock = lock_mtab(); + if (mtablock < 0) { + close(fd); + return -1; + } + } +#endif + if (getuid() != 0) { res = drop_privs(); - if (res == -1) + if (res == -1) { + close(fd); +#ifndef USE_UCLIBC + unlock_mtab(mtablock); +#endif return -1; + } + } + + read_conf(); + + if (getuid != 0 && mount_max != -1) { + int mount_count = count_fuse_fs(); + if (mount_count >= mount_max) { + fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in /etc/fuse.conf\n", progname); + close(fd); +#ifndef USE_UCLIBC + unlock_mtab(mtablock); +#endif + return -1; + } } res = check_version(dev); @@ -751,8 +843,13 @@ static int mount_fuse(const char *mnt, const char *opts) if (getuid() != 0) restore_privs(); - if (res == -1) + if (res == -1) { + close(fd); +#ifndef USE_UCLIBC + unlock_mtab(mtablock); +#endif return -1; + } if (currdir_fd != -1) { fchdir(currdir_fd); @@ -761,11 +858,11 @@ static int mount_fuse(const char *mnt, const char *opts) #ifndef USE_UCLIBC if (geteuid() == 0) { - int mtablock = lock_mtab(); res = add_mount(fsname, mnt, type, mnt_opts); unlock_mtab(mtablock); if (res == -1) { umount2(mnt, 2); /* lazy umount */ + close(fd); return -1; } }