Re: [Security][Ceph] OSDMap new_state decode overflow causes out-of-bounds read in kernel client
Ilya Dryomov <[email protected]> Sat, 25 Jul 2026 11:27:52 +0200
| Newsgroups | org.kernel.vger.ceph-devel |
|---|---|
| Message-ID | <CAOi1vP-180-2L6LxR7X3s=MJJ+rBRZCi0ZjFqg9OS8t=wbK0RA@mail.gmail.com> |
On Sat, Jul 25, 2026 at 11:19=E2=80=AFAM Baul Lee <[email protected]> wrote= : > > [PATCH] libceph: fix out-of-bounds read in decode_new_up_state_weight() > > decode_new_up_state_weight() parses the new_up_client, new_state and > new_weight arrays of an incremental OSDMap received from the monitor. > > The new_weight loop validates every entry with ceph_decode_need() > before consuming the 2 * sizeof(u32) it reads. The new_state loop does > not: it relies solely on the earlier > > ceph_decode_32_safe(p, end, len, e_inval); > len *=3D sizeof(u32) + (struct_v >=3D 5 ? sizeof(u32) : sizeof(u8)); > ceph_decode_need(p, end, len, e_inval); > > pre-check. That product is computed in 32-bit arithmetic, so a large > entry count overflows u32 and wraps to a small value; ceph_decode_need() > then succeeds for the truncated size while the loop still iterates the > full, attacker-controlled count, decoding an osd id (u32) plus an > xorstate (u32 or u8) per entry past the end of the map buffer. > > A malicious or compromised monitor can thus make a client read out of > bounds while applying an incremental OSDMap. > > Validate each new_state entry against the buffer end before decoding it, > mirroring the existing new_weight loop. > > Fixes: 930c53286977 ("libceph: apply new_state before new_up_client on in= crementals") > Reported-by: Federico Kirschbaum <[email protected]> > Reported-by: Baul Lee <[email protected]> > --- > net/ceph/osdmap.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c > index 8b5b0587a0cf..f09a1c99690e 100644 > --- a/net/ceph/osdmap.c > +++ b/net/ceph/osdmap.c > @@ -1902,6 +1902,9 @@ static int decode_new_up_state_weight(void **p, voi= d *end, u8 struct_v, > s32 osd; > u32 xorstate; > > + ceph_decode_need(p, end, sizeof(u32) + > + (struct_v >=3D 5 ? sizeof(u32) : sizeof(u8)), > + e_inval); > osd =3D ceph_decode_32(p); > if (osd >=3D map->max_osd) > goto e_inval; > -- Hi Federico, Baul, I believe this is already fixed by a patch that prevents the "first-pass truncation" (as it's referred to in the previous messages) from happening in the first place: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?= id=3D98917a499ec7064c14fc56d180a4fd636fc2784c Thanks, Ilya