]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
efi-api: validate boot option device path lengths 42926/head
authordongshengyuan <545258830@qq.com>
Thu, 9 Jul 2026 00:39:03 +0000 (08:39 +0800)
committerdongshengyuan <545258830@qq.com>
Thu, 9 Jul 2026 00:39:03 +0000 (08:39 +0800)
efi_get_boot_option() validates the overall Boot#### variable size and
the advertised device-path byte count, but then walks each device-path
node without first checking that the node header and subtype payload fit
in the remaining buffer.

A malformed Boot#### variable could make the parser read past the end of
the current node, or past the available device-path data.

Limit parsing to the bytes that are actually present, and stop walking
the device path when a malformed node is encountered. This keeps the
previous best-effort behaviour for fields parsed before the anomaly while
avoiding out-of-bounds reads.

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
src/shared/efi-api.c

index 56b055a0c8a94325cd6c5cc9c9cadfee6c7d1989..652c48e84bac4baa24af39c85092c52d3900081c 100644 (file)
@@ -283,19 +283,23 @@ int efi_get_boot_option(
 
         if (header->path_len > 0) {
                 uint8_t *dbuf;
-                size_t dnext, doff;
+                size_t dnext, doff, path_len;
 
                 doff = offsetof(struct boot_option, title) + title_size;
                 dbuf = buf + doff;
-                if (header->path_len > l - doff)
-                        return -EINVAL;
+                path_len = MIN((size_t) header->path_len, l - doff);
 
                 dnext = 0;
-                while (dnext < header->path_len) {
+                while (dnext < path_len) {
                         struct device_path *dpath;
+                        size_t remaining = path_len - dnext;
+
+                        if (remaining < offsetof(struct device_path, path))
+                                break;
 
                         dpath = (struct device_path *)(dbuf + dnext);
-                        if (dpath->length < 4)
+                        if (dpath->length < offsetof(struct device_path, path) ||
+                            dpath->length > remaining)
                                 break;
 
                         /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
@@ -310,6 +314,9 @@ int efi_get_boot_option(
 
                         /* Sub-Type 1 – Hard Drive */
                         if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
+                                if (dpath->length < offsetof(struct device_path, drive) + sizeof(struct drive_path))
+                                        break;
+
                                 /* 0x02 – GUID Partition Table */
                                 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
                                         continue;
@@ -325,9 +332,9 @@ int efi_get_boot_option(
 
                         /* Sub-Type 4 – File Path */
                         if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && ret_path) {
-                                p = utf16_to_utf8(dpath->path, dpath->length-4);
+                                p = utf16_to_utf8(dpath->path, dpath->length - offsetof(struct device_path, path));
                                 if (!p)
-                                        return  -ENOMEM;
+                                        return -ENOMEM;
 
                                 efi_tilt_backslashes(p);
                                 continue;