svn commit: r279929 - head/sys/boot/amd64/efi

John Baldwin jhb at FreeBSD.org
Thu Mar 12 17:07:25 UTC 2015


Author: jhb
Date: Thu Mar 12 17:07:24 2015
New Revision: 279929
URL: https://svnweb.freebsd.org/changeset/base/279929

Log:
  Allow the EFI loader to work with large kernels and/or modules
  (for example, a large mfsroot).  Note that for EFI the kernel and
  modules (as well as other metadata files such as splash screens or
  memory disk images) are loaded into a statically-sized staging area.
  When the EFI loader exits it copies this staging area down to the
  location the kernel expects to run at.
  - Add bounds checking to the copy routines to fail attempts to access
    memory outside of the staging area.  Previously loading a combined
    kernel + modules larger than the staging size (32MB) would overflow
    the staging area trashing whatever memory was afterwards.  Under
    Intel's OVMF firmware for qemu this resulted in fatal faults in the
    firmware itself.  Now the attempt will fail with ENOMEM.
  - Allow the staging area size to be configured at compile time via
    an EFI_STAGING_SIZE variable in src.conf or on the command line.
    It accepts the size of the staging area in MB.  The default size
    remains 32MB.
  
  MFC after:	2 weeks
  Sponsored by:	Cisco Systems, Inc.

Modified:
  head/sys/boot/amd64/efi/Makefile
  head/sys/boot/amd64/efi/copy.c

Modified: head/sys/boot/amd64/efi/Makefile
==============================================================================
--- head/sys/boot/amd64/efi/Makefile	Thu Mar 12 17:01:30 2015	(r279928)
+++ head/sys/boot/amd64/efi/Makefile	Thu Mar 12 17:07:24 2015	(r279929)
@@ -44,6 +44,10 @@ LIBFICL=	${.OBJDIR}/../../ficl/libficl.a
 # Include bcache code.
 HAVE_BCACHE=    yes
 
+.if defined(EFI_STAGING_SIZE)
+CFLAGS+=	-DEFI_STAGING_SIZE=${EFI_STAGING_SIZE}
+.endif
+
 # Always add MI sources 
 .PATH:		${.CURDIR}/../../common
 .include	"${.CURDIR}/../../common/Makefile.inc"

Modified: head/sys/boot/amd64/efi/copy.c
==============================================================================
--- head/sys/boot/amd64/efi/copy.c	Thu Mar 12 17:01:30 2015	(r279928)
+++ head/sys/boot/amd64/efi/copy.c	Thu Mar 12 17:07:24 2015	(r279929)
@@ -37,9 +37,13 @@ __FBSDID("$FreeBSD$");
 #include <efi.h>
 #include <efilib.h>
 
-#define	STAGE_PAGES	8192	/* 32MB */
+#ifndef EFI_STAGING_SIZE
+#define	EFI_STAGING_SIZE	32
+#endif
 
-EFI_PHYSICAL_ADDRESS	staging;
+#define	STAGE_PAGES	((EFI_STAGING_SIZE) * 1024 * 1024 / 4096)
+
+EFI_PHYSICAL_ADDRESS	staging, staging_end;
 int			stage_offset_set = 0;
 ssize_t			stage_offset;
 
@@ -55,6 +59,7 @@ x86_efi_copy_init(void)
 		    (unsigned long)(status & EFI_ERROR_MASK));
 		return (status);
 	}
+	staging_end = staging + STAGE_PAGES * 4096;
 
 	return (0);
 }
@@ -68,6 +73,11 @@ x86_efi_copyin(const void *src, vm_offse
 		stage_offset_set = 1;
 	}
 
+	/* XXX: Callers do not check for failure. */
+	if (dest + stage_offset + len > staging_end) {
+		errno = ENOMEM;
+		return (-1);
+	}
 	bcopy(src, (void *)(dest + stage_offset), len);
 	return (len);
 }
@@ -76,6 +86,11 @@ ssize_t
 x86_efi_copyout(const vm_offset_t src, void *dest, const size_t len)
 {
 
+	/* XXX: Callers do not check for failure. */
+	if (src + stage_offset + len > staging_end) {
+		errno = ENOMEM;
+		return (-1);
+	}
 	bcopy((void *)(src + stage_offset), dest, len);
 	return (len);
 }
@@ -85,6 +100,10 @@ ssize_t
 x86_efi_readin(const int fd, vm_offset_t dest, const size_t len)
 {
 
+	if (dest + stage_offset + len > staging_end) {
+		errno = ENOMEM;
+		return (-1);
+	}
 	return (read(fd, (void *)(dest + stage_offset), len));
 }
 


More information about the svn-src-all mailing list