mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: Douglas Anderson <dianders@chromium.org>
Cc: Devicetree-compiler@vger.kernel.org,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Konrad Dybcio" <konradybcio@kernel.org>,
	"Peter Griffin" <peter.griffin@linaro.org>,
	"Saravana Kannan" <saravanak@kernel.org>,
	Devicetree@vger.kernel.org, "Simon Glass" <sjg@chromium.org>,
	"Chen-Yu Tsai" <wenst@chromium.org>,
	"Julius Werner" <jwerner@chromium.org>,
	"Brian Norris" <briannorris@chromium.org>,
	linux-kernel@vger.kernel.org,
	"Tudor Ambarus" <tudor.ambarus@linaro.org>,
	"André Draszik" <andre.draszik@linaro.org>
Subject: Re: [PATCH v3 01/15] libfdt: overlay: Fix out-of-bounds write on bad fixup offset
Date: Mon, 2 Nov 2026 15:29:10 +1100	[thread overview]
Message-ID: <augRiw6Z9CKcwo_w@gractus.seuss> (raw)
In-Reply-To: <20261101220224.1436242-2-dianders@chromium.org>

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

On Sun, Nov 01, 2026 at 02:01:08PM -0800, Douglas Anderson wrote:
> A malformed overlay with a negative or very large fixup offset in
> /__fixups__ (such as "/fragment@0:target:-4" or
> "/fragment@0:target:4294967292") can cause an out-of-bounds write during
> overlay application:
> 
> 1. overlay_fixup_phandle() parses the offset with strtoul(), which
>    accepts negative numbers and values larger than UINT32_MAX, and
>    truncates the result into a 32-bit integer.
> 2. fdt_setprop_inplace_namelen_partial() checks bounds with
>    `(unsigned)proplen < (len + idx)`, where `len + idx` wraps around to
>    a small number when `idx` is near UINT32_MAX, bypassing the check and
>    passing the huge offset to memcpy().
> 
> Tighten the fixup offset parsing in overlay_fixup_phandle(), fix the
> bounds check in fdt_setprop_inplace_namelen_partial() to avoid unsigned
> wrap-around, and add test cases covering both negative and overflowing
> offsets.
> 
> Assisted-by: Gemini:gemini-pro-prerelease
> Signed-off-by: Douglas Anderson <dianders@chromium.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

Thanks for this - this bug has been reported by a couple of people,
and I hadn't gotten around to making my own fix.

> ---
> 
> Changes in v3:
> - Split the fixup offset overflow fix and fdt_wip.c bounds check out of
>   "libfdt: overlay: Prepare fixup and fragment path helpers for reuse"
>   into a standalone bugfix patch with dedicated tests (Simon Glass)
> - Add a comment explaining why an initial ASCII digit check is needed
>   before strtoul() (David Gibson)
> 
>  libfdt/fdt_overlay.c                       | 34 +++++++++++++++++-----
>  libfdt/fdt_wip.c                           |  7 ++++-
>  tests/overlay_bad_fixup_negative_index.dts |  9 ++++++
>  tests/overlay_bad_fixup_overflow_index.dts |  9 ++++++
>  tests/run_tests.sh                         |  2 ++
>  tests/setprop_inplace.c                    |  8 +++++
>  6 files changed, 60 insertions(+), 9 deletions(-)
>  create mode 100644 tests/overlay_bad_fixup_negative_index.dts
>  create mode 100644 tests/overlay_bad_fixup_overflow_index.dts
> 
> diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c
> index 51a3859620a4..c6dc4774cff3 100644
> --- a/libfdt/fdt_overlay.c
> +++ b/libfdt/fdt_overlay.c
> @@ -330,10 +330,10 @@ static int overlay_update_local_references(void *fdto, uint32_t delta)
>  static int overlay_fixup_one_phandle(void *fdto, int symbols_off,
>  				     const char *path, uint32_t path_len,
>  				     const char *name, uint32_t name_len,
> -				     int poffset, uint32_t phandle)
> +				     uint32_t poffset, uint32_t phandle)
>  {
>  	fdt32_t phandle_prop;
> -	int fixup_off;
> +	int fixup_off, ret;
>  
>  	if (symbols_off < 0)
>  		return symbols_off;
> @@ -345,10 +345,20 @@ static int overlay_fixup_one_phandle(void *fdto, int symbols_off,
>  		return fixup_off;
>  
>  	phandle_prop = cpu_to_fdt32(phandle);
> -	return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
> -						   name, name_len, poffset,
> -						   &phandle_prop,
> -						   sizeof(phandle_prop));
> +	ret = fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
> +						  name, name_len, poffset,
> +						  &phandle_prop,
> +						  sizeof(phandle_prop));
> +	/*
> +	 * fdt_setprop_inplace_namelen_partial() only returns -FDT_ERR_NOSPACE
> +	 * when poffset + sizeof(phandle_prop) exceeds the existing property's
> +	 * length in the overlay, which means the overlay is malformed (not
> +	 * that the base DTB buffer ran out of space).
> +	 */
> +	if (ret == -FDT_ERR_NOSPACE)
> +		return -FDT_ERR_BADOVERLAY;
> +
> +	return ret;
>  }
>  
>  /**
> @@ -409,7 +419,8 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
>  		uint32_t fixup_len;
>  		const char *sep;
>  		char *endptr;
> -		int poffset, ret;
> +		unsigned long poffset;
> +		int ret;
>  
>  		fixup_end = memchr(value, '\0', len);
>  		if (!fixup_end)
> @@ -438,8 +449,15 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
>  		if (!name_len)
>  			return -FDT_ERR_BADOVERLAY;
>  
> +		/*
> +		 * Require an initial ASCII digit because strtoul() accepts
> +		 * leading whitespace and '+'/'-' signs (wrapping negative
> +		 * values to unsigned long).
> +		 */
> +		if ((*(sep + 1) < '0') || (*(sep + 1) > '9'))
> +			return -FDT_ERR_BADOVERLAY;
>  		poffset = strtoul(sep + 1, &endptr, 10);
> -		if ((*endptr != '\0') || (endptr <= (sep + 1)))
> +		if ((*endptr != '\0') || (poffset > UINT32_MAX))
>  			return -FDT_ERR_BADOVERLAY;
>  
>  		ret = overlay_fixup_one_phandle(fdto, symbols_off,
> diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c
> index c2d7566a67dc..dd163d91498c 100644
> --- a/libfdt/fdt_wip.c
> +++ b/libfdt/fdt_wip.c
> @@ -23,7 +23,12 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
>  	if (!propval)
>  		return proplen;
>  
> -	if ((unsigned)proplen < (len + idx))
> +	/*
> +	 * Check that idx + len fits within proplen using subtraction rather
> +	 * than addition so that a large idx (or negative len) cannot wrap
> +	 * around 32-bit unsigned arithmetic.
> +	 */
> +	if (idx > (unsigned)proplen || (unsigned)len > (unsigned)proplen - idx)
>  		return -FDT_ERR_NOSPACE;
>  
>  	memcpy((char *)propval + idx, val, len);
> diff --git a/tests/overlay_bad_fixup_negative_index.dts b/tests/overlay_bad_fixup_negative_index.dts
> new file mode 100644
> index 000000000000..02ccee905e85
> --- /dev/null
> +++ b/tests/overlay_bad_fixup_negative_index.dts
> @@ -0,0 +1,9 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +/include/ "overlay_bad_fixup_base.dtsi"
> +
> +/ {
> +	__fixups__ {
> +		test = "/fragment@0:target:-4";
> +	};
> +};
> diff --git a/tests/overlay_bad_fixup_overflow_index.dts b/tests/overlay_bad_fixup_overflow_index.dts
> new file mode 100644
> index 000000000000..d7d05267d7b3
> --- /dev/null
> +++ b/tests/overlay_bad_fixup_overflow_index.dts
> @@ -0,0 +1,9 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +/include/ "overlay_bad_fixup_base.dtsi"
> +
> +/ {
> +	__fixups__ {
> +		test = "/fragment@0:target:4294967292";
> +	};
> +};
> diff --git a/tests/run_tests.sh b/tests/run_tests.sh
> index 5bc7817dd12a..0d815e307909 100755
> --- a/tests/run_tests.sh
> +++ b/tests/run_tests.sh
> @@ -274,6 +274,8 @@ BAD_FIXUP_TREES="bad_index \
>  		empty \
>  		empty_index \
>  		index_trailing \
> +		negative_index \
> +		overflow_index \
>  		path_empty_prop \
>  		path_only \
>  		path_only_sep \
> diff --git a/tests/setprop_inplace.c b/tests/setprop_inplace.c
> index 61a0da16fce8..48182169fbf6 100644
> --- a/tests/setprop_inplace.c
> +++ b/tests/setprop_inplace.c
> @@ -80,5 +80,13 @@ int main(int argc, char *argv[])
>  	check_getprop(fdt, 0, "compatible", strlen(TEST_STRING_4_RESULT) + 1,
>  		      TEST_STRING_4_RESULT);
>  
> +	err = fdt_setprop_inplace_namelen_partial(fdt, 0, "compatible",
> +						  strlen("compatible"),
> +						  0xfffffffcU,
> +						  TEST_STRING_4_PARTIAL, 4);
> +	if (err != -FDT_ERR_NOSPACE)
> +		FAIL("fdt_setprop_inplace_namelen_partial() with wrapping idx returned %d instead of -FDT_ERR_NOSPACE\n",
> +		     err);
> +
>  	PASS();
>  }
> -- 
> 2.56.0.317.g454f8302e1-goog
> 
> 

-- 
David Gibson (he or they)	| 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 --]

  reply	other threads:[~2026-11-02  4:29 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-01 22:01 [PATCH v3 00/15] fdtfactor: Introduce fdtfactor to auto-factor overlays Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 01/15] libfdt: overlay: Fix out-of-bounds write on bad fixup offset Douglas Anderson
2026-11-02  4:29   ` David Gibson [this message]
2026-11-01 22:01 ` [PATCH v3 02/15] libfdt: overlay: Drop redundant *sep != ':' checks after memchr() Douglas Anderson
2026-11-02  4:30   ` David Gibson
2026-11-01 22:01 ` [PATCH v3 03/15] pylibfdt: Clarify iterator docstrings and test negative offsets Douglas Anderson
2026-11-02  4:32   ` David Gibson
2026-11-01 22:01 ` [PATCH v3 04/15] pylibfdt: Handle empty properties in as_str() and as_stringlist() Douglas Anderson
2026-11-02  4:33   ` David Gibson
2026-11-01 22:01 ` [PATCH v3 05/15] pylibfdt: Add Fdt.set_boot_cpuid_phys() Douglas Anderson
2026-11-02  4:34   ` David Gibson
2026-11-01 22:01 ` [PATCH v3 06/15] pylibfdt: Support copy.copy() and copy.deepcopy() on Property Douglas Anderson
2026-11-02  4:35   ` David Gibson
2026-11-01 22:01 ` [PATCH v3 07/15] devicetree: Add DeviceTree live tree representation Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 08/15] libfdt: overlay: Factor out fixup and fragment path parsing helpers Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 09/15] libfdt: overlay: Prepare fragment path helper for reuse Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 10/15] libfdt: overlay: Make fdto const in overlay_apply_node() Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 11/15] libfdt: overlay: Update base /__local_fixups__ on apply Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 12/15] fdtfactor: Add tool to split DTBs into a base DTB and overlays Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 13/15] fdtfactor: Add -S/--strip-local-fixups option Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 14/15] fdtfactor: Support compressed DTB inputs and outputs Douglas Anderson
2026-11-01 22:01 ` [PATCH v3 15/15] fdtfactor: Add compiled FIT factoring support Douglas Anderson
2026-11-02  4:44 ` [PATCH v3 00/15] fdtfactor: Introduce fdtfactor to auto-factor overlays David Gibson

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=augRiw6Z9CKcwo_w@gractus.seuss \
    --to=david@gibson.dropbear.id.au \
    --cc=Devicetree-compiler@vger.kernel.org \
    --cc=Devicetree@vger.kernel.org \
    --cc=andre.draszik@linaro.org \
    --cc=briannorris@chromium.org \
    --cc=conor+dt@kernel.org \
    --cc=dianders@chromium.org \
    --cc=jwerner@chromium.org \
    --cc=konradybcio@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peter.griffin@linaro.org \
    --cc=robh@kernel.org \
    --cc=saravanak@kernel.org \
    --cc=sjg@chromium.org \
    --cc=tudor.ambarus@linaro.org \
    --cc=wenst@chromium.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®