mirror of
				https://git.proxmox.com/git/fwupd
				synced 2025-11-04 08:59:20 +00:00 
			
		
		
		
	The end year is legally and functionally redundant, and more importantly causes cherry-pick conflicts when trying to maintain old branches. Use git for history.
		
			
				
	
	
		
			129 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: LGPL-2.1+
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
#include <efivar.h>
 | 
						|
 | 
						|
#include "fu-common.h"
 | 
						|
#include "fu-uefi-devpath.h"
 | 
						|
 | 
						|
#include "fwupd-error.h"
 | 
						|
 | 
						|
typedef struct {
 | 
						|
	guint8	 type;
 | 
						|
	guint8	 subtype;
 | 
						|
	GBytes	*data;
 | 
						|
} FuUefiDevPath;
 | 
						|
 | 
						|
static void
 | 
						|
fu_uefi_efi_dp_free (FuUefiDevPath *dp)
 | 
						|
{
 | 
						|
	if (dp->data != NULL)
 | 
						|
		g_bytes_unref (dp->data);
 | 
						|
	g_free (dp);
 | 
						|
}
 | 
						|
 | 
						|
GBytes *
 | 
						|
fu_uefi_devpath_find_data (GPtrArray *dps, guint8 type, guint8 subtype, GError **error)
 | 
						|
{
 | 
						|
	for (guint i = 0; i < dps->len; i++) {
 | 
						|
		FuUefiDevPath *dp = g_ptr_array_index (dps, i);
 | 
						|
		if (dp->type == type && dp->subtype == subtype)
 | 
						|
			return dp->data;
 | 
						|
	}
 | 
						|
	g_set_error (error,
 | 
						|
		     FWUPD_ERROR,
 | 
						|
		     FWUPD_ERROR_INTERNAL,
 | 
						|
		     "no DP with type 0x%02x and subtype 0x%02x",
 | 
						|
		     type, subtype);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
GPtrArray *
 | 
						|
fu_uefi_devpath_parse (const guint8 *buf, gsize sz,
 | 
						|
		       FuUefiDevpathParseFlags flags, GError **error)
 | 
						|
{
 | 
						|
	guint16 offset = 0;
 | 
						|
	g_autoptr(GPtrArray) dps = NULL;
 | 
						|
 | 
						|
	/* sanity check */
 | 
						|
	if (sz < sizeof(efidp_header)) {
 | 
						|
		g_set_error_literal (error,
 | 
						|
				     FWUPD_ERROR,
 | 
						|
				     FWUPD_ERROR_INTERNAL,
 | 
						|
				     "const_efidp is corrupt");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	dps = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_uefi_efi_dp_free);
 | 
						|
	while (1) {
 | 
						|
		FuUefiDevPath *dp;
 | 
						|
		const efidp_header *hdr = (efidp_header *) (buf + offset);
 | 
						|
		guint16 hdr_length = GUINT16_FROM_LE(hdr->length);
 | 
						|
 | 
						|
		/* check if last entry */
 | 
						|
		g_debug ("DP type:0x%02x subtype:0x%02x size:0x%04x",
 | 
						|
			 hdr->type, hdr->subtype, hdr->length);
 | 
						|
		if (hdr->type == EFIDP_END_TYPE && hdr->subtype == EFIDP_END_ENTIRE)
 | 
						|
			break;
 | 
						|
 | 
						|
		/* work around a bug in efi_va_generate_file_device_path_from_esp */
 | 
						|
		if (offset + sizeof(efidp_header) + hdr->length > sz) {
 | 
						|
			hdr_length = 0;
 | 
						|
			fu_common_dump_full (G_LOG_DOMAIN, "efidp",
 | 
						|
					     buf + offset, sz - offset, 32,
 | 
						|
					     FU_DUMP_FLAGS_SHOW_ADDRESSES);
 | 
						|
			for (guint16 i = offset + 4; i <= sz - 4; i++) {
 | 
						|
				if (memcmp (buf + i, "\x7f\xff\x04\x00", 4) == 0) {
 | 
						|
					hdr_length = i - offset;
 | 
						|
					g_debug ("found END_ENTIRE at 0x%04x",
 | 
						|
						 (guint) (i - offset));
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			if (hdr_length == 0) {
 | 
						|
				g_set_error_literal (error,
 | 
						|
						     FWUPD_ERROR,
 | 
						|
						     FWUPD_ERROR_INTERNAL,
 | 
						|
						     "DP length invalid and no END_ENTIRE "
 | 
						|
						     "found, possibly data truncation?");
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
			if ((flags & FU_UEFI_DEVPATH_PARSE_FLAG_REPAIR) == 0) {
 | 
						|
				g_set_error (error,
 | 
						|
					     FWUPD_ERROR,
 | 
						|
					     FWUPD_ERROR_INTERNAL,
 | 
						|
					     "DP length invalid, reported 0x%04x, maybe 0x%04x",
 | 
						|
					     hdr->length, hdr_length);
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
			g_debug ("DP length invalid! Truncating from 0x%04x to 0x%04x",
 | 
						|
				 hdr->length, hdr_length);
 | 
						|
		}
 | 
						|
 | 
						|
		/* add new DP */
 | 
						|
		dp = g_new0 (FuUefiDevPath, 1);
 | 
						|
		dp->type = hdr->type;
 | 
						|
		dp->subtype = hdr->subtype;
 | 
						|
		if (hdr_length > 0)
 | 
						|
			dp->data = g_bytes_new (buf + offset + 4, hdr_length);
 | 
						|
		g_ptr_array_add (dps, dp);
 | 
						|
 | 
						|
		/* advance to next DP */
 | 
						|
		offset += hdr_length;
 | 
						|
		if (offset + sizeof(efidp_header) > sz) {
 | 
						|
			g_set_error_literal (error,
 | 
						|
					     FWUPD_ERROR,
 | 
						|
					     FWUPD_ERROR_INTERNAL,
 | 
						|
					     "DP length invalid after fixing");
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
 | 
						|
	}
 | 
						|
	return g_steal_pointer (&dps);
 | 
						|
}
 |