All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] libceph: Fix multiplication overflow in __decode_pg_upmap_items()
       [not found] ` <20260513081425.1477060-1-raphael.zimmer@tu-ilmenau.de>
@ 2026-05-13 16:40   ` Viacheslav Dubeyko
  2026-05-13 17:18     ` Viacheslav Dubeyko
  0 siblings, 1 reply; 5+ messages in thread
From: Viacheslav Dubeyko @ 2026-05-13 16:40 UTC (permalink / raw)
  To: Raphael Zimmer, Ilya Dryomov, Alex Markuze; +Cc: security, ceph-devel

cc: ceph-devel@vger.kernel.org

On Wed, 2026-05-13 at 10:14 +0200, Raphael Zimmer wrote:
> A message of type CEPH_MSG_OSD_MAP holds an OSD map, which typically
> contains a pg_upmap part at its end. When decoding this part in
> __decode_pg_upmap_items(), a len value is decoded from the message to
> determine the number of items and the size of the allocation needed
> for
> them. If the len value is greater than or equal to 2^31, an overflow
> occurs in the multiplication that is performed to determine the
> needed
> size of the incoming buffer to decode, as well as for the length of
> the
> allocation for the ceph_pg_mapping struct. Subsequently, this results
> in
> out-of-bounds writes (and reads) when decoding the incoming message
> fields into the ceph_pg_mapping struct.
> 
> This patch fixes the issue by adding a UL suffix to the literal in
> the
> multiplication to perform it as an unsigned long multiplication.
> 
> Signed-off-by: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
> ---
>  net/ceph/osdmap.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
> index 8b5b0587a0cf..42b7b5300901 100644
> --- a/net/ceph/osdmap.c
> +++ b/net/ceph/osdmap.c
> @@ -1620,8 +1620,8 @@ static struct ceph_pg_mapping
> *__decode_pg_upmap_items(void **p, void *end,
>  	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 *
> sizeof(u32)))
>  		return ERR_PTR(-EINVAL);
>  
> -	ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);
> -	pg = alloc_pg_mapping(2 * len * sizeof(u32));
> +	ceph_decode_need(p, end, 2UL * len * sizeof(u32), e_inval);
> +	pg = alloc_pg_mapping(2UL * len * sizeof(u32));
>  	if (!pg)
>  		return ERR_PTR(-ENOMEM);
>  

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [bug report] libceph: Multiplication overflow that leads to out-of-bounds writes in __decode_pg_upmap_items()
       [not found] <8edcef9c-0b7c-46dc-8094-dc55b62567d3@tu-ilmenau.de>
       [not found] ` <20260513081425.1477060-1-raphael.zimmer@tu-ilmenau.de>
@ 2026-05-13 16:40 ` Viacheslav Dubeyko
  1 sibling, 0 replies; 5+ messages in thread
From: Viacheslav Dubeyko @ 2026-05-13 16:40 UTC (permalink / raw)
  To: Raphael Zimmer, Ilya Dryomov, Alex Markuze
  Cc: security@kernel.org, ceph-devel

cc: ceph-devel@vger.kernel.org

On Wed, 2026-05-13 at 10:13 +0200, Raphael Zimmer wrote:
> Hi,
> I encountered a bug in the libceph module, specifically in the
> function
> __decode_pg_upmap_items() in net/ceph/osdmap.c. It can be triggered
> by a
> message of type CEPH_MSG_OSD_MAP arriving on an open connection to a
> Ceph monitor or OSD.
> 
> A message of type CEPH_MSG_OSD_MAP holds an OSD map, which typically
> contains a pg_upmap part at its end. When decoding this part,
> __decode_pg_upmap_items() is called. In this function, a len value is
> decoded from the message. It is used to determine the number of items
> and the size of the allocation needed for them. If the len value is
> greater than or equal to 2^31, an overflow occurs in the
> multiplication
> that is performed to determine the needed size of the incoming buffer
> to
> decode, as well as for the length of the allocation for the
> ceph_pg_mapping struct. The performed multiplication is "2 * len *
> sizeof(u32)" where len is of type u32. Subsequently, the len
> parameter
> is used as the upper bound of a loop that decodes the incoming
> message
> fields into the ceph_pg_mapping struct. This results in out-of-bounds
> memory accesses in case of a previous overflow. The len field can be
> set
> arbitrarily by a (maliciously acting) Ceph monitor or OSD and allows
> writing data received over the network beyond the end of the
> allocated
> buffer. Furthermore, I observed that it can ultimately result in a
> kernel panic because of general protection faults when attempting to
> access the memory.
> 
> The issues can be reproduced on the recent stable release 7.0.6 when
> injecting a specifically crafted message into an open Ceph
> connection.
> However, 32-bit systems are probably not affected, as the previous
> check
> for:
> if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
> 		return ERR_PTR(-EINVAL);
> would not allow a value this large for len on these systems.
> 
> The bug can be fixed by explicitly performing the multiplication in
> 64
> bit on 64-bit systems by switching to "2UL * len * sizeof(u32)" or
> changing the evaluation order of the multiplication. This would
> suffice
> as the mentioned check catches such values already beforehand on 32-
> bit
> systems, so that an additional check is not necessary. However, I
> would
> also be open to adding an additional check instead if it seems more
> appropriate.
> 
> I will send the proposed fix in reply to this email.
> 
> 
> Best regards,
> Raphael

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH] libceph: Fix multiplication overflow in __decode_pg_upmap_items()
  2026-05-13 16:40   ` [PATCH] libceph: Fix multiplication overflow in __decode_pg_upmap_items() Viacheslav Dubeyko
@ 2026-05-13 17:18     ` Viacheslav Dubeyko
  2026-05-15  7:41       ` Raphael Zimmer
  0 siblings, 1 reply; 5+ messages in thread
From: Viacheslav Dubeyko @ 2026-05-13 17:18 UTC (permalink / raw)
  To: raphael.zimmer@tu-ilmenau.de, idryomov@gmail.com,
	slava@dubeyko.com, Alex Markuze
  Cc: security@kernel.org, ceph-devel@vger.kernel.org

On Wed, 2026-05-13 at 09:40 -0700, Viacheslav Dubeyko wrote:
> cc: ceph-devel@vger.kernel.org
> 
> On Wed, 2026-05-13 at 10:14 +0200, Raphael Zimmer wrote:
> > A message of type CEPH_MSG_OSD_MAP holds an OSD map, which typically
> > contains a pg_upmap part at its end. When decoding this part in
> > __decode_pg_upmap_items(), a len value is decoded from the message to
> > determine the number of items and the size of the allocation needed
> > for
> > them. If the len value is greater than or equal to 2^31, an overflow
> > occurs in the multiplication that is performed to determine the
> > needed
> > size of the incoming buffer to decode, as well as for the length of
> > the
> > allocation for the ceph_pg_mapping struct. Subsequently, this results
> > in
> > out-of-bounds writes (and reads) when decoding the incoming message
> > fields into the ceph_pg_mapping struct.
> > 
> > This patch fixes the issue by adding a UL suffix to the literal in
> > the
> > multiplication to perform it as an unsigned long multiplication.
> > 
> > Signed-off-by: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
> > ---
> >  net/ceph/osdmap.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
> > index 8b5b0587a0cf..42b7b5300901 100644
> > --- a/net/ceph/osdmap.c
> > +++ b/net/ceph/osdmap.c
> > @@ -1620,8 +1620,8 @@ static struct ceph_pg_mapping
> > *__decode_pg_upmap_items(void **p, void *end,
> >  	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 *
> > sizeof(u32)))
> >  		return ERR_PTR(-EINVAL);
> >  
> > -	ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);

We use the pattern 2 * sizeof(u32) three times in the function. I can suggest to
introduce a local variable that will keep this value.

> > -	pg = alloc_pg_mapping(2 * len * sizeof(u32));

I think it doesn't make sense to execute the same calculation two times. Of
course, compiler can do some optimizations. But I suggest to introduce a local
variable that will contain the final calculation of 2UL * len * sizeof(u32) and
it will be used in both cases.

> > +	ceph_decode_need(p, end, 2UL * len * sizeof(u32), e_inval);
> > +	pg = alloc_pg_mapping(2UL * len * sizeof(u32));
> >  	if (!pg)
> >  		return ERR_PTR(-ENOMEM);
> >  

By the way, this check:

	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
		return ERR_PTR(-EINVAL);

will work  a wrong way for the case of if the len value is greater than or equal
to 2^31.

Thanks,
Slava.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] libceph: Fix multiplication overflow in __decode_pg_upmap_items()
  2026-05-13 17:18     ` Viacheslav Dubeyko
@ 2026-05-15  7:41       ` Raphael Zimmer
  2026-05-15 18:40         ` Viacheslav Dubeyko
  0 siblings, 1 reply; 5+ messages in thread
From: Raphael Zimmer @ 2026-05-15  7:41 UTC (permalink / raw)
  To: Viacheslav Dubeyko, idryomov@gmail.com, slava@dubeyko.com,
	Alex Markuze
  Cc: security@kernel.org, ceph-devel@vger.kernel.org

On 13.05.26 7:18 PM, Viacheslav Dubeyko wrote:
> On Wed, 2026-05-13 at 09:40 -0700, Viacheslav Dubeyko wrote:
>> cc: ceph-devel@vger.kernel.org
>>
>> On Wed, 2026-05-13 at 10:14 +0200, Raphael Zimmer wrote:
>>> A message of type CEPH_MSG_OSD_MAP holds an OSD map, which typically
>>> contains a pg_upmap part at its end. When decoding this part in
>>> __decode_pg_upmap_items(), a len value is decoded from the message to
>>> determine the number of items and the size of the allocation needed
>>> for
>>> them. If the len value is greater than or equal to 2^31, an overflow
>>> occurs in the multiplication that is performed to determine the
>>> needed
>>> size of the incoming buffer to decode, as well as for the length of
>>> the
>>> allocation for the ceph_pg_mapping struct. Subsequently, this results
>>> in
>>> out-of-bounds writes (and reads) when decoding the incoming message
>>> fields into the ceph_pg_mapping struct.
>>>
>>> This patch fixes the issue by adding a UL suffix to the literal in
>>> the
>>> multiplication to perform it as an unsigned long multiplication.
>>>
>>> Signed-off-by: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
>>> ---
>>>  net/ceph/osdmap.c | 4 ++--
>>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
>>> index 8b5b0587a0cf..42b7b5300901 100644
>>> --- a/net/ceph/osdmap.c
>>> +++ b/net/ceph/osdmap.c
>>> @@ -1620,8 +1620,8 @@ static struct ceph_pg_mapping
>>> *__decode_pg_upmap_items(void **p, void *end,
>>>  	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 *
>>> sizeof(u32)))
>>>  		return ERR_PTR(-EINVAL);
>>>  
>>> -	ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);
> 
> We use the pattern 2 * sizeof(u32) three times in the function. I can suggest to
> introduce a local variable that will keep this value.
> 
>>> -	pg = alloc_pg_mapping(2 * len * sizeof(u32));
> 
> I think it doesn't make sense to execute the same calculation two times. Of
> course, compiler can do some optimizations. But I suggest to introduce a local
> variable that will contain the final calculation of 2UL * len * sizeof(u32) and
> it will be used in both cases.
> 

Hi Slava,
I will rework this.

>>> +	ceph_decode_need(p, end, 2UL * len * sizeof(u32), e_inval);
>>> +	pg = alloc_pg_mapping(2UL * len * sizeof(u32));
>>>  	if (!pg)
>>>  		return ERR_PTR(-ENOMEM);
>>>  
> 
> By the way, this check:
> 
> 	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
> 		return ERR_PTR(-EINVAL);
> 
> will work  a wrong way for the case of if the len value is greater than or equal
> to 2^31.
> 

What do you mean by "will work a wrong way"? I don't see any issue with
it or different behavior in case of len >= 2^31.

Best regards,
Raphael

> Thanks,
> Slava.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH] libceph: Fix multiplication overflow in __decode_pg_upmap_items()
  2026-05-15  7:41       ` Raphael Zimmer
@ 2026-05-15 18:40         ` Viacheslav Dubeyko
  0 siblings, 0 replies; 5+ messages in thread
From: Viacheslav Dubeyko @ 2026-05-15 18:40 UTC (permalink / raw)
  To: raphael.zimmer@tu-ilmenau.de, idryomov@gmail.com,
	slava@dubeyko.com, Alex Markuze
  Cc: security@kernel.org, ceph-devel@vger.kernel.org

On Fri, 2026-05-15 at 09:41 +0200, Raphael Zimmer wrote:
> On 13.05.26 7:18 PM, Viacheslav Dubeyko wrote:
> > On Wed, 2026-05-13 at 09:40 -0700, Viacheslav Dubeyko wrote:
> > > cc: ceph-devel@vger.kernel.org
> > > 
> > > On Wed, 2026-05-13 at 10:14 +0200, Raphael Zimmer wrote:
> > > > A message of type CEPH_MSG_OSD_MAP holds an OSD map, which typically
> > > > contains a pg_upmap part at its end. When decoding this part in
> > > > __decode_pg_upmap_items(), a len value is decoded from the message to
> > > > determine the number of items and the size of the allocation needed
> > > > for
> > > > them. If the len value is greater than or equal to 2^31, an overflow
> > > > occurs in the multiplication that is performed to determine the
> > > > needed
> > > > size of the incoming buffer to decode, as well as for the length of
> > > > the
> > > > allocation for the ceph_pg_mapping struct. Subsequently, this results
> > > > in
> > > > out-of-bounds writes (and reads) when decoding the incoming message
> > > > fields into the ceph_pg_mapping struct.
> > > > 
> > > > This patch fixes the issue by adding a UL suffix to the literal in
> > > > the
> > > > multiplication to perform it as an unsigned long multiplication.
> > > > 
> > > > Signed-off-by: Raphael Zimmer <raphael.zimmer@tu-ilmenau.de>
> > > > ---
> > > >  net/ceph/osdmap.c | 4 ++--
> > > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
> > > > index 8b5b0587a0cf..42b7b5300901 100644
> > > > --- a/net/ceph/osdmap.c
> > > > +++ b/net/ceph/osdmap.c
> > > > @@ -1620,8 +1620,8 @@ static struct ceph_pg_mapping
> > > > *__decode_pg_upmap_items(void **p, void *end,
> > > >  	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 *
> > > > sizeof(u32)))
> > > >  		return ERR_PTR(-EINVAL);
> > > >  
> > > > -	ceph_decode_need(p, end, 2 * len * sizeof(u32), e_inval);
> > 
> > We use the pattern 2 * sizeof(u32) three times in the function. I can suggest to
> > introduce a local variable that will keep this value.
> > 
> > > > -	pg = alloc_pg_mapping(2 * len * sizeof(u32));
> > 
> > I think it doesn't make sense to execute the same calculation two times. Of
> > course, compiler can do some optimizations. But I suggest to introduce a local
> > variable that will contain the final calculation of 2UL * len * sizeof(u32) and
> > it will be used in both cases.
> > 
> 
> Hi Slava,
> I will rework this.
> 
> > > > +	ceph_decode_need(p, end, 2UL * len * sizeof(u32), e_inval);
> > > > +	pg = alloc_pg_mapping(2UL * len * sizeof(u32));
> > > >  	if (!pg)
> > > >  		return ERR_PTR(-ENOMEM);
> > > >  
> > 
> > By the way, this check:
> > 
> > 	if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))
> > 		return ERR_PTR(-EINVAL);
> > 
> > will work  a wrong way for the case of if the len value is greater than or equal
> > to 2^31.
> > 
> 
> What do you mean by "will work a wrong way"? I don't see any issue with
> it or different behavior in case of len >= 2^31.
> 
> 

I think the main confusing point was this phrase from the commit message "If the
len value is greater than or equal to 2^31". But, as far as I can see, we have
declaration [1]:

u32 len, i;

Then, how the len can have value "greater than 2^31"? :) I assume that you mean
the calculation of 2 * len * sizeof(u32) can be greater than 2^31.

But, maybe, we need to have this declaration instead:

size_t len, i;

In such case, we don't need in the case (size_t)len here:

if ((size_t)len > (SIZE_MAX - sizeof(*pg)) / (2 * sizeof(u32)))

What do you think?

Thanks,
Slava. 

[1] https://elixir.bootlin.com/linux/v7.1-rc3/source/net/ceph/osdmap.c#L1610

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-05-15 18:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <8edcef9c-0b7c-46dc-8094-dc55b62567d3@tu-ilmenau.de>
     [not found] ` <20260513081425.1477060-1-raphael.zimmer@tu-ilmenau.de>
2026-05-13 16:40   ` [PATCH] libceph: Fix multiplication overflow in __decode_pg_upmap_items() Viacheslav Dubeyko
2026-05-13 17:18     ` Viacheslav Dubeyko
2026-05-15  7:41       ` Raphael Zimmer
2026-05-15 18:40         ` Viacheslav Dubeyko
2026-05-13 16:40 ` [bug report] libceph: Multiplication overflow that leads to out-of-bounds writes " Viacheslav Dubeyko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.