Commit 240b8d82 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 23b0d2f7 7987cce3
Loading
Loading
Loading
Loading
+21 −12
Original line number Diff line number Diff line
@@ -3495,11 +3495,29 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req)
	rbd_assert(!need_exclusive_lock(img_req) ||
		   __rbd_is_lock_owner(rbd_dev));

	if (test_bit(IMG_REQ_CHILD, &img_req->flags)) {
		rbd_assert(!rbd_img_is_write(img_req));
	} else {
		struct request *rq = blk_mq_rq_from_pdu(img_req);
		u64 off = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
		u64 len = blk_rq_bytes(rq);
		u64 mapping_size;

		down_read(&rbd_dev->header_rwsem);
		mapping_size = rbd_dev->mapping.size;
		if (rbd_img_is_write(img_req)) {
			rbd_assert(!img_req->snapc);
		down_read(&rbd_dev->header_rwsem);
		img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
			img_req->snapc =
			    ceph_get_snap_context(rbd_dev->header.snapc);
		}
		up_read(&rbd_dev->header_rwsem);

		if (unlikely(off + len > mapping_size)) {
			rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)",
				 off, len, mapping_size);
			img_req->pending.result = -EIO;
			return;
		}
	}

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

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

	down_read(&rbd_dev->header_rwsem);
	mapping_size = rbd_dev->mapping.size;
	rbd_img_capture_header(img_request);
	up_read(&rbd_dev->header_rwsem);

	if (offset + length > mapping_size) {
		rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)", offset,
			 length, mapping_size);
		result = -EIO;
		goto err_img_request;
	}

	dout("%s rbd_dev %p img_req %p %s %llu~%llu\n", __func__, rbd_dev,
	     img_request, obj_op_name(op_type), offset, length);

+5 −4
Original line number Diff line number Diff line
@@ -166,12 +166,13 @@ static struct inode *parse_longname(const struct inode *parent,
	struct ceph_vino vino = { .snap = CEPH_NOSNAP };
	char *name_end, *inode_number;
	int ret = -EIO;
	/* NUL-terminate */
	char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL);
	/* Snapshot name must start with an underscore */
	if (*name_len <= 0 || name[0] != '_')
		return ERR_PTR(-EIO);
	/* Skip initial '_' and NUL-terminate */
	char *str __free(kfree) = kmemdup_nul(name + 1, *name_len - 1, GFP_KERNEL);
	if (!str)
		return ERR_PTR(-ENOMEM);
	/* Skip initial '_' */
	str++;
	name_end = strrchr(str, '_');
	if (!name_end) {
		doutc(cl, "failed to parse long snapshot name: %s\n", str);
+3 −2
Original line number Diff line number Diff line
@@ -5671,7 +5671,7 @@ static int ceph_mds_auth_match(struct ceph_mds_client *mdsc,
	u32 caller_uid = from_kuid(&init_user_ns, cred->fsuid);
	u32 caller_gid = from_kgid(&init_user_ns, cred->fsgid);
	struct ceph_client *cl = mdsc->fsc->client;
	const char *fs_name = mdsc->fsc->mount_options->mds_namespace;
	const char *fs_name = mdsc->mdsmap->m_fs_name;
	const char *spath = mdsc->fsc->mount_options->server_path;
	bool gid_matched = false;
	u32 gid, tlen, len;
@@ -5679,7 +5679,8 @@ static int ceph_mds_auth_match(struct ceph_mds_client *mdsc,

	doutc(cl, "fsname check fs_name=%s  match.fs_name=%s\n",
	      fs_name, auth->match.fs_name ? auth->match.fs_name : "");
	if (auth->match.fs_name && strcmp(auth->match.fs_name, fs_name)) {

	if (!ceph_namespace_match(auth->match.fs_name, fs_name)) {
		/* fsname mismatch, try next one */
		return 0;
	}
+19 −7
Original line number Diff line number Diff line
@@ -353,22 +353,33 @@ struct ceph_mdsmap *ceph_mdsmap_decode(struct ceph_mds_client *mdsc, void **p,
		__decode_and_drop_type(p, end, u8, bad_ext);
	}
	if (mdsmap_ev >= 8) {
		u32 fsname_len;
		size_t fsname_len;

		/* enabled */
		ceph_decode_8_safe(p, end, m->m_enabled, bad_ext);

		/* fs_name */
		ceph_decode_32_safe(p, end, fsname_len, bad_ext);
		m->m_fs_name = ceph_extract_encoded_string(p, end,
							   &fsname_len,
							   GFP_NOFS);
		if (IS_ERR(m->m_fs_name)) {
			m->m_fs_name = NULL;
			goto nomem;
		}

		/* validate fsname against mds_namespace */
		if (!namespace_equals(mdsc->fsc->mount_options, *p,
		if (!namespace_equals(mdsc->fsc->mount_options, m->m_fs_name,
				      fsname_len)) {
			pr_warn_client(cl, "fsname %*pE doesn't match mds_namespace %s\n",
				       (int)fsname_len, (char *)*p,
			pr_warn_client(cl, "fsname %s doesn't match mds_namespace %s\n",
				       m->m_fs_name,
				       mdsc->fsc->mount_options->mds_namespace);
			goto bad;
		}
		/* skip fsname after validation */
		ceph_decode_skip_n(p, end, fsname_len, bad);
	} else {
		m->m_enabled = false;
		m->m_fs_name = kstrdup(CEPH_OLD_FS_NAME, GFP_NOFS);
		if (!m->m_fs_name)
			goto nomem;
	}
	/* damaged */
	if (mdsmap_ev >= 9) {
@@ -430,6 +441,7 @@ void ceph_mdsmap_destroy(struct ceph_mdsmap *m)
		kfree(m->m_info);
	}
	kfree(m->m_data_pg_pools);
	kfree(m->m_fs_name);
	kfree(m);
}

+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct ceph_mdsmap {
	bool m_enabled;
	bool m_damaged;
	int m_num_laggy;
	char *m_fs_name;
};

static inline struct ceph_entity_addr *
Loading