]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ceph: don't allow access to MDS-private inodes
authorJeff Layton <jlayton@kernel.org>
Thu, 1 Apr 2021 17:55:11 +0000 (13:55 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 22 May 2021 09:43:50 +0000 (11:43 +0200)
[ Upstream commit d4f6b31d721779d91b5e2f8072478af73b196c34 ]

The MDS reserves a set of inodes for its own usage, and these should
never be accessible to clients. Add a new helper to vet a proposed
inode number against that range, and complain loudly and refuse to
create or look it up if it's in it.

Also, ensure that the MDS doesn't try to delegate inodes that are in
that range or lower. Print a warning if it does, and don't save the
range in the xarray.

URL: https://tracker.ceph.com/issues/49922
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/ceph/export.c
fs/ceph/inode.c
fs/ceph/mds_client.c
fs/ceph/super.h

index baa6368bece59a5077ce1d343ac8b8e91b4e8fa4..042bb4a02c0a23f5a4d7fd764ed9d686a32c9dde 100644 (file)
@@ -129,6 +129,10 @@ static struct inode *__lookup_inode(struct super_block *sb, u64 ino)
 
        vino.ino = ino;
        vino.snap = CEPH_NOSNAP;
+
+       if (ceph_vino_is_reserved(vino))
+               return ERR_PTR(-ESTALE);
+
        inode = ceph_find_inode(sb, vino);
        if (!inode) {
                struct ceph_mds_request *req;
@@ -214,6 +218,10 @@ static struct dentry *__snapfh_to_dentry(struct super_block *sb,
                vino.ino = sfh->ino;
                vino.snap = sfh->snapid;
        }
+
+       if (ceph_vino_is_reserved(vino))
+               return ERR_PTR(-ESTALE);
+
        inode = ceph_find_inode(sb, vino);
        if (inode)
                return d_obtain_alias(inode);
index 2fd1c48ac5d7ce733cdbc0329e6d649692193855..179d2ef69a24ab689d44bb754a47c756809cb913 100644 (file)
@@ -56,6 +56,9 @@ struct inode *ceph_get_inode(struct super_block *sb, struct ceph_vino vino)
 {
        struct inode *inode;
 
+       if (ceph_vino_is_reserved(vino))
+               return ERR_PTR(-EREMOTEIO);
+
        inode = iget5_locked(sb, (unsigned long)vino.ino, ceph_ino_compare,
                             ceph_set_ino_cb, &vino);
        if (!inode)
index d87bd852ed961d3e99d676479bea899aacf65ac2..298cb0b3d28c0a47ca9be7f9642a2377f89ee836 100644 (file)
@@ -433,6 +433,13 @@ static int ceph_parse_deleg_inos(void **p, void *end,
 
                ceph_decode_64_safe(p, end, start, bad);
                ceph_decode_64_safe(p, end, len, bad);
+
+               /* Don't accept a delegation of system inodes */
+               if (start < CEPH_INO_SYSTEM_BASE) {
+                       pr_warn_ratelimited("ceph: ignoring reserved inode range delegation (start=0x%llx len=0x%llx)\n",
+                                       start, len);
+                       continue;
+               }
                while (len--) {
                        int err = xa_insert(&s->s_delegated_inos, ino = start++,
                                            DELEGATED_INO_AVAILABLE,
index c48bb30c8d70efc231400296dd7a8fa8bbbf15d6..1d2fe70439bd0e5adbb1d7908727629b16d5876a 100644 (file)
@@ -529,10 +529,34 @@ static inline int ceph_ino_compare(struct inode *inode, void *data)
                ci->i_vino.snap == pvino->snap;
 }
 
+/*
+ * The MDS reserves a set of inodes for its own usage. These should never
+ * be accessible by clients, and so the MDS has no reason to ever hand these
+ * out. The range is CEPH_MDS_INO_MDSDIR_OFFSET..CEPH_INO_SYSTEM_BASE.
+ *
+ * These come from src/mds/mdstypes.h in the ceph sources.
+ */
+#define CEPH_MAX_MDS           0x100
+#define CEPH_NUM_STRAY         10
+#define CEPH_MDS_INO_MDSDIR_OFFSET     (1 * CEPH_MAX_MDS)
+#define CEPH_INO_SYSTEM_BASE           ((6*CEPH_MAX_MDS) + (CEPH_MAX_MDS * CEPH_NUM_STRAY))
+
+static inline bool ceph_vino_is_reserved(const struct ceph_vino vino)
+{
+       if (vino.ino < CEPH_INO_SYSTEM_BASE &&
+           vino.ino >= CEPH_MDS_INO_MDSDIR_OFFSET) {
+               WARN_RATELIMIT(1, "Attempt to access reserved inode number 0x%llx", vino.ino);
+               return true;
+       }
+       return false;
+}
 
 static inline struct inode *ceph_find_inode(struct super_block *sb,
                                            struct ceph_vino vino)
 {
+       if (ceph_vino_is_reserved(vino))
+               return NULL;
+
        /*
         * NB: The hashval will be run through the fs/inode.c hash function
         * anyway, so there is no need to squash the inode number down to