]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/fuse/dev.c
fuse: fix unlocked access to processing queue
[mirror_ubuntu-bionic-kernel.git] / fs / fuse / dev.c
index 17f0d05bfd4c4b4dc9a877832ac3d7f88f0acbaa..b28cbc0532ce082dcd1e76b0de248c362afc60b2 100644 (file)
@@ -114,8 +114,8 @@ static void __fuse_put_request(struct fuse_req *req)
 
 static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
 {
-       req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
-       req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
+       req->in.h.uid = from_kuid(fc->user_ns, current_fsuid());
+       req->in.h.gid = from_kgid(fc->user_ns, current_fsgid());
        req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
 }
 
@@ -167,6 +167,10 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
        __set_bit(FR_WAITING, &req->flags);
        if (for_background)
                __set_bit(FR_BACKGROUND, &req->flags);
+       if (req->in.h.uid == (uid_t)-1 || req->in.h.gid == (gid_t)-1) {
+               fuse_put_request(fc, req);
+               return ERR_PTR(-EOVERFLOW);
+       }
 
        return req;
 
@@ -364,7 +368,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
        struct fuse_iqueue *fiq = &fc->iq;
 
        if (test_and_set_bit(FR_FINISHED, &req->flags))
-               return;
+               goto out_put_req;
 
        spin_lock(&fiq->waitq.lock);
        list_del_init(&req->intr_entry);
@@ -381,8 +385,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
                if (!fc->blocked && waitqueue_active(&fc->blocked_waitq))
                        wake_up(&fc->blocked_waitq);
 
-               if (fc->num_background == fc->congestion_threshold &&
-                   fc->connected && fc->sb) {
+               if (fc->num_background == fc->congestion_threshold && fc->sb) {
                        clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);
                        clear_bdi_congested(fc->sb->s_bdi, BLK_RW_ASYNC);
                }
@@ -394,6 +397,7 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
        wake_up(&req->waitq);
        if (req->end)
                req->end(fc, req);
+out_put_req:
        fuse_put_request(fc, req);
 }
 
@@ -1222,6 +1226,9 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
        struct fuse_in *in;
        unsigned reqsize;
 
+       if (current_user_ns() != fc->user_ns)
+               return -EIO;
+
  restart:
        spin_lock(&fiq->waitq.lock);
        err = -EAGAIN;
@@ -1827,6 +1834,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
        struct fuse_req *req;
        struct fuse_out_header oh;
 
+       if (current_user_ns() != fc->user_ns)
+               return -EIO;
+
        if (nbytes < sizeof(struct fuse_out_header))
                return -EINVAL;
 
@@ -2101,6 +2111,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
                                set_bit(FR_ABORTED, &req->flags);
                                if (!test_bit(FR_LOCKED, &req->flags)) {
                                        set_bit(FR_PRIVATE, &req->flags);
+                                       __fuse_get_request(req);
                                        list_move(&req->list, &to_end1);
                                }
                                spin_unlock(&req->waitq.lock);
@@ -2127,7 +2138,6 @@ void fuse_abort_conn(struct fuse_conn *fc)
 
                while (!list_empty(&to_end1)) {
                        req = list_first_entry(&to_end1, struct fuse_req, list);
-                       __fuse_get_request(req);
                        list_del_init(&req->list);
                        request_end(fc, req);
                }
@@ -2145,9 +2155,15 @@ int fuse_dev_release(struct inode *inode, struct file *file)
        if (fud) {
                struct fuse_conn *fc = fud->fc;
                struct fuse_pqueue *fpq = &fud->pq;
+               LIST_HEAD(to_end);
 
+               spin_lock(&fpq->lock);
                WARN_ON(!list_empty(&fpq->io));
-               end_requests(fc, &fpq->processing);
+               list_splice_init(&fpq->processing, &to_end);
+               spin_unlock(&fpq->lock);
+
+               end_requests(fc, &to_end);
+
                /* Are we the last open device? */
                if (atomic_dec_and_test(&fc->dev_count)) {
                        WARN_ON(fc->iq.fasync != NULL);