Re: [PATCH 05/12] libfdt: Safer access to memory reservations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



On 4/4/18 9:06 pm, David Gibson wrote:
> On Tue, Mar 27, 2018 at 06:09:12PM +1100, Alexey Kardashevskiy wrote:
>> On 26/3/18 10:25 am, David Gibson wrote:
>>> fdt_num_mem_rsv() and fdt_get_mem_rsv() currently don't sanity check their
>>> parameters, or the memory reserve section offset in the header.  That means
>>> that on a corrupted blob they could access outside of the range of memory
>>> that they should.
>>>
>>> This improves their safety checking, meaning they shouldn't access outside
>>> the blob's bounds, even if its contents are badly corrupted.
>>>
>>> Signed-off-by: David Gibson <david@xxxxxxxxxxxxxxxxxxxxx>
>>> ---
>>>  libfdt/fdt_ro.c          | 33 ++++++++++++++++++++-----
>>>  tests/.gitignore         |  1 +
>>>  tests/Makefile.tests     |  2 +-
>>>  tests/run_tests.sh       |  1 +
>>>  tests/testdata.h         |  1 +
>>>  tests/trees.S            | 20 +++++++++++++++
>>>  tests/truncated_memrsv.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  7 files changed, 114 insertions(+), 7 deletions(-)
>>>  create mode 100644 tests/truncated_memrsv.c
>>>
>>> diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
>>> index d4cec0e..c74b962 100644
>>> --- a/libfdt/fdt_ro.c
>>> +++ b/libfdt/fdt_ro.c
>>> @@ -170,21 +170,42 @@ uint32_t fdt_get_max_phandle(const void *fdt)
>>>  	return 0;
>>>  }
>>>  
>>> +static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
>>> +{
>>> +	int offset = n * sizeof(struct fdt_reserve_entry);
>>> +	int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
>>> +
>>> +	if (absoffset < fdt_off_mem_rsvmap(fdt))
>>> +		return NULL;
>>> +	if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
>>> +		return NULL;
>>> +	return fdt_mem_rsv_(fdt, n);
>>> +}
>>> +
>>>  int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
>>>  {
>>> +	const struct fdt_reserve_entry *re;
>>> +
>>>  	FDT_RO_PROBE(fdt);
>>> -	*address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
>>> -	*size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
>>> +	re = fdt_mem_rsv(fdt, n);
>>> +	if (!re)
>>> +		return -FDT_ERR_BADOFFSET;
>>> +
>>> +	*address = fdt64_to_cpu(re->address);
>>> +	*size = fdt64_to_cpu(re->size);
>>>  	return 0;
>>>  }
>>>  
>>>  int fdt_num_mem_rsv(const void *fdt)
>>>  {
>>> -	int i = 0;
>>> +	int i;
>>> +	const struct fdt_reserve_entry *re;
>>>  
>>> -	while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
>>> -		i++;
>>> -	return i;
>>> +	for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
>>> +		if (fdt64_to_cpu(re->size) == 0)
>>> +			return i;
>>> +	}
>>> +	return -FDT_ERR_TRUNCATED;
>>
>>
>> QEMU's spapr_h_cas_compose_response() crashes on this one as it calls
>> fdt_open_into() and that guy does not check if fdt_num_mem_rsv() fails and
>> it does as there is no any reserved entry, even an empty one in the end of
>> the list.
>>
>> fdt_create() could create an empty record or fdt_open_into() could test for
>> an error, not sure which one is right here.
> 
> Ah.  So, technically spapr_h_cas_compose_response() is just doing the
> wrong thing here.  You're supposed to construct a mem reserve segment
> between fdt_create() and the first fdt_begin_node(), even if that's
> just a single call to fdt_finish_reservemap().

Fair enough, I've posted a patch for QEMU.

> That said, it would be good for libfdt to be more robust against
> that.  Either fdt_begin_node() should return FDT_ERR_BADSTATE in this
> situatipon, or it should automatically finish off the reserve map.

Returning an error from fdt_begin_node() should do it. Also probably
including fdt_finish() as it looks like it is possible to call fdt_create()
and fdt_finish() without creating nodes in between (have not tested this).

Automation is supposed to fix only one place in QEMU for now and it just
does not seem worth it.


-- 
Alexey
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux