git: 1c85c5eea09a - main - loader.efi: Search boot device before foreign ZFS pools

From: Warner Losh <imp_at_FreeBSD.org>
Date: Tue, 09 Jun 2026 23:34:01 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=1c85c5eea09a4c9649b7634225220337e6005cd4

commit 1c85c5eea09a4c9649b7634225220337e6005cd4
Author:     Faraz Vahedi <kfv@kfv.io>
AuthorDate: 2026-05-26 14:35:42 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-06-09 23:33:05 +0000

    loader.efi: Search boot device before foreign ZFS pools
    
    When `boot_policy` is `RELAXED`, `find_currdev()` tried ZFS pools on every
    disk before searching the boot ESP and sibling partitions. Booting install
    media from USB could therefore select an installed ZFS root on internal
    storage instead of the intended memstick UFS image.
    
    Extract the boot-device partition walk into `try_boot_device_partitions()`
    and run it before relaxed foreign-pool probing. The ZFS search order is
    preserved; pools on the boot device are tried first, followed by pools on
    other devices when `boot_policy` is `RELAXED` and the boot device yields
    no bootable root.
    
    Signed-off-by: Faraz Vahedi <kfv@kfv.io>
    Reviewed by: imp
    Pull Request: https://github.com/freebsd/freebsd-src/pull/2239
---
 stand/efi/loader/main.c | 125 ++++++++++++++++++++++++++++--------------------
 1 file changed, 72 insertions(+), 53 deletions(-)

diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
index 2dc7924b9fcd..1444b1eee17d 100644
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -364,6 +364,49 @@ try_as_currdev(pdinfo_t *hd, pdinfo_t *pp)
 	return (sanity_check_currdev());
 }
 
+/*
+ * Search the boot device first (i.e. the ESP and any sibling partitions).
+ * Per the UEFI specification, filesystems on other devices must not be
+ * preferred until the boot device has been fully exhausted.
+ */
+static int
+try_boot_device_partitions(void)
+{
+	pdinfo_t *dp, *pp, *espdp;
+	CHAR16 *text;
+
+	dp = efiblk_get_pdinfo_by_handle(boot_img->DeviceHandle);
+	if (dp == NULL)
+		return (ENOENT);
+
+	text = efi_devpath_name(dp->pd_devpath);
+	if (text != NULL) {
+		printf("Trying ESP: %S\n", text);
+		efi_free_devpath_name(text);
+	}
+	set_currdev_pdinfo(dp);
+	if (sanity_check_currdev())
+		return (0);
+
+	if (dp->pd_parent == NULL)
+		return (ENOENT);
+
+	espdp = dp;
+	dp = dp->pd_parent;
+	STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+		if (espdp == pp)
+			continue;
+		text = efi_devpath_name(pp->pd_devpath);
+		if (text != NULL) {
+			printf("Trying: %S\n", text);
+			efi_free_devpath_name(text);
+		}
+		if (try_as_currdev(dp, pp))
+			return (0);
+	}
+	return (ENOENT);
+}
+
 /*
  * Sometimes we get filenames that are all upper case
  * and/or have backslashes in them. Filter all this out
@@ -535,10 +578,9 @@ match_boot_info(char *boot_info, size_t bisz)
 static int
 find_currdev(bool do_bootmgr, char *boot_info, size_t boot_info_sz)
 {
-	pdinfo_t *dp, *pp;
+	pdinfo_t *dp;
 	EFI_DEVICE_PATH *devpath, *copy;
 	EFI_HANDLE h;
-	CHAR16 *text;
 	struct devsw *dev;
 	int unit;
 	uint64_t extra;
@@ -606,65 +648,42 @@ find_currdev(bool do_bootmgr, char *boot_info, size_t boot_info_sz)
 		return (0);
 #endif /* MD_IMAGE_SIZE */
 
-#ifdef EFI_ZFS_BOOT
-	zfsinfo_list_t *zfsinfo = efizfs_get_zfsinfo_list();
-	zfsinfo_t *zi;
+	if (try_boot_device_partitions() == 0)
+		return (0);
 
-	/*
-	 * First try the zfs pool(s) that were on the boot device, then
-	 * try any other pool if we have a relaxed policy. zfsinfo has
-	 * the pools that had elements on the boot device first.
-	 */
-	STAILQ_FOREACH(zi, zfsinfo, zi_link) {
-		if (boot_policy == STRICT &&
-		    zi->zi_handle != boot_img->DeviceHandle)
-			continue;
-		printf("Trying ZFS pool 0x%jx\n", zi->zi_pool_guid);
-		if (probe_zfs_currdev(zi->zi_pool_guid))
-			return (0);
-	}
-#endif /* EFI_ZFS_BOOT */
+#ifdef EFI_ZFS_BOOT
+	{
+		zfsinfo_list_t *zfsinfo = efizfs_get_zfsinfo_list();
+		zfsinfo_t *zi;
 
-	/*
-	 * Try to find the block device by its handle based on the
-	 * image we're booting. If we can't find a sane partition,
-	 * search all the other partitions of the disk. We do not
-	 * search other disks because it's a violation of the UEFI
-	 * boot protocol to do so. We fail and let UEFI go on to
-	 * the next candidate.
-	 */
-	dp = efiblk_get_pdinfo_by_handle(boot_img->DeviceHandle);
-	if (dp != NULL) {
-		text = efi_devpath_name(dp->pd_devpath);
-		if (text != NULL) {
-			printf("Trying ESP: %S\n", text);
-			efi_free_devpath_name(text);
+		/*
+		 * Try ZFS pool(s) on the boot device not reachable via
+		 * the partition walk above.
+		 */
+		STAILQ_FOREACH(zi, zfsinfo, zi_link) {
+			if (zi->zi_handle != boot_img->DeviceHandle)
+				continue;
+			printf("Trying ZFS pool 0x%jx\n", zi->zi_pool_guid);
+			if (probe_zfs_currdev(zi->zi_pool_guid))
+				return (0);
 		}
-		set_currdev_pdinfo(dp);
-		if (sanity_check_currdev())
-			return (0);
-		if (dp->pd_parent != NULL) {
-			pdinfo_t *espdp = dp;
-			dp = dp->pd_parent;
-			STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
-				/* Already tried the ESP */
-				if (espdp == pp)
+
+		/*
+		 * With a relaxed policy, try pools on other devices only
+		 * after the boot device has no bootable root.
+		 */
+		if (boot_policy == RELAXED) {
+			STAILQ_FOREACH(zi, zfsinfo, zi_link) {
+				if (zi->zi_handle == boot_img->DeviceHandle)
 					continue;
-				/*
-				 * Roll up the ZFS special case
-				 * for those partitions that have
-				 * zpools on them.
-				 */
-				text = efi_devpath_name(pp->pd_devpath);
-				if (text != NULL) {
-					printf("Trying: %S\n", text);
-					efi_free_devpath_name(text);
-				}
-				if (try_as_currdev(dp, pp))
+				printf("Trying ZFS pool 0x%jx\n",
+				    zi->zi_pool_guid);
+				if (probe_zfs_currdev(zi->zi_pool_guid))
 					return (0);
 			}
 		}
 	}
+#endif /* EFI_ZFS_BOOT */
 
 	/*
 	 * Try the device handle from our loaded image first.  If that