aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2005-04-22 12:04:55 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2005-04-22 12:04:55 +0000
commit0111f9dbe43a8c4ae516d3eb470186770894c5bf (patch)
tree6112c59cbfcebc262d88ae10d1e06d92e0fcd142
parentd001bf9915e651dd301c29aafe0b7e777a1ae7cf (diff)
downloadlibfuse-0111f9dbe43a8c4ae516d3eb470186770894c5bf.tar.gz
fix
-rw-r--r--ChangeLog6
-rw-r--r--kernel/dev.c14
-rw-r--r--kernel/dir.c7
-rw-r--r--kernel/fuse_i.h17
-rw-r--r--kernel/inode.c32
-rw-r--r--lib/fuse.c19
-rw-r--r--lib/fuse_i.h1
-rw-r--r--lib/helper.c6
8 files changed, 56 insertions, 46 deletions
diff --git a/ChangeLog b/ChangeLog
index 94327f4..5415803 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,12 @@
* Fix buggy behavior of open(..., O_CREAT|O_EXCL) if interrupted.
Reported by David Shaw
+ * Remove "allow_root" option from kernel module, and implement
+ it's functionality in the library
+
+ * Fix Oops caused by premature release of fuse_conn. Clean up
+ related code, to be more readable
+
2005-04-08 Miklos Szeredi <miklos@szeredi.hu>
* Fix Oops in case of nfs export. Spotted by David Shaw
diff --git a/kernel/dev.c b/kernel/dev.c
index 29a9b63..d64423e 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -24,7 +24,7 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file)
struct fuse_conn *fc;
spin_lock(&fuse_lock);
fc = file->private_data;
- if (fc && !fc->sb)
+ if (fc && !fc->mounted)
fc = NULL;
spin_unlock(&fuse_lock);
return fc;
@@ -214,7 +214,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
spin_unlock(&fuse_lock);
if (req->background) {
down_read(&fc->sbput_sem);
- if (fc->sb)
+ if (fc->mounted)
fuse_release_background(req);
up_read(&fc->sbput_sem);
}
@@ -371,7 +371,7 @@ static void request_send_wait(struct fuse_conn *fc, struct fuse_req *req,
{
req->isreply = 1;
spin_lock(&fuse_lock);
- if (!fc->file)
+ if (!fc->connected)
req->out.h.error = -ENOTCONN;
else if (fc->conn_error)
req->out.h.error = -ECONNREFUSED;
@@ -404,7 +404,7 @@ void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req)
static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req)
{
spin_lock(&fuse_lock);
- if (fc->file) {
+ if (fc->connected) {
queue_request(fc, req);
spin_unlock(&fuse_lock);
} else {
@@ -659,7 +659,7 @@ static void request_wait(struct fuse_conn *fc)
DECLARE_WAITQUEUE(wait, current);
add_wait_queue_exclusive(&fc->waitq, &wait);
- while (fc->sb && list_empty(&fc->pending)) {
+ while (fc->mounted && list_empty(&fc->pending)) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current))
break;
@@ -709,7 +709,7 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
goto err_unlock;
request_wait(fc);
err = -ENODEV;
- if (!fc->sb)
+ if (!fc->mounted)
goto err_unlock;
err = -ERESTARTSYS;
if (list_empty(&fc->pending))
@@ -917,7 +917,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
spin_lock(&fuse_lock);
fc = file->private_data;
if (fc) {
- fc->file = NULL;
+ fc->connected = 0;
end_requests(fc, &fc->pending);
end_requests(fc, &fc->processing);
fuse_release_conn(fc);
diff --git a/kernel/dir.c b/kernel/dir.c
index 6ae498c..947d538 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -441,9 +441,7 @@ static int fuse_revalidate(struct dentry *entry)
if (get_node_id(inode) == FUSE_ROOT_ID) {
if (!(fc->flags & FUSE_ALLOW_OTHER) &&
- current->fsuid != fc->user_id &&
- (!(fc->flags & FUSE_ALLOW_ROOT) ||
- !capable(CAP_DAC_OVERRIDE)))
+ current->fsuid != fc->user_id)
return -EACCES;
} else if (time_before_eq(jiffies, fi->i_time))
return 0;
@@ -455,8 +453,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) || !capable(CAP_DAC_OVERRIDE)))
+ if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id)
return -EACCES;
else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
#ifdef KERNEL_2_6_10_PLUS
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index 373f36d..164eaa7 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -101,10 +101,6 @@ static inline void set_page_dirty_lock(struct page *page)
/** 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 inode */
struct fuse_inode {
/** Inode data */
@@ -260,11 +256,8 @@ struct fuse_req {
* unmounted.
*/
struct fuse_conn {
- /** The superblock of the mounted filesystem */
- struct super_block *sb;
-
- /** The opened client device */
- struct file *file;
+ /** Reference count */
+ int count;
/** The user id for this mount */
uid_t user_id;
@@ -307,6 +300,12 @@ struct fuse_conn {
/** The next unique request id */
int reqctr;
+ /** Mount is active */
+ unsigned mounted : 1;
+
+ /** Connection established */
+ unsigned connected : 1;
+
/** Connection failed (version mismatch) */
unsigned conn_error : 1;
diff --git a/kernel/inode.c b/kernel/inode.c
index 1feaba9..9b894f5 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -99,8 +99,8 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
static void fuse_clear_inode(struct inode *inode)
{
- struct fuse_conn *fc = get_fuse_conn(inode);
- if (fc && (inode->i_sb->s_flags & MS_ACTIVE)) {
+ if (inode->i_sb->s_flags & MS_ACTIVE) {
+ struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
fuse_send_forget(fc, fi->forget_req, fi->nodeid, inode->i_version);
fi->forget_req = NULL;
@@ -260,14 +260,13 @@ static void fuse_put_super(struct super_block *sb)
struct fuse_req, bg_entry));
spin_lock(&fuse_lock);
- fc->sb = NULL;
+ fc->mounted = 0;
fc->user_id = 0;
fc->flags = 0;
/* Flush all readers on this fs */
wake_up_all(&fc->waitq);
up_write(&fc->sbput_sem);
fuse_release_conn(fc);
- *get_fuse_conn_super_p(sb) = NULL;
spin_unlock(&fuse_lock);
}
@@ -314,7 +313,6 @@ enum {
OPT_USER_ID,
OPT_DEFAULT_PERMISSIONS,
OPT_ALLOW_OTHER,
- OPT_ALLOW_ROOT,
OPT_KERNEL_CACHE,
#ifndef KERNEL_2_6
OPT_LARGE_READ,
@@ -330,7 +328,6 @@ static match_table_t tokens = {
{OPT_USER_ID, "user_id=%u"},
{OPT_DEFAULT_PERMISSIONS, "default_permissions"},
{OPT_ALLOW_OTHER, "allow_other"},
- {OPT_ALLOW_ROOT, "allow_root"},
{OPT_KERNEL_CACHE, "kernel_cache"},
#ifndef KERNEL_2_6
{OPT_LARGE_READ, "large_read"},
@@ -382,10 +379,6 @@ 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;
@@ -424,8 +417,6 @@ 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
@@ -453,7 +444,8 @@ static void free_conn(struct fuse_conn *fc)
/* Must be called with the fuse lock held */
void fuse_release_conn(struct fuse_conn *fc)
{
- if (!fc->sb && !fc->file)
+ fc->count--;
+ if (!fc->count)
free_conn(fc);
}
@@ -465,10 +457,6 @@ static struct fuse_conn *new_conn(void)
if (fc != NULL) {
int i;
memset(fc, 0, sizeof(*fc));
- fc->sb = NULL;
- fc->file = NULL;
- fc->flags = 0;
- fc->user_id = 0;
init_waitqueue_head(&fc->waitq);
INIT_LIST_HEAD(&fc->pending);
INIT_LIST_HEAD(&fc->processing);
@@ -508,8 +496,10 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
fc = ERR_PTR(-EINVAL);
} else {
file->private_data = fc;
- fc->sb = sb;
- fc->file = file;
+ *get_fuse_conn_super_p(sb) = fc;
+ fc->mounted = 1;
+ fc->connected = 1;
+ fc->count = 2;
}
spin_unlock(&fuse_lock);
return fc;
@@ -636,8 +626,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
#endif
fc->max_write = FUSE_MAX_IN / 2;
- *get_fuse_conn_super_p(sb) = fc;
-
err = -ENOMEM;
root = get_root_inode(sb, d.rootmode);
if (root == NULL)
@@ -653,10 +641,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
err:
spin_lock(&fuse_lock);
- fc->sb = NULL;
fuse_release_conn(fc);
spin_unlock(&fuse_lock);
- *get_fuse_conn_super_p(sb) = NULL;
return err;
}
diff --git a/lib/fuse.c b/lib/fuse.c
index 82adeb2..9659a0d 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -35,6 +35,9 @@
/** Use st_ino field in getattr instead of generating inode numbers */
#define FUSE_USE_INO (1 << 3)
+/** Only allow root or the owner to access the filesystem */
+#define FUSE_ALLOW_ROOT (1 << 4)
+
#define FUSE_KERNEL_MINOR_VERSION_NEED 1
#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
#define FUSE_VERSION_FILE_NEW "/sys/fs/fuse/version"
@@ -1765,6 +1768,15 @@ void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
goto out;
}
+ if ((f->flags & FUSE_ALLOW_ROOT) && in->uid != f->owner && in->uid != 0 &&
+ in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
+ in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
+ in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
+ in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
+ send_reply(f, in, -EACCES, NULL, 0);
+ goto out;
+ }
+
ctx->fuse = f;
ctx->uid = in->uid;
ctx->gid = in->gid;
@@ -2000,7 +2012,8 @@ int fuse_is_lib_option(const char *opt)
{
if (strcmp(opt, "debug") == 0 ||
strcmp(opt, "hard_remove") == 0 ||
- strcmp(opt, "use_ino") == 0)
+ strcmp(opt, "use_ino") == 0 ||
+ strcmp(opt, "allow_root") == 0)
return 1;
else
return 0;
@@ -2025,6 +2038,8 @@ static int parse_lib_opts(struct fuse *f, const char *opts)
f->flags |= FUSE_HARD_REMOVE;
else if (strcmp(opt, "use_ino") == 0)
f->flags |= FUSE_USE_INO;
+ else if (strcmp(opt, "allow_root") == 0)
+ f->flags |= FUSE_ALLOW_ROOT;
else
fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
}
@@ -2100,6 +2115,8 @@ struct fuse *fuse_new_common(int fd, const char *opts,
root->refctr = 1;
hash_id(f, root);
+ f->owner = getuid();
+
return f;
out_free_root:
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 4a9f04a..3bdfb00 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -32,6 +32,7 @@ struct fuse {
void *user_data;
int major;
int minor;
+ uid_t owner;
};
struct fuse *fuse_new_common(int fd, const char *opts,
diff --git a/lib/helper.c b/lib/helper.c
index 42fe44c..d1a3d1f 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -138,8 +138,12 @@ static int add_options(char **lib_optp, char **kernel_optp, const char *opts)
while((opt = strsep(&s, ",")) != NULL) {
int res;
- if (fuse_is_lib_option(opt))
+ if (fuse_is_lib_option(opt)) {
res = add_option_to(opt, lib_optp);
+ /* Compatibility hack */
+ if (strcmp(opt, "allow_root") == 0 && res != -1)
+ res = add_option_to("allow_other", kernel_optp);
+ }
else
res = add_option_to(opt, kernel_optp);
if (res == -1) {