Coverage Report

Created: 2026-06-15 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-efi-device-path-list.c
Line
Count
Source
1
/*
2
 * Copyright 2023 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#define G_LOG_DOMAIN "FuEfiDevicePath"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-common.h"
13
#include "fu-efi-device-path-list.h"
14
#include "fu-efi-file-path-device-path.h"
15
#include "fu-efi-hard-drive-device-path.h"
16
#include "fu-efi-struct.h"
17
#include "fu-input-stream.h"
18
19
struct _FuEfiDevicePathList {
20
  FuFirmware parent_instance;
21
};
22
23
static void
24
fu_efi_device_path_list_codec_iface_init(FwupdCodecInterface *iface);
25
26
4.98k
G_DEFINE_TYPE_EXTENDED(FuEfiDevicePathList,
27
4.98k
           fu_efi_device_path_list,
28
4.98k
           FU_TYPE_FIRMWARE,
29
4.98k
           0,
30
4.98k
           G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC,
31
4.98k
               fu_efi_device_path_list_codec_iface_init))
32
4.98k
33
4.98k
#define FU_EFI_DEVICE_PATH_LIST_IMAGES_MAX 1000u
34
35
static const gchar *
36
fu_efi_device_path_list_gtype_to_member_name(GType gtype)
37
0
{
38
0
  if (gtype == FU_TYPE_EFI_DEVICE_PATH)
39
0
    return "Dp";
40
0
  if (gtype == FU_TYPE_EFI_FILE_PATH_DEVICE_PATH)
41
0
    return "Fp";
42
0
  if (gtype == FU_TYPE_EFI_HARD_DRIVE_DEVICE_PATH)
43
0
    return "Hd";
44
0
  return g_type_name(gtype);
45
0
}
46
47
static void
48
fu_efi_device_path_list_add_json(FwupdCodec *codec,
49
         FwupdJsonObject *json_obj,
50
         FwupdCodecFlags flags)
51
0
{
52
0
  FuFirmware *firmware = FU_FIRMWARE(codec);
53
0
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
54
0
  g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new();
55
56
0
  for (guint i = 0; i < imgs->len; i++) {
57
0
    FuFirmware *img = g_ptr_array_index(imgs, i);
58
0
    g_autoptr(FwupdJsonObject) json_obj_tmp = fwupd_json_object_new();
59
0
    g_autoptr(FwupdJsonObject) json_object_tmp2 = fwupd_json_object_new();
60
0
    fwupd_codec_to_json(FWUPD_CODEC(img), json_object_tmp2, flags);
61
0
    fwupd_json_object_add_object(
62
0
        json_obj_tmp,
63
0
        fu_efi_device_path_list_gtype_to_member_name(G_OBJECT_TYPE(img)),
64
0
        json_object_tmp2);
65
0
    fwupd_json_array_add_object(json_arr, json_obj_tmp);
66
0
  }
67
0
  fwupd_json_object_add_array(json_obj, "DPs", json_arr);
68
0
}
69
70
static gboolean
71
fu_efi_device_path_list_parse(FuFirmware *firmware,
72
            GInputStream *stream,
73
            FuFirmwareParseFlags flags,
74
            GError **error)
75
1.76k
{
76
1.76k
  gsize offset = 0;
77
1.76k
  gsize streamsz = 0;
78
1.76k
  if (!fu_input_stream_size(stream, &streamsz, error))
79
0
    return FALSE;
80
23.8k
  while (offset < streamsz) {
81
23.4k
    g_autoptr(FuEfiDevicePath) efi_dp = NULL;
82
23.4k
    g_autoptr(FuStructEfiDevicePath) st_dp = NULL;
83
84
    /* parse the header so we can work out what GType to create */
85
23.4k
    st_dp = fu_struct_efi_device_path_parse_stream(stream, offset, error);
86
23.4k
    if (st_dp == NULL)
87
37
      return FALSE;
88
23.3k
    if (fu_struct_efi_device_path_get_type(st_dp) == FU_EFI_DEVICE_PATH_TYPE_END)
89
1.08k
      break;
90
22.2k
    if (fu_struct_efi_device_path_get_type(st_dp) == FU_EFI_DEVICE_PATH_TYPE_MEDIA &&
91
17.9k
        fu_struct_efi_device_path_get_subtype(st_dp) ==
92
17.9k
      FU_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE_FILE_PATH) {
93
16.6k
      efi_dp = FU_EFI_DEVICE_PATH(fu_efi_file_path_device_path_new());
94
16.6k
    } else if (fu_struct_efi_device_path_get_type(st_dp) ==
95
5.60k
             FU_EFI_DEVICE_PATH_TYPE_MEDIA &&
96
1.28k
         fu_struct_efi_device_path_get_subtype(st_dp) ==
97
1.28k
             FU_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE_HARD_DRIVE) {
98
659
      efi_dp = FU_EFI_DEVICE_PATH(fu_efi_hard_drive_device_path_new());
99
4.94k
    } else {
100
4.94k
      efi_dp = fu_efi_device_path_new();
101
4.94k
    }
102
22.2k
    fu_firmware_set_offset(FU_FIRMWARE(efi_dp), offset);
103
22.2k
    if (!fu_firmware_parse_stream(FU_FIRMWARE(efi_dp), stream, offset, flags, error))
104
234
      return FALSE;
105
22.0k
    if (fu_firmware_get_size(FU_FIRMWARE(efi_dp)) == 0) {
106
0
      g_set_error_literal(error,
107
0
              FWUPD_ERROR,
108
0
              FWUPD_ERROR_INVALID_DATA,
109
0
              "DP section had zero size");
110
0
      return FALSE;
111
0
    }
112
22.0k
    if (!fu_firmware_add_image(firmware, FU_FIRMWARE(efi_dp), error))
113
3
      return FALSE;
114
22.0k
    if (!fu_size_checked_inc(&offset, fu_firmware_get_size(FU_FIRMWARE(efi_dp)), error))
115
0
      return FALSE;
116
22.0k
  }
117
118
  /* success */
119
1.48k
  return TRUE;
120
1.76k
}
121
122
static GByteArray *
123
fu_efi_device_path_list_write(FuFirmware *firmware, GError **error)
124
979
{
125
979
  g_autoptr(GPtrArray) imgs = fu_firmware_get_images(firmware);
126
979
  g_autoptr(GByteArray) buf = g_byte_array_new();
127
979
  g_autoptr(FuStructEfiDevicePath) st_dp_end = NULL;
128
129
  /* add each image */
130
7.16k
  for (guint i = 0; i < imgs->len; i++) {
131
6.48k
    FuFirmware *img = g_ptr_array_index(imgs, i);
132
6.48k
    g_autoptr(GBytes) dp_blob = fu_firmware_write(img, error);
133
6.48k
    if (dp_blob == NULL)
134
298
      return NULL;
135
6.18k
    fu_byte_array_append_bytes(buf, dp_blob);
136
6.18k
  }
137
138
  /* add end marker */
139
681
  st_dp_end = fu_struct_efi_device_path_new();
140
681
  fu_struct_efi_device_path_set_type(st_dp_end, FU_EFI_DEVICE_PATH_TYPE_END);
141
681
  fu_struct_efi_device_path_set_subtype(st_dp_end, 0xFF);
142
681
  fu_byte_array_append_array(buf, st_dp_end->buf);
143
144
  /* success */
145
681
  return g_steal_pointer(&buf);
146
979
}
147
148
static void
149
fu_efi_device_path_list_codec_iface_init(FwupdCodecInterface *iface)
150
1
{
151
1
  iface->add_json = fu_efi_device_path_list_add_json;
152
1
}
153
154
static void
155
fu_efi_device_path_list_class_init(FuEfiDevicePathListClass *klass)
156
1
{
157
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
158
1
  firmware_class->parse = fu_efi_device_path_list_parse;
159
1
  firmware_class->write = fu_efi_device_path_list_write;
160
1
}
161
162
static void
163
fu_efi_device_path_list_init(FuEfiDevicePathList *self)
164
2.00k
{
165
2.00k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_DEVICE_PATH);
166
2.00k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_FILE_PATH_DEVICE_PATH);
167
2.00k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_HARD_DRIVE_DEVICE_PATH);
168
2.00k
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_EFI_DEVICE_PATH_LIST_IMAGES_MAX);
169
2.00k
  fu_firmware_set_size_max(FU_FIRMWARE(self), 1 * FU_MB);
170
2.00k
}
171
172
/**
173
 * fu_efi_device_path_list_new:
174
 *
175
 * Creates a new EFI DEVICE_PATH list.
176
 *
177
 * Returns: (transfer full): a #FuEfiDevicePathList
178
 *
179
 * Since: 1.9.3
180
 **/
181
FuEfiDevicePathList *
182
fu_efi_device_path_list_new(void)
183
2.00k
{
184
2.00k
  return g_object_new(FU_TYPE_EFI_DEVICE_PATH_LIST, NULL);
185
2.00k
}