aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/dev.c4
-rw-r--r--kernel/dir.c8
-rw-r--r--kernel/fuse_i.h8
-rw-r--r--kernel/inode.c8
4 files changed, 25 insertions, 3 deletions
diff --git a/kernel/dev.c b/kernel/dev.c
index 60a6bbf..f8b7f3a 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -131,7 +131,7 @@ static struct fuse_req *get_reserved_req(struct fuse_conn *fc,
struct fuse_file *ff = file->private_data;
do {
- wait_event(fc->blocked_waitq, ff->reserved_req);
+ wait_event(fc->reserved_req_waitq, ff->reserved_req);
spin_lock(&fc->lock);
if (ff->reserved_req) {
req = ff->reserved_req;
@@ -157,7 +157,7 @@ static void put_reserved_req(struct fuse_conn *fc, struct fuse_req *req)
fuse_request_init(req);
BUG_ON(ff->reserved_req);
ff->reserved_req = req;
- wake_up(&fc->blocked_waitq);
+ wake_up_all(&fc->reserved_req_waitq);
spin_unlock(&fc->lock);
fput(file);
}
diff --git a/kernel/dir.c b/kernel/dir.c
index b493e4e..c5316d9 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -720,7 +720,7 @@ int fuse_do_getattr(struct inode *inode)
* for which the owner of the mount has ptrace privilege. This
* excludes processes started by other users, suid or sgid processes.
*/
-static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
+int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
{
if (fc->flags & FUSE_ALLOW_OTHER)
return 1;
@@ -1059,6 +1059,9 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
int err;
int is_truncate = 0;
+ if (!fuse_allow_task(fc, current))
+ return -EACCES;
+
if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
err = inode_change_ok(inode, attr);
if (err)
@@ -1233,6 +1236,9 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
struct fuse_getxattr_out outarg;
ssize_t ret;
+ if (!fuse_allow_task(fc, current))
+ return -EACCES;
+
if (fc->no_listxattr)
return -EOPNOTSUPP;
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index f9803b4..3ea9a57 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -368,6 +368,9 @@ struct fuse_conn {
/** waitq for blocked connection */
wait_queue_head_t blocked_waitq;
+ /** waitq for reserved requests */
+ wait_queue_head_t reserved_req_waitq;
+
/** The next unique request id */
u64 reqctr;
@@ -639,3 +642,8 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc);
* Is file type valid?
*/
int fuse_valid_type(int m);
+
+/**
+ * Is task allowed to perform filesystem operation?
+ */
+int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task);
diff --git a/kernel/inode.c b/kernel/inode.c
index f52ee8b..8195f6e 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -258,6 +258,7 @@ static void fuse_put_super(struct super_block *sb)
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
wake_up_all(&fc->waitq);
wake_up_all(&fc->blocked_waitq);
+ wake_up_all(&fc->reserved_req_waitq);
mutex_lock(&fuse_mutex);
list_del(&fc->entry);
fuse_ctl_remove_conn(fc);
@@ -293,6 +294,11 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
struct fuse_statfs_out outarg;
int err;
+ if (!fuse_allow_task(fc, current)) {
+ buf->f_type = FUSE_SUPER_MAGIC;
+ return 0;
+ }
+
req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -469,6 +475,7 @@ static struct fuse_conn *new_conn(void)
atomic_set(&fc->count, 1);
init_waitqueue_head(&fc->waitq);
init_waitqueue_head(&fc->blocked_waitq);
+ init_waitqueue_head(&fc->reserved_req_waitq);
INIT_LIST_HEAD(&fc->pending);
INIT_LIST_HEAD(&fc->processing);
INIT_LIST_HEAD(&fc->io);
@@ -506,6 +513,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
attr.mode = mode;
attr.ino = FUSE_ROOT_ID;
+ attr.nlink = 1;
return fuse_iget(sb, 1, 0, &attr);
}
#ifndef FUSE_MAINLINE