Re: [PATCH] libceph: Assign requests to homeless osd if calculated osd exceeds max_osd

Raphael Zimmer <[email protected]>
Newsgroups org.kernel.vger.ceph-devel
Message-ID <[email protected]>
On 29.06.26 7:30 PM, Viacheslav Dubeyko wrote:
> On Mon, 2026-06-29 at 09:46 -0700, Viacheslav Dubeyko wrote:
>> CC: [email protected]
>>
>> On Mon, 2026-06-29 at 10:42 +0200, Raphael Zimmer wrote:
>>> A corrupted osdmap received from a Ceph monitor or OSD may contain
>>> placement groups with osd indices greater than max_osd.
>>> Subsequently,
>>> this may lead to calc_target() returning such an index as target
>>> osd
>>> for
>>> a (linger) request. Because the osd_state, osd_weight, and osd_addr
>>> arrays only contain max_osd entries, this leads to out-of-bounds
>>> accesses when trying to read values from these arrays.
>>>
>>> This patch fixes the issue by adding a check to calc_target()
>>> assigning
>>> the request to the homeless osd if the target osd index read from
>>> the
>>> osdmap exceeds the maximum index of an osd.
>>>
>>> Fixes: 63244fa123a7 ("libceph: introduce ceph_osd_request_target,
>>> calc_target()")
>>> Signed-off-by: Raphael Zimmer <[email protected]>
>>> ---
>>>  net/ceph/osd_client.c | 6 ++++++
>>>  1 file changed, 6 insertions(+)
>>>
>>> diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
>>> index a4d3cbfd27a3..3ae7c51e2edc 100644
>>> --- a/net/ceph/osd_client.c
>>> +++ b/net/ceph/osd_client.c
>>> @@ -1707,6 +1707,12 @@ static enum calc_target_result
>>> calc_target(struct ceph_osd_client *osdc,
>>>  		}
>>>  	}
>>>  
>>> +	if (t->osd >= osdc->osdmap->max_osd) {
> 
> The t->osd is int, osdc->osdmap->max_osd is u32. In C, the signed
> operand is promoted to unsigned in a mixed comparison. If t->osd ==
> CEPH_HOMELESS_OSD == -1, the comparison becomes (u32)-1 >= max_osd. The
> check fires on every homeless request. I think we need to be more
> careful in this comparison:
> 
> if (t->osd >= 0 && (u32)t->osd >= osdc->osdmap->max_osd)
> 

You're right, I missed this point. I will fix it.

>>> +		t->osd = CEPH_HOMELESS_OSD;
>>> +		ct_res = CALC_TARGET_NO_ACTION;
> 
> I am not completely sure that CALC_TARGET_NO_ACTION is correct setting.
> We set req->r_t.osd == CEPH_HOMELESS_OSD while req->r_osd still points
> to the old OSD. I assume that request will be sent to the wrong OSD and
> it will never retried via the homeless path. The calc_target() has
> multiple callers. Should we set ct_res to CALC_TARGET_NEED_RESEND?

I also wasn't sure which option would be the best for ct_res in this
specific case of a corrupted osdmap. It sounds reasonable to me to
switch to CALC_TARGET_NEED_RESEND.

I will send a new version of the patch with these modifications.

Best regards,
Raphael

> 
> Thanks,
> Slava.
> 
>>> +		goto out;
>>> +	}
>>> +
>>>  	if (unpaused || legacy_change || force_resend || split)
>>>  		ct_res = CALC_TARGET_NEED_RESEND;
>>>  	else
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.