aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-07-24 13:22:41 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-07-24 13:22:41 -0700
commitdad0a87d79ff3e7e4ef35ebd588fe4f115329964 (patch)
treeb8f300e11060a7c917865a6ca80b74c12b7cc18b /net
parent981f4a2baaf15a15fd4a22d311f15d066e28833b (diff)
parent5b602344a49e039e792ce5a8923bcc61412ee134 (diff)
Merge tag 'ceph-for-7.2-rc5' of https://github.com/ceph/ceph-client
Pull ceph fixes from Ilya Dryomov: "A bunch of assorted fixes with the majority being hardening against malformed input and invalid data scenarios that don't happen in real deployments but can be utilized to trigger use-after-free and similar issues, some error path leak fixups and two patches from Max to avoid a potential hang in __ceph_get_caps() and unintended nesting of current->journal_info while handling replies from the MDS. All marked for stable" * tag 'ceph-for-7.2-rc5' of https://github.com/ceph/ceph-client: ceph: avoid fs reclaim while using current->journal_info ceph: add owner/capability checks for CEPH_IOC_SET_LAYOUT* ceph: fix hanging __ceph_get_caps() with stale mds_wanted rbd: Reset positive result codes to zero in object map update path libceph: bound pg_{temp,upmap,upmap_items} length to CEPH_PG_MAX_SIZE libceph: refresh auth->authorizer_buf{,_len} after authorizer update ceph: fix refcount leak in ceph_readdir() libceph: guard missing CRUSH type name lookup libceph: remove debugfs files before client teardown libceph: bound get_version reply decode to front len ceph: fix writeback_count leak in write_folio_nounlock() libceph: fix two unsafe bare decodes in decode_lockers() ceph: fix pre-auth out-of-bounds read on snaptrace in ceph_handle_caps() libceph: Reject monmaps advertising zero monitors libceph: reject zero bucket types in crush_decode libceph: Fix multiplication overflow in decode_new_up_state_weight()
Diffstat (limited to 'net')
-rw-r--r--net/ceph/auth_x.c9
-rw-r--r--net/ceph/ceph_common.c4
-rw-r--r--net/ceph/cls_lock_client.c8
-rw-r--r--net/ceph/mon_client.c4
-rw-r--r--net/ceph/osdmap.c16
5 files changed, 30 insertions, 11 deletions
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index 9e64e82d0b63..50a79e8aa656 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -849,9 +849,16 @@ static int ceph_x_update_authorizer(
au = (struct ceph_x_authorizer *)auth->authorizer;
if (au->secret_id < th->secret_id) {
+ int ret;
+
dout("ceph_x_update_authorizer service %u secret %llu < %llu\n",
au->service, au->secret_id, th->secret_id);
- return ceph_x_build_authorizer(ac, th, au);
+ ret = ceph_x_build_authorizer(ac, th, au);
+ if (ret)
+ return ret;
+
+ auth->authorizer_buf = au->buf->vec.iov_base;
+ auth->authorizer_buf_len = au->buf->vec.iov_len;
}
return 0;
}
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 952121849180..a797c7360e3c 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -762,13 +762,13 @@ void ceph_destroy_client(struct ceph_client *client)
atomic_set(&client->msgr.stopping, 1);
+ ceph_debugfs_client_cleanup(client);
+
/* unmount */
ceph_osdc_stop(&client->osdc);
ceph_monc_stop(&client->monc);
ceph_messenger_fini(&client->msgr);
- ceph_debugfs_client_cleanup(client);
-
ceph_destroy_options(client->options);
kfree(client);
diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c
index c6956f1df333..377336982f7d 100644
--- a/net/ceph/cls_lock_client.c
+++ b/net/ceph/cls_lock_client.c
@@ -299,7 +299,7 @@ static int decode_lockers(void **p, void *end, u8 *type, char **tag,
if (ret)
return ret;
- *num_lockers = ceph_decode_32(p);
+ ceph_decode_32_safe(p, end, *num_lockers, err_inval);
*lockers = kzalloc_objs(**lockers, *num_lockers, GFP_NOIO);
if (!*lockers)
return -ENOMEM;
@@ -310,7 +310,8 @@ static int decode_lockers(void **p, void *end, u8 *type, char **tag,
goto err_free_lockers;
}
- *type = ceph_decode_8(p);
+ ret = -EINVAL;
+ ceph_decode_8_safe(p, end, *type, err_free_lockers);
s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
if (IS_ERR(s)) {
ret = PTR_ERR(s);
@@ -320,6 +321,9 @@ static int decode_lockers(void **p, void *end, u8 *type, char **tag,
*tag = s;
return 0;
+err_inval:
+ return -EINVAL;
+
err_free_lockers:
ceph_free_lockers(*lockers, *num_lockers);
return ret;
diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
index d2cdc8ee3155..c56457378d00 100644
--- a/net/ceph/mon_client.c
+++ b/net/ceph/mon_client.c
@@ -114,7 +114,7 @@ static struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
dout("%s fsid %pU epoch %u num_mon %u\n", __func__, &fsid, epoch,
num_mon);
- if (num_mon > CEPH_MAX_MON)
+ if (num_mon == 0 || num_mon > CEPH_MAX_MON)
goto e_inval;
monmap = kmalloc_flex(*monmap, mon_inst, num_mon, GFP_NOIO);
@@ -821,7 +821,7 @@ static void handle_get_version_reply(struct ceph_mon_client *monc,
struct ceph_mon_generic_request *req;
u64 tid = le64_to_cpu(msg->hdr.tid);
void *p = msg->front.iov_base;
- void *end = p + msg->front_alloc_len;
+ void *const end = p + msg->front.iov_len;
u64 handle;
dout("%s msg %p tid %llu\n", __func__, msg, tid);
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index 8b5b0587a0cf..a4b0dd8672ec 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -518,6 +518,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
ceph_decode_need(p, end, 4*sizeof(u32), bad);
b->id = ceph_decode_32(p);
b->type = ceph_decode_16(p);
+ if (b->type == 0)
+ goto bad;
b->alg = ceph_decode_8(p);
if (b->alg != alg) {
b->alg = 0;
@@ -1436,7 +1438,7 @@ static struct ceph_pg_mapping *__decode_pg_temp(void **p, void *end,
ceph_decode_32_safe(p, end, len, e_inval);
if (len == 0 && incremental)
return NULL; /* new_pg_temp: [] to remove */
- if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / sizeof(u32))
+ if (len > CEPH_PG_MAX_SIZE)
return ERR_PTR(-EINVAL);
ceph_decode_need(p, end, len * sizeof(u32), e_inval);
@@ -1617,7 +1619,7 @@ static struct ceph_pg_mapping *__decode_pg_upmap_items(void **p, void *end,
u32 len, i;
ceph_decode_32_safe(p, end, len, e_inval);
- if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
+ if (len > CEPH_PG_MAX_SIZE)
return ERR_PTR(-EINVAL);
ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);
@@ -1842,6 +1844,8 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
void *new_up_client;
void *new_state;
void *new_weight_end;
+ const u32 new_state_item_size =
+ sizeof(u32) + (struct_v >= 5 ? sizeof(u32) : sizeof(u8));
u32 len;
int ret;
int i;
@@ -1862,7 +1866,8 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
new_state = *p;
ceph_decode_32_safe(p, end, len, e_inval);
- len *= sizeof(u32) + (struct_v >= 5 ? sizeof(u32) : sizeof(u8));
+ if (check_mul_overflow(len, new_state_item_size, &len))
+ goto e_inval;
ceph_decode_need(p, end, len, e_inval);
*p += len;
@@ -3055,8 +3060,11 @@ static int get_immediate_parent(struct crush_map *c, int id,
if (b->items[j] != id)
continue;
- *parent_type_id = b->type;
type_cn = lookup_crush_name(&c->type_names, b->type);
+ if (WARN_ON_ONCE(!type_cn))
+ continue;
+
+ *parent_type_id = b->type;
parent_loc->cl_type_name = type_cn->cn_name;
parent_loc->cl_name = cn->cn_name;
return b->id;