Skip to content

Commit 7987cce

Browse files
dubeykoidryomov
authored andcommitted
ceph: fix NULL pointer dereference in ceph_mds_auth_match()
The CephFS kernel client has regression starting from 6.18-rc1. We have issue in ceph_mds_auth_match() if fs_name == NULL: const char fs_name = mdsc->fsc->mount_options->mds_namespace; ... if (auth->match.fs_name && strcmp(auth->match.fs_name, fs_name)) { / fsname mismatch, try next one */ return 0; } Patrick Donnelly suggested that: In summary, we should definitely start decoding `fs_name` from the MDSMap and do strict authorizations checks against it. Note that the `-o mds_namespace=foo` should only be used for selecting the file system to mount and nothing else. It's possible no mds_namespace is specified but the kernel will mount the only file system that exists which may have name "foo". This patch reworks ceph_mdsmap_decode() and namespace_equals() with the goal of supporting the suggested concept. Now struct ceph_mdsmap contains m_fs_name field that receives copy of extracted FS name by ceph_extract_encoded_string(). For the case of "old" CephFS file systems, it is used "cephfs" name. [ idryomov: replace redundant %*pE with %s in ceph_mdsmap_decode(), get rid of a series of strlen() calls in ceph_namespace_match(), drop changes to namespace_equals() body to avoid treating empty mds_namespace as equal, drop changes to ceph_mdsc_handle_fsmap() as namespace_equals() isn't an equivalent substitution there ] Cc: [email protected] Fixes: 22c73d5 ("ceph: fix multifs mds auth caps issue") Link: https://tracker.ceph.com/issues/73886 Signed-off-by: Viacheslav Dubeyko <[email protected]> Reviewed-by: Patrick Donnelly <[email protected]> Tested-by: Patrick Donnelly <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent bc8deda commit 7987cce

5 files changed

Lines changed: 43 additions & 11 deletions

File tree

fs/ceph/mds_client.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5671,15 +5671,16 @@ static int ceph_mds_auth_match(struct ceph_mds_client *mdsc,
56715671
u32 caller_uid = from_kuid(&init_user_ns, cred->fsuid);
56725672
u32 caller_gid = from_kgid(&init_user_ns, cred->fsgid);
56735673
struct ceph_client *cl = mdsc->fsc->client;
5674-
const char *fs_name = mdsc->fsc->mount_options->mds_namespace;
5674+
const char *fs_name = mdsc->mdsmap->m_fs_name;
56755675
const char *spath = mdsc->fsc->mount_options->server_path;
56765676
bool gid_matched = false;
56775677
u32 gid, tlen, len;
56785678
int i, j;
56795679

56805680
doutc(cl, "fsname check fs_name=%s match.fs_name=%s\n",
56815681
fs_name, auth->match.fs_name ? auth->match.fs_name : "");
5682-
if (auth->match.fs_name && strcmp(auth->match.fs_name, fs_name)) {
5682+
5683+
if (!ceph_namespace_match(auth->match.fs_name, fs_name)) {
56835684
/* fsname mismatch, try next one */
56845685
return 0;
56855686
}

fs/ceph/mdsmap.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -353,22 +353,33 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p,
353353
__decode_and_drop_type(p, end, u8, bad_ext);
354354
}
355355
if (mdsmap_ev >= 8) {
356-
u32 fsname_len;
356+
size_t fsname_len;
357+
357358
/* enabled */
358359
ceph_decode_8_safe(p, end, m->m_enabled, bad_ext);
360+
359361
/* fs_name */
360-
ceph_decode_32_safe(p, end, fsname_len, bad_ext);
362+
m->m_fs_name = ceph_extract_encoded_string(p, end,
363+
&fsname_len,
364+
GFP_NOFS);
365+
if (IS_ERR(m->m_fs_name)) {
366+
m->m_fs_name = NULL;
367+
goto nomem;
368+
}
361369

362370
/* validate fsname against mds_namespace */
363-
if (!namespace_equals(mdsc->fsc->mount_options, *p,
371+
if (!namespace_equals(mdsc->fsc->mount_options, m->m_fs_name,
364372
fsname_len)) {
365-
pr_warn_client(cl, "fsname %*pE doesn't match mds_namespace %s\n",
366-
(int)fsname_len, (char *)*p,
373+
pr_warn_client(cl, "fsname %s doesn't match mds_namespace %s\n",
374+
m->m_fs_name,
367375
mdsc->fsc->mount_options->mds_namespace);
368376
goto bad;
369377
}
370-
/* skip fsname after validation */
371-
ceph_decode_skip_n(p, end, fsname_len, bad);
378+
} else {
379+
m->m_enabled = false;
380+
m->m_fs_name = kstrdup(CEPH_OLD_FS_NAME, GFP_NOFS);
381+
if (!m->m_fs_name)
382+
goto nomem;
372383
}
373384
/* damaged */
374385
if (mdsmap_ev >= 9) {
@@ -430,6 +441,7 @@ void ceph_mdsmap_destroy(struct ceph_mdsmap *m)
430441
kfree(m->m_info);
431442
}
432443
kfree(m->m_data_pg_pools);
444+
kfree(m->m_fs_name);
433445
kfree(m);
434446
}
435447

fs/ceph/mdsmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct ceph_mdsmap {
4545
bool m_enabled;
4646
bool m_damaged;
4747
int m_num_laggy;
48+
char *m_fs_name;
4849
};
4950

5051
static inline struct ceph_entity_addr *

fs/ceph/super.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,26 @@ struct ceph_mount_options {
104104
struct fscrypt_dummy_policy dummy_enc_policy;
105105
};
106106

107+
#define CEPH_NAMESPACE_WILDCARD "*"
108+
109+
static inline bool ceph_namespace_match(const char *pattern,
110+
const char *target)
111+
{
112+
if (!pattern || !pattern[0] ||
113+
!strcmp(pattern, CEPH_NAMESPACE_WILDCARD))
114+
return true;
115+
116+
return !strcmp(pattern, target);
117+
}
118+
107119
/*
108120
* Check if the mds namespace in ceph_mount_options matches
109121
* the passed in namespace string. First time match (when
110122
* ->mds_namespace is NULL) is treated specially, since
111123
* ->mds_namespace needs to be initialized by the caller.
112124
*/
113-
static inline int namespace_equals(struct ceph_mount_options *fsopt,
114-
const char *namespace, size_t len)
125+
static inline bool namespace_equals(struct ceph_mount_options *fsopt,
126+
const char *namespace, size_t len)
115127
{
116128
return !(fsopt->mds_namespace &&
117129
(strlen(fsopt->mds_namespace) != len ||

include/linux/ceph/ceph_fs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@
3131
#define CEPH_INO_CEPH 2 /* hidden .ceph dir */
3232
#define CEPH_INO_GLOBAL_SNAPREALM 3 /* global dummy snaprealm */
3333

34+
/*
35+
* name for "old" CephFS file systems,
36+
* see ceph.git e2b151d009640114b2565c901d6f41f6cd5ec652
37+
*/
38+
#define CEPH_OLD_FS_NAME "cephfs"
39+
3440
/* arbitrary limit on max # of monitors (cluster of 3 is typical) */
3541
#define CEPH_MAX_MON 31
3642

0 commit comments

Comments
 (0)