fix
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 13 Jan 2005 12:11:49 +0000 (12:11 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 13 Jan 2005 12:11:49 +0000 (12:11 +0000)
ChangeLog
kernel/dir.c
kernel/inode.c
util/fusermount.c

index 34fe25c9fe935163ea275af701cbe1cc95cd07d7..ace122cffc5b6f9d44dbe5460ab568f329a00498 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2005-01-13  Miklos Szeredi <miklos@szeredi.hu>
+
+       * 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 <miklos@szeredi.hu>
 
        * KERNEL: fix possible inode allocation problem, where
index e07ea79db06b1b3b24c1884255ce7055dec3106e..6d968edc1592cfaf7ae3efe4d244ad81ce8879e9 100644 (file)
@@ -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
index a3a709b078e5f9ccec659c0aa71e0a229cf3d6b4..a82a62abdce3f9882964d0b4d79d21f607a7a61f 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #ifdef KERNEL_2_6
-#include <linux/moduleparam.h>
 #include <linux/parser.h>
 #include <linux/statfs.h>
 #else
-#include <linux/proc_fs.h>
 #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);
index 259d0f77c58ecb2ba125039b3762a534f59d2f3e..9e39dbd019ac0eea09351660b7e10d98f618f0f3 100644 (file)
 #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;
         }
     }