aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2005-01-13 12:11:49 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2005-01-13 12:11:49 +0000
commit9ed69ba6898c5b1bdceddcf96bf3d92ba943892d (patch)
tree5bf0a4281f2a00b4b543f93115f1a02ffda81c1f
parent4fcbff6cf3006745845e168537a8bdfaf73722f0 (diff)
downloadlibfuse-9ed69ba6898c5b1bdceddcf96bf3d92ba943892d.tar.gz
fix
-rw-r--r--ChangeLog7
-rw-r--r--kernel/dir.c4
-rw-r--r--kernel/inode.c41
-rw-r--r--util/fusermount.c123
4 files changed, 119 insertions, 56 deletions
diff --git a/ChangeLog b/ChangeLog
index 34fe25c..ace122c 100644
--- 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
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 <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);
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;
}
}