]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/ceph/super.c
ceph: fix use-after-free in ceph_statfs()
[mirror_ubuntu-bionic-kernel.git] / fs / ceph / super.c
index a62d2a9841dc2b0487181155373c03eac60f8a02..23d9cfba27700e5efc8d40dfea016a3a2f5c46cc 100644 (file)
@@ -45,7 +45,7 @@ static void ceph_put_super(struct super_block *s)
 static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct ceph_fs_client *fsc = ceph_inode_to_client(d_inode(dentry));
-       struct ceph_monmap *monmap = fsc->client->monc.monmap;
+       struct ceph_mon_client *monc = &fsc->client->monc;
        struct ceph_statfs st;
        u64 fsid;
        int err;
@@ -58,7 +58,7 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
        }
 
        dout("statfs\n");
-       err = ceph_monc_do_statfs(&fsc->client->monc, data_pool, &st);
+       err = ceph_monc_do_statfs(monc, data_pool, &st);
        if (err < 0)
                return err;
 
@@ -85,8 +85,11 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_namelen = NAME_MAX;
 
        /* Must convert the fsid, for consistent values across arches */
-       fsid = le64_to_cpu(*(__le64 *)(&monmap->fsid)) ^
-              le64_to_cpu(*((__le64 *)&monmap->fsid + 1));
+       mutex_lock(&monc->mutex);
+       fsid = le64_to_cpu(*(__le64 *)(&monc->monmap->fsid)) ^
+              le64_to_cpu(*((__le64 *)&monc->monmap->fsid + 1));
+       mutex_unlock(&monc->mutex);
+
        buf->f_fsid.val[0] = fsid & 0xffffffff;
        buf->f_fsid.val[1] = fsid >> 32;
 
@@ -225,6 +228,7 @@ static int parse_fsopt_token(char *c, void *private)
                        return -ENOMEM;
                break;
        case Opt_mds_namespace:
+               kfree(fsopt->mds_namespace);
                fsopt->mds_namespace = kstrndup(argstr[0].from,
                                                argstr[0].to-argstr[0].from,
                                                GFP_KERNEL);
@@ -232,6 +236,7 @@ static int parse_fsopt_token(char *c, void *private)
                        return -ENOMEM;
                break;
        case Opt_fscache_uniq:
+               kfree(fsopt->fscache_uniq);
                fsopt->fscache_uniq = kstrndup(argstr[0].from,
                                               argstr[0].to-argstr[0].from,
                                               GFP_KERNEL);
@@ -253,7 +258,7 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_rasize:
                if (intval < 0)
                        return -EINVAL;
-               fsopt->rasize = ALIGN(intval + PAGE_SIZE - 1, PAGE_SIZE);
+               fsopt->rasize = ALIGN(intval, PAGE_SIZE);
                break;
        case Opt_caps_wanted_delay_min:
                if (intval < 1)
@@ -711,14 +716,17 @@ static int __init init_caches(void)
                goto bad_dentry;
 
        ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);
-
        if (!ceph_file_cachep)
                goto bad_file;
 
-       if ((error = ceph_fscache_register()))
-               goto bad_file;
+       error = ceph_fscache_register();
+       if (error)
+               goto bad_fscache;
 
        return 0;
+
+bad_fscache:
+       kmem_cache_destroy(ceph_file_cachep);
 bad_file:
        kmem_cache_destroy(ceph_dentry_cachep);
 bad_dentry:
@@ -836,7 +844,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
        int err;
        unsigned long started = jiffies;  /* note the start time */
        struct dentry *root;
-       int first = 0;   /* first vfsmount for this super_block */
 
        dout("mount start %p\n", fsc);
        mutex_lock(&fsc->client->mount_mutex);
@@ -861,17 +868,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
                        path = fsc->mount_options->server_path + 1;
                        dout("mount opening path %s\n", path);
                }
+
+               err = ceph_fs_debugfs_init(fsc);
+               if (err < 0)
+                       goto out;
+
                root = open_root_dentry(fsc, path, started);
                if (IS_ERR(root)) {
                        err = PTR_ERR(root);
                        goto out;
                }
                fsc->sb->s_root = dget(root);
-               first = 1;
-
-               err = ceph_fs_debugfs_init(fsc);
-               if (err < 0)
-                       goto fail;
        } else {
                root = dget(fsc->sb->s_root);
        }
@@ -881,11 +888,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
        mutex_unlock(&fsc->client->mount_mutex);
        return root;
 
-fail:
-       if (first) {
-               dput(fsc->sb->s_root);
-               fsc->sb->s_root = NULL;
-       }
 out:
        mutex_unlock(&fsc->client->mount_mutex);
        return ERR_PTR(err);