All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Gibson <david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
To: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Cc: Devicetree Compiler
	<devicetree-compiler-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH v5 4/7] libfdt: Add support for disabling sanity checks
Date: Tue, 11 Feb 2020 12:12:31 +1100	[thread overview]
Message-ID: <20200211011231.GI22584@umbus.fritz.box> (raw)
In-Reply-To: <20200206054034.162732-5-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 8098 bytes --]

On Wed, Feb 05, 2020 at 10:40:31PM -0700, Simon Glass wrote:
> Allow enabling ASSUME_VALID_INPUT to disable sanity checks on the device
> tree and the parameters to libfdt. This assumption covers that cases where
> the problem could be with either.
> 
> Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
> 
> Changes in v5:
> - Include just VALID_INPUT checks in this patch
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  libfdt/fdt.c    | 12 +++++----
>  libfdt/fdt_ro.c | 71 ++++++++++++++++++++++++++++++++-----------------
>  2 files changed, 54 insertions(+), 29 deletions(-)
> 
> diff --git a/libfdt/fdt.c b/libfdt/fdt.c
> index 03f2b7d..e2c1da0 100644
> --- a/libfdt/fdt.c
> +++ b/libfdt/fdt.c
> @@ -126,10 +126,11 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
>  {
>  	unsigned absoffset = offset + fdt_off_dt_struct(fdt);
>  
> -	if ((absoffset < offset)
> -	    || ((absoffset + len) < absoffset)
> -	    || (absoffset + len) > fdt_totalsize(fdt))
> -		return NULL;
> +	if (!can_assume(VALID_INPUT))
> +		if ((absoffset < offset)
> +		    || ((absoffset + len) < absoffset)
> +		    || (absoffset + len) > fdt_totalsize(fdt))
> +			return NULL;
>  
>  	if (fdt_version(fdt) >= 0x11)
>  		if (((offset + len) < offset)
> @@ -185,7 +186,8 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
>  		return FDT_END;
>  	}
>  
> -	if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
> +	if (!can_assume(VALID_INPUT) &&
> +	    !fdt_offset_ptr(fdt, startoffset, offset - startoffset))
>  		return FDT_END; /* premature end */
>  
>  	*nextoffset = FDT_TAGALIGN(offset);
> diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
> index b41083f..07c13c9 100644
> --- a/libfdt/fdt_ro.c
> +++ b/libfdt/fdt_ro.c
> @@ -16,7 +16,7 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
>  	int olen;
>  	const char *p = fdt_get_name(fdt, offset, &olen);
>  
> -	if (!p || olen < len)
> +	if (!p || (!can_assume(VALID_INPUT) && olen < len))

Oof, this one's subtle.  We certainly *can* have olen < len even in
perfectly valid cases.  However, if we're assuming validly \0
terminated strings in the strings block *and* no \0s in s (which you
can with assume(VALID_INPUT)), then the memcmp() will necessarily pick
up that case.

If we also assume memcmp() is the obvious byte-by-byte implementation
then it will stop before accessing beyond the end of the strings block
string.  But... I don't think that's necessarily the case for all C
libraries / runtimes.  So, if this is close to the end of the strings
block, the memcmp() could access beyond the dtb buffer, which is a no
no.

Now, I guess we could have an assume(DUMB_MEMCMP) and/or
assume(READ_ACCESS_SLIGHTLY_BEYOND_THE_DTB_WILL_WORK), but we're
getting really esoteric now.

Is avoiding this one comparison worth it?

>  		/* short match */
>  		return 0;
>  
> @@ -33,17 +33,26 @@ static int fdt_nodename_eq_(const void *fdt, int offset,
>  
>  const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
>  {
> -	int32_t totalsize = fdt_ro_probe_(fdt);
> -	uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
> +	int32_t totalsize;
> +	uint32_t absoffset;
>  	size_t len;
>  	int err;
>  	const char *s, *n;
>  
> +	if (can_assume(VALID_INPUT)) {
> +		s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
> +
> +		if (lenp)
> +			*lenp = strlen(s);
> +		return s;
> +	}
> +	totalsize = fdt_ro_probe_(fdt);
>  	err = totalsize;
>  	if (totalsize < 0)
>  		goto fail;
>  
>  	err = -FDT_ERR_BADOFFSET;
> +	absoffset = stroffset + fdt_off_dt_strings(fdt);
>  	if (absoffset >= totalsize)
>  		goto fail;
>  	len = totalsize - absoffset;
> @@ -151,10 +160,13 @@ 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;
> +	if (!can_assume(VALID_INPUT)) {
> +		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);
>  }
>  
> @@ -164,7 +176,7 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
>  
>  	FDT_RO_PROBE(fdt);
>  	re = fdt_mem_rsv(fdt, n);
> -	if (!re)
> +	if (!can_assume(VALID_INPUT) && !re)
>  		return -FDT_ERR_BADOFFSET;
>  
>  	*address = fdt64_ld(&re->address);
> @@ -292,8 +304,9 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
>  	if (!can_assume(VALID_DTB)) {
>  		if ((err = fdt_ro_probe_(fdt)) < 0)
>  			goto fail;
> -		if ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
> -			goto fail;
> +		if (can_assume(VALID_INPUT) &&

That should be !can_assume, no?

> +		    (err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
> +		goto fail;
>  	}
>  
>  	nameptr = nh->name;
> @@ -349,7 +362,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
>  	int err;
>  	const struct fdt_property *prop;
>  
> -	if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
> +	if (!can_assume(VALID_INPUT) &&
> +	    (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
>  		if (lenp)
>  			*lenp = err;
>  		return NULL;
> @@ -391,7 +405,8 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
>  	     (offset = fdt_next_property_offset(fdt, offset))) {
>  		const struct fdt_property *prop;
>  
> -		if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
> +		prop = fdt_get_property_by_offset_(fdt, offset, lenp);
> +		if (!can_assume(VALID_INPUT) && !prop) {
>  			offset = -FDT_ERR_INTERNAL;

So, arguably you could put this one under a weaker assumption flag.
Basicaly FDT_ERR_INTERNAL errors should *never* happen, even with bad
input - they're basically assert()s, except I didn't want to rely on
the runtime things that assert() needs.

>  			break;
>  		}
> @@ -464,14 +479,19 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
>  	if (namep) {
>  		const char *name;
>  		int namelen;
> -		name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
> -				      &namelen);
> -		if (!name) {
> -			if (lenp)
> -				*lenp = namelen;
> -			return NULL;
> +
> +		if (!can_assume(VALID_INPUT)) {
> +			name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
> +					      &namelen);
> +			if (!name) {
> +				if (lenp)
> +					*lenp = namelen;
> +				return NULL;
> +			}
> +			*namep = name;
> +		} else {
> +			*namep = fdt_string(fdt, fdt32_ld(&prop->nameoff));
>  		}
> -		*namep = name;
>  	}
>  
>  	/* Handle realignment */
> @@ -601,10 +621,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
>  		}
>  	}
>  
> -	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
> -		return -FDT_ERR_BADOFFSET;
> -	else if (offset == -FDT_ERR_BADOFFSET)
> -		return -FDT_ERR_BADSTRUCTURE;
> +	if (!can_assume(VALID_INPUT)) {
> +		if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
> +			return -FDT_ERR_BADOFFSET;
> +		else if (offset == -FDT_ERR_BADOFFSET)
> +			return -FDT_ERR_BADSTRUCTURE;
> +	}
>  
>  	return offset; /* error from fdt_next_node() */
>  }
> @@ -616,7 +638,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset)
>  
>  	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
>  	if (err)
> -		return (err < 0) ? err : -FDT_ERR_INTERNAL;
> +		return (can_assume(VALID_INPUT) || err < 0) ? err :
> +			-FDT_ERR_INTERNAL;
>  	return nodedepth;
>  }
>  

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  parent reply	other threads:[~2020-02-11  1:12 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-06  5:40 [PATCH v5 0/7] libfdt: Allow more control of code size Simon Glass
     [not found] ` <20200206054034.162732-1-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2020-02-06  5:40   ` [PATCH v5 1/7] libfdt: De-inline fdt_header_size() Simon Glass
2020-02-06  5:40   ` [PATCH v5 2/7] Add a way to control the level of checks in the code Simon Glass
2020-02-06  5:40   ` [PATCH v5 3/7] libfdt: Add support for disabling dtb checks Simon Glass
     [not found]     ` <20200206054034.162732-4-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2020-02-10  4:02       ` David Gibson
     [not found]         ` <20200210040201.GA22584-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>
2020-02-11  1:04           ` Simon Glass
     [not found]             ` <CAPnjgZ3Ut2CCVqDnRiafMqR+sV0eMn_obhcXYLfbuQgXhhPS1Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2020-02-11  1:42               ` David Gibson
     [not found]                 ` <20200211014254.GJ22584-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>
2020-02-11 20:08                   ` Simon Glass
     [not found]                     ` <CAPnjgZ2M+Y7ExHar2+iCinW+w8DniNUFn=_VRs+-_+zfRuoG7Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2020-02-12  0:53                       ` David Gibson
     [not found]                         ` <20200212005316.GM22584-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>
2020-02-12  1:20                           ` Simon Glass
2020-02-06  5:40   ` [PATCH v5 4/7] libfdt: Add support for disabling sanity checks Simon Glass
     [not found]     ` <20200206054034.162732-5-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2020-02-11  1:12       ` David Gibson [this message]
     [not found]         ` <20200211011231.GI22584-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>
2020-02-11 20:08           ` Simon Glass
     [not found]             ` <CAPnjgZ29PgXrG65RKVsGFzxiSYX5VJrynD+u-mwwiFO+HkKQPg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2020-02-12  1:05               ` David Gibson
     [not found]                 ` <20200212010519.GN22584-K0bRW+63XPQe6aEkudXLsA@public.gmane.org>
2020-02-12  1:23                   ` Simon Glass
     [not found]                     ` <CAPnjgZ1apEQmMYKT0TVQQOGgtUwOHryRbmujO92ovqHjT1rxrg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2020-02-12  2:05                       ` David Gibson
2020-02-06  5:40   ` [PATCH v5 5/7] libfdt: Add support for disabling rollback handling Simon Glass
2020-02-06  5:40   ` [PATCH v5 6/7] libfdt: Add support for disabling version checks Simon Glass
     [not found]     ` <20200206054034.162732-7-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2020-02-11  3:10       ` David Gibson
2020-02-06  5:40   ` [PATCH v5 7/7] libfdt: Allow exclusion of fdt_check_full() Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200211011231.GI22584@umbus.fritz.box \
    --to=david-xt8fgy+axnrb3ne2bgzf6laj5h9x9tb+@public.gmane.org \
    --cc=devicetree-compiler-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.