public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: AKASHI Takahiro <takahiro.akashi@linaro.org>
To: u-boot@lists.denx.de
Subject: efi_loader: tighten PE verification code?
Date: Mon, 11 May 2020 11:27:23 +0900	[thread overview]
Message-ID: <20200511022723.GB9483@laputa> (raw)
In-Reply-To: <20200508185637.GA4433@nox.fritz.box>

Patrick,

On Fri, May 08, 2020 at 08:56:37PM +0200, Patrick Wildt wrote:
> Hi,
> 
> even though this mail has a diff, it's not supposed to be a patch.  I
> have started adjusting my fuzzer to the upstreamed EFI Secure Boot code
> and I hit a few issues right away.  Two of those I have already sent and
> were reviewed.  I have seen more, but since I needed to reschedule some
> things I couldn't continue and unfortunately have to postpone fuzzing
> the code.  I can assure you if someone starts fuzzing that code, we will
> find a few more bugs.

Thank you for examining the code.

> Especially since this is "Secure Boot", this part should definitely be
> air tight.

Yeah, we definitely need more eyes on the code.

> One thing I saw is that the virt_size is smaller then the memcpy below
> at the "Copy PE headers" line then actually copies.
> 
> Another thing I saw is SizeOfRawData can be bigger then the VirtualSize,
> and PointerToRawData + SizeOfRawData bigger then the allocated size.
> 
> I'm not sure if this is the right place to do the checks.  Maybe they
> need to be at the place where we are adding the image regions.  I guess
> the fields should be properly verified in view of "does it make sense?".
>
> Also I'm questioning whether it's a good idea to continue parsing the
> file if it's already clear that the signature can't be verified against
> the "db".  I can understand that you'd like to finish loading the file
> into an object, and some other instance decides whether or not it's fine
> to start that image, but you also open yourself to issues when you're
> parsing a file that obviously is against the current security policy.

One comment:
I have changed the logic in a past version when Heinrich pointed
out that we should return EFI_SECURITY_VIOLATION and that image
execution information table must also be supported.

"Status Codes Returned" by LoadImage API in UEFI specification says,

EFI_ACCESS_DENIED:Image was not loaded because the platform policy prohibits
                  the image from being loaded. NULL is returned in *ImageHandle.
EFI_SECURITY_VIOLATION:Image was loaded and an ImageHandle was created with
                  a valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
                  platform policy specifies that the image should not be
                  started.

Now the code returns EFI_SECURITY_VIOLATION, instead of EFI_ACCESS_DENIED,
when image's signature can not be verified but yet the image itself will be
loaded.
When invoking the binary with StartImage API, it fails and put a record
in image execution information table.
(I have not yet submitted a patch for table support though.)

As UEFI specification doesn't say anything about "policy,"
I don't know which error code should be returned here.

-Takahiro Akashi

> If you keep on parsing a file that obviously (because tested against the
> "db") cannot be allowed to boot anyway, the checks for the headers need
> to be even tighter.
> 
> I'd be unhappy to see U-Boot CVEs come up regarding PE parsing issues.
> 
> Best regards,
> Patrick
> 
> diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
> index 43a53d3dd1..d134b748be 100644
> --- a/lib/efi_loader/efi_image_loader.c
> +++ b/lib/efi_loader/efi_image_loader.c
> @@ -681,10 +681,11 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
>  	}
>  
>  	/* Authenticate an image */
> -	if (efi_image_authenticate(efi, efi_size))
> -		handle->auth_status = EFI_IMAGE_AUTH_PASSED;
> -	else
> +	if (!efi_image_authenticate(efi, efi_size)) {
>  		handle->auth_status = EFI_IMAGE_AUTH_FAILED;
> +		ret = EFI_SECURITY_VIOLATION;
> +		goto err;
> +	}
>  
>  	/* Calculate upper virtual address boundary */
>  	for (i = num_sections - 1; i >= 0; i--) {
> @@ -736,6 +737,15 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
>  		goto err;
>  	}
>  
> +	if (virt_size < sizeof(*dos) + sizeof(*nt) +
> +	    nt->FileHeader.SizeOfOptionalHeader +
> +	    num_sections * sizeof(IMAGE_SECTION_HEADER)) {
> +		efi_free_pages((uintptr_t) efi_reloc,
> +		       (virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT);
> +		ret = EFI_LOAD_ERROR;
> +		goto err;
> +	}
> +
>  	/* Copy PE headers */
>  	memcpy(efi_reloc, efi,
>  	       sizeof(*dos)
> @@ -746,6 +756,13 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
>  	/* Load sections into RAM */
>  	for (i = num_sections - 1; i >= 0; i--) {
>  		IMAGE_SECTION_HEADER *sec = &sections[i];
> +		if (sec->SizeOfRawData > sec->Misc.VirtualSize ||
> +		    sec->PointerToRawData + sec->SizeOfRawData > efi_size) {
> +			efi_free_pages((uintptr_t) efi_reloc,
> +			       (virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT);
> +			ret = EFI_LOAD_ERROR;
> +			goto err;
> +		}
>  		memset(efi_reloc + sec->VirtualAddress, 0,
>  		       sec->Misc.VirtualSize);
>  		memcpy(efi_reloc + sec->VirtualAddress,
> @@ -771,10 +788,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
>  	loaded_image_info->image_base = efi_reloc;
>  	loaded_image_info->image_size = virt_size;
>  
> -	if (handle->auth_status == EFI_IMAGE_AUTH_PASSED)
> -		return EFI_SUCCESS;
> -	else
> -		return EFI_SECURITY_VIOLATION;
> +	handle->auth_status = EFI_IMAGE_AUTH_PASSED;
> +	return EFI_SUCCESS;
>  
>  err:
>  	return ret;

      parent reply	other threads:[~2020-05-11  2:27 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-08 18:56 efi_loader: tighten PE verification code? Patrick Wildt
2020-05-10 20:36 ` Simon Glass
2020-05-10 21:00   ` Patrick Wildt
2020-05-11  2:27 ` AKASHI Takahiro [this message]

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=20200511022723.GB9483@laputa \
    --to=takahiro.akashi@linaro.org \
    --cc=u-boot@lists.denx.de \
    /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