Skip to content

Commit 240b8d8

Browse files
committed
Merge tag 'ceph-for-6.19-rc9' of https://github.com/ceph/ceph-client
Pull ceph fixes from Ilya Dryomov: "One RBD and two CephFS fixes which address potential oopses. The RBD thing is more of a rare edge case that pops up in our CI, while the two CephFS scenarios are regressions that were reported by users and can be triggered trivially in normal operation. All marked for stable" * tag 'ceph-for-6.19-rc9' of https://github.com/ceph/ceph-client: ceph: fix NULL pointer dereference in ceph_mds_auth_match() ceph: fix oops due to invalid pointer for kfree() in parse_longname() rbd: check for EOD after exclusive lock is ensured to be held
2 parents 23b0d2f + 7987cce commit 240b8d8

7 files changed

Lines changed: 69 additions & 27 deletions

File tree

drivers/block/rbd.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3495,11 +3495,29 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req)
34953495
rbd_assert(!need_exclusive_lock(img_req) ||
34963496
__rbd_is_lock_owner(rbd_dev));
34973497

3498-
if (rbd_img_is_write(img_req)) {
3499-
rbd_assert(!img_req->snapc);
3498+
if (test_bit(IMG_REQ_CHILD, &img_req->flags)) {
3499+
rbd_assert(!rbd_img_is_write(img_req));
3500+
} else {
3501+
struct request *rq = blk_mq_rq_from_pdu(img_req);
3502+
u64 off = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
3503+
u64 len = blk_rq_bytes(rq);
3504+
u64 mapping_size;
3505+
35003506
down_read(&rbd_dev->header_rwsem);
3501-
img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
3507+
mapping_size = rbd_dev->mapping.size;
3508+
if (rbd_img_is_write(img_req)) {
3509+
rbd_assert(!img_req->snapc);
3510+
img_req->snapc =
3511+
ceph_get_snap_context(rbd_dev->header.snapc);
3512+
}
35023513
up_read(&rbd_dev->header_rwsem);
3514+
3515+
if (unlikely(off + len > mapping_size)) {
3516+
rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)",
3517+
off, len, mapping_size);
3518+
img_req->pending.result = -EIO;
3519+
return;
3520+
}
35033521
}
35043522

35053523
for_each_obj_request(img_req, obj_req) {
@@ -4725,7 +4743,6 @@ static void rbd_queue_workfn(struct work_struct *work)
47254743
struct request *rq = blk_mq_rq_from_pdu(img_request);
47264744
u64 offset = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
47274745
u64 length = blk_rq_bytes(rq);
4728-
u64 mapping_size;
47294746
int result;
47304747

47314748
/* Ignore/skip any zero-length requests */
@@ -4738,17 +4755,9 @@ static void rbd_queue_workfn(struct work_struct *work)
47384755
blk_mq_start_request(rq);
47394756

47404757
down_read(&rbd_dev->header_rwsem);
4741-
mapping_size = rbd_dev->mapping.size;
47424758
rbd_img_capture_header(img_request);
47434759
up_read(&rbd_dev->header_rwsem);
47444760

4745-
if (offset + length > mapping_size) {
4746-
rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)", offset,
4747-
length, mapping_size);
4748-
result = -EIO;
4749-
goto err_img_request;
4750-
}
4751-
47524761
dout("%s rbd_dev %p img_req %p %s %llu~%llu\n", __func__, rbd_dev,
47534762
img_request, obj_op_name(op_type), offset, length);
47544763

fs/ceph/crypto.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,13 @@ static struct inode *parse_longname(const struct inode *parent,
166166
struct ceph_vino vino = { .snap = CEPH_NOSNAP };
167167
char *name_end, *inode_number;
168168
int ret = -EIO;
169-
/* NUL-terminate */
170-
char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL);
169+
/* Snapshot name must start with an underscore */
170+
if (*name_len <= 0 || name[0] != '_')
171+
return ERR_PTR(-EIO);
172+
/* Skip initial '_' and NUL-terminate */
173+
char *str __free(kfree) = kmemdup_nul(name + 1, *name_len - 1, GFP_KERNEL);
171174
if (!str)
172175
return ERR_PTR(-ENOMEM);
173-
/* Skip initial '_' */
174-
str++;
175176
name_end = strrchr(str, '_');
176177
if (!name_end) {
177178
doutc(cl, "failed to parse long snapshot name: %s\n", str);

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)