diff mbox series

device_tree: check device tree blob file size

Message ID 20190322073555.20889-1-ppandit@redhat.com (mailing list archive)
State New, archived
Headers show
Series device_tree: check device tree blob file size | expand

Commit Message

Prasad Pandit March 22, 2019, 7:35 a.m. UTC
From: Prasad J Pandit <pjp@fedoraproject.org>

Device tree blob(dtb) file can not be larger than 2MB in size.[*]
Add check to avoid loading large dtb files in load_device_tree(),
and potential integer(dt_size) overflow.

[*] linux.git/tree/Documentation/arm64/booting.txt

Reported-by: Kurtis Miller <kurtis.miller@nccgroup.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
 device_tree.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Comments

Peter Maydell March 22, 2019, 9:14 a.m. UTC | #1
On Fri, 22 Mar 2019 at 07:38, P J P <ppandit@redhat.com> wrote:
>
> From: Prasad J Pandit <pjp@fedoraproject.org>
>
> Device tree blob(dtb) file can not be larger than 2MB in size.[*]
> Add check to avoid loading large dtb files in load_device_tree(),
> and potential integer(dt_size) overflow.
>
> [*] linux.git/tree/Documentation/arm64/booting.txt

This document is specific to aarch64, but the part of
QEMU's device tree code being modified here is
architecture independent.

Cc'ing David Gibson who will probably know if there is
an architecture-independent limit on DTB size we should
be enforcing, or whether we are better just to have a check
that avoids the overflow.

It's also worth noting in the commit message that this is
not a security problem -- even if the "add 10000 and double"
calculation overflows, the load_image_size() function will
not load more data into the buffer than will fit, so the
behaviour will be to truncate the DTB.

> Reported-by: Kurtis Miller <kurtis.miller@nccgroup.com>
> Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
> ---
>  device_tree.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/device_tree.c b/device_tree.c
> index 296278e12a..9059ee5545 100644
> --- a/device_tree.c
> +++ b/device_tree.c
> @@ -79,9 +79,9 @@ void *load_device_tree(const char *filename_path, int *sizep)
>
>      *sizep = 0;
>      dt_size = get_image_size(filename_path);
> -    if (dt_size < 0) {
> -        error_report("Unable to get size of device tree file '%s'",
> -                     filename_path);
> +    if (dt_size < 0 || dt_size > FDT_MAX_SIZE) {
> +        error_report("Invalid size of device tree file: %s: %d",
> +                     filename_path, dt_size);
>          goto fail;
>      }

thanks
-- PMM
Prasad Pandit March 22, 2019, 10:10 a.m. UTC | #2
+-- On Fri, 22 Mar 2019, Peter Maydell wrote --+
| This document is specific to aarch64, but the part of
| QEMU's device tree code being modified here is
| architecture independent.
| 
| Cc'ing David Gibson who will probably know if there is
| an architecture-independent limit on DTB size we should
| be enforcing, or whether we are better just to have a check
| that avoids the overflow.

Thank you for CC'ing David. It seems Agraf did not receive email @suse.de.

Current limit defined by FDT_MAX_SIZE is ~1MB.

device_tree.c:
#define FDT_MAX_SIZE  0x100000
 
| It's also worth noting in the commit message that this is
| not a security problem -- even if the "add 10000 and double"
| calculation overflows, the load_image_size() function will
| not load more data into the buffer than will fit, so the
| behaviour will be to truncate the DTB.

True, load_image_size() helps to avoid buffer overflow issue.

Proposed check (dt_size > FDT_MAX_SIZE) in this patch is to enforce same size 
limit as used in create_device_tree() and avoid loading large files and the 
said integer overflow.

Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
Peter Maydell March 22, 2019, 10:30 a.m. UTC | #3
On Fri, 22 Mar 2019 at 10:11, P J P <ppandit@redhat.com> wrote:
>
> +-- On Fri, 22 Mar 2019, Peter Maydell wrote --+
> | This document is specific to aarch64, but the part of
> | QEMU's device tree code being modified here is
> | architecture independent.
> |
> | Cc'ing David Gibson who will probably know if there is
> | an architecture-independent limit on DTB size we should
> | be enforcing, or whether we are better just to have a check
> | that avoids the overflow.
>
> Thank you for CC'ing David. It seems Agraf did not receive email @suse.de.

Yes, Alex's email has changed (I've updated the cc list).

> Current limit defined by FDT_MAX_SIZE is ~1MB.

But currently this is only used when creating a DT from scratch.

> Proposed check (dt_size > FDT_MAX_SIZE) in this patch is to enforce same size
> limit as used in create_device_tree() and avoid loading large files and the
> said integer overflow.

My worry is that this might possibly break existing
working use cases which load a device tree that is larger
than 1MB. Unless there's a cross-architecture justification
for the 1MB limit it seems quite a low one to be enforcing
(especially since the one limit we've found so far for
aarch64 is 2MB, not 1MB).

thanks
-- PMM
David Gibson March 25, 2019, 1:38 a.m. UTC | #4
On Fri, Mar 22, 2019 at 09:14:53AM +0000, Peter Maydell wrote:
> On Fri, 22 Mar 2019 at 07:38, P J P <ppandit@redhat.com> wrote:
> >
> > From: Prasad J Pandit <pjp@fedoraproject.org>
> >
> > Device tree blob(dtb) file can not be larger than 2MB in size.[*]
> > Add check to avoid loading large dtb files in load_device_tree(),
> > and potential integer(dt_size) overflow.
> >
> > [*] linux.git/tree/Documentation/arm64/booting.txt
> 
> This document is specific to aarch64, but the part of
> QEMU's device tree code being modified here is
> architecture independent.
> 
> Cc'ing David Gibson who will probably know if there is
> an architecture-independent limit on DTB size we should
> be enforcing, or whether we are better just to have a check
> that avoids the overflow.

The only inherent limit to dtb size should be 2^31-1 bytes (the format
uses signed 32-bit ints as offsets).

Indeed there shouldn't be any architecture (as in instruction set)
dependent limits either.  There may however be more specific platform
dependent limits.

> It's also worth noting in the commit message that this is
> not a security problem -- even if the "add 10000 and double"
> calculation overflows, the load_image_size() function will
> not load more data into the buffer than will fit, so the
> behaviour will be to truncate the DTB.

Yeah, you should probably make that hard error rather than truncating.
If a system works with a truncated tree, it can only be by sheer
accident.
David Gibson March 25, 2019, 1:39 a.m. UTC | #5
On Fri, Mar 22, 2019 at 10:30:51AM +0000, Peter Maydell wrote:
> On Fri, 22 Mar 2019 at 10:11, P J P <ppandit@redhat.com> wrote:
> >
> > +-- On Fri, 22 Mar 2019, Peter Maydell wrote --+
> > | This document is specific to aarch64, but the part of
> > | QEMU's device tree code being modified here is
> > | architecture independent.
> > |
> > | Cc'ing David Gibson who will probably know if there is
> > | an architecture-independent limit on DTB size we should
> > | be enforcing, or whether we are better just to have a check
> > | that avoids the overflow.
> >
> > Thank you for CC'ing David. It seems Agraf did not receive email @suse.de.
> 
> Yes, Alex's email has changed (I've updated the cc list).
> 
> > Current limit defined by FDT_MAX_SIZE is ~1MB.
> 
> But currently this is only used when creating a DT from scratch.

Right, and AFAIK the only reason we have a fixed buffer size for that
is because it avoids having to mess around with reallocation if we hit
an -FDT_ERR_NOSPACE during creation.
Prasad Pandit March 25, 2019, 10:34 a.m. UTC | #6
Hello David,

+-- On Mon, 25 Mar 2019, David Gibson wrote --+
| The only inherent limit to dtb size should be 2^31-1 bytes (the format
| uses signed 32-bit ints as offsets).

  ~2GB of dtb?! Seems quite big to specify the h/w that a kernel is
going to run/boot on.

| Indeed there shouldn't be any architecture (as in instruction set)
| dependent limits either.  There may however be more specific platform
| dependent limits.

  $ find . -name \*.dts -exec ls -shXS --color {} \; | sort -grk1 | less -r

   -> https://paste.fedoraproject.org/paste/~9p-lVWwX7jmngHMQjCBsg

Going through the .dts files in the Linux kernel tree, 64KB appears to top 
the list of file sizes.

IMO, generic 2MB of dtb size limit is reasonable; Considering 64KB is the max 
we are seeing, plus QEMU has FDT_MAX_SIZE defined to be 0x100000(~1MB), and 
noone has complained that it's too small.

| Yeah, you should probably make that hard error rather than truncating.
| If a system works with a truncated tree, it can only be by sheer
| accident.

Yes, current patch would 'goto fail; if (dt_size > FDT_MAX_SIZE)'.


Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
Peter Maydell March 25, 2019, 10:38 a.m. UTC | #7
On Mon, 25 Mar 2019 at 10:34, P J P <ppandit@redhat.com> wrote:
> IMO, generic 2MB of dtb size limit is reasonable; Considering 64KB is the max
> we are seeing, plus QEMU has FDT_MAX_SIZE defined to be 0x100000(~1MB), and
> noone has complained that it's too small.

Noone has complained that it's too small because right now
*we do not check against it* for the common case of "just
load an external dtb".

We should not be imposing an arbitrary limit within QEMU
if we don't need to. Here, we do not need to.

thanks
-- PMM
Prasad Pandit March 25, 2019, 4:11 p.m. UTC | #8
+-- On Mon, 25 Mar 2019, Peter Maydell wrote --+
| Noone has complained that it's too small because right now *we do not check 
| against it* for the common case of "just load an external dtb".
| 
| We should not be imposing an arbitrary limit within QEMU if we don't need 
| to. Here, we do not need to.

  Hmmn, it could help to avoid loading of truncated dtb files as David pointed 
out.

Thank you.
--
Prasad J Pandit / Red Hat Product Security Team
47AF CE69 3A90 54AA 9045 1053 DD13 3D32 FE5B 041F
Peter Maydell March 25, 2019, 4:18 p.m. UTC | #9
On Mon, 25 Mar 2019 at 16:11, P J P <ppandit@redhat.com> wrote:
>
> +-- On Mon, 25 Mar 2019, Peter Maydell wrote --+
> | Noone has complained that it's too small because right now *we do not check
> | against it* for the common case of "just load an external dtb".
> |
> | We should not be imposing an arbitrary limit within QEMU if we don't need
> | to. Here, we do not need to.
>
>   Hmmn, it could help to avoid loading of truncated dtb files as David pointed
> out.

Yes, we don't want to do that. We can do that in a less
arbitrary manner than "impose a flat 1MB limit".

thanks
-- PMM
David Gibson March 25, 2019, 11:07 p.m. UTC | #10
On Mon, Mar 25, 2019 at 04:04:33PM +0530, P J P wrote:
>   Hello David,
> 
> +-- On Mon, 25 Mar 2019, David Gibson wrote --+
> | The only inherent limit to dtb size should be 2^31-1 bytes (the format
> | uses signed 32-bit ints as offsets).
> 
>   ~2GB of dtb?! Seems quite big to specify the h/w that a kernel is
> going to run/boot on.

Well, sure, but why would we impose a limit when we didn't have a need
to.
diff mbox series

Patch

diff --git a/device_tree.c b/device_tree.c
index 296278e12a..9059ee5545 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -79,9 +79,9 @@  void *load_device_tree(const char *filename_path, int *sizep)
 
     *sizep = 0;
     dt_size = get_image_size(filename_path);
-    if (dt_size < 0) {
-        error_report("Unable to get size of device tree file '%s'",
-                     filename_path);
+    if (dt_size < 0 || dt_size > FDT_MAX_SIZE) {
+        error_report("Invalid size of device tree file: %s: %d",
+                     filename_path, dt_size);
         goto fail;
     }