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 ]
Unified · Split
| @@ -5671,7 +5671,7 @@ static int ceph_mds_auth_match(struct ceph_mds_client *mdsc, · 5670 unmodified lines | ||
| 5671 | 5671 | u32 caller_uid = from_kuid(&init_user_ns, cred->fsuid); |
| 5672 | 5672 | u32 caller_gid = from_kgid(&init_user_ns, cred->fsgid); |
| 5673 | 5673 | 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; | |
| 5675 | 5675 | const char *spath = mdsc->fsc->mount_options->server_path; |
| 5676 | 5676 | bool gid_matched = false; |
| 5677 | 5677 | u32 gid, tlen, len; |
| @@ -5679,7 +5679,8 @@ static int ceph_mds_auth_match(struct ceph_mds_client *mdsc, · 1 unmodified line | ||
| 5679 | 5679 | |
| 5680 | 5680 | doutc(cl, "fsname check fs_name=%s match.fs_name=%s\n", |
| 5681 | 5681 | 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)) { | |
| 5683 | 5684 | /* fsname mismatch, try next one */ |
| 5684 | 5685 | return 0; |
| 5685 | 5686 | } |
| @@ -353,22 +353,33 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p, · 352 unmodified lines | ||
| 353 | 353 | __decode_and_drop_type(p, end, u8, bad_ext); |
| 354 | 354 | } |
| 355 | 355 | if (mdsmap_ev >= 8) { |
| 356 | − u32 fsname_len; | |
| 356 | + size_t fsname_len; | |
| 357 | + | |
| 357 | 358 | /* enabled */ |
| 358 | 359 | ceph_decode_8_safe(p, end, m->m_enabled, bad_ext); |
| 360 | + | |
| 359 | 361 | /* 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 | + } | |
| 361 | 369 | |
| 362 | 370 | /* 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, | |
| 364 | 372 | 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, | |
| 367 | 375 | mdsc->fsc->mount_options->mds_namespace); |
| 368 | 376 | goto bad; |
| 369 | 377 | } |
| 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; | |
| 372 | 383 | } |
| 373 | 384 | /* damaged */ |
| 374 | 385 | if (mdsmap_ev >= 9) { |
| @@ -430,6 +441,7 @@ void ceph_mdsmap_destroy(struct ceph_mdsmap *m) · 55 unmodified lines | ||
| 430 | 441 | kfree(m->m_info); |
| 431 | 442 | } |
| 432 | 443 | kfree(m->m_data_pg_pools); |
| 444 | + kfree(m->m_fs_name); | |
| 433 | 445 | kfree(m); |
| 434 | 446 | } |
| 435 | 447 | |
| @@ -45,6 +45,7 @@ struct ceph_mdsmap { · 44 unmodified lines | ||
| 45 | 45 | bool m_enabled; |
| 46 | 46 | bool m_damaged; |
| 47 | 47 | int m_num_laggy; |
| 48 | + char *m_fs_name; | |
| 48 | 49 | }; |
| 49 | 50 | |
| 50 | 51 | static inline struct ceph_entity_addr * |
| @@ -104,14 +104,26 @@ struct ceph_mount_options { · 103 unmodified lines | ||
| 104 | 104 | struct fscrypt_dummy_policy dummy_enc_policy; |
| 105 | 105 | }; |
| 106 | 106 | |
| 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 | + | |
| 107 | 119 | /* |
| 108 | 120 | * Check if the mds namespace in ceph_mount_options matches |
| 109 | 121 | * the passed in namespace string. First time match (when |
| 110 | 122 | * ->mds_namespace is NULL) is treated specially, since |
| 111 | 123 | * ->mds_namespace needs to be initialized by the caller. |
| 112 | 124 | */ |
| 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) | |
| 115 | 127 | { |
| 116 | 128 | return !(fsopt->mds_namespace && |
| 117 | 129 | (strlen(fsopt->mds_namespace) != len || |
| @@ -31,6 +31,12 @@ · 30 unmodified lines | ||
| 31 | 31 | #define CEPH_INO_CEPH 2 /* hidden .ceph dir */ |
| 32 | 32 | #define CEPH_INO_GLOBAL_SNAPREALM 3 /* global dummy snaprealm */ |
| 33 | 33 | |
| 34 | +/* | |
| 35 | + * name for "old" CephFS file systems, | |
| 36 | + * see ceph.git e2b151d009640114b2565c901d6f41f6cd5ec652 | |
| 37 | + */ | |
| 38 | +#define CEPH_OLD_FS_NAME "cephfs" | |
| 39 | + | |
| 34 | 40 | /* arbitrary limit on max # of monitors (cluster of 3 is typical) */ |
| 35 | 41 | #define CEPH_MAX_MON 31 |
| 36 | 42 | |