/src/fwupd/libfwupdplugin/fu-efi-section.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2020 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | 9.61k | #define G_LOG_DOMAIN "FuEfiSection" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include "fu-byte-array.h" |
12 | | #include "fu-common.h" |
13 | | #include "fu-efi-common.h" |
14 | | #include "fu-efi-lz77-decompressor.h" |
15 | | #include "fu-efi-section.h" |
16 | | #include "fu-efi-struct.h" |
17 | | #include "fu-efi-volume.h" |
18 | | #include "fu-input-stream.h" |
19 | | #include "fu-lzma-common.h" |
20 | | #include "fu-memory-input-stream.h" |
21 | | #include "fu-partial-input-stream.h" |
22 | | #include "fu-string.h" |
23 | | |
24 | | /** |
25 | | * FuEfiSection: |
26 | | * |
27 | | * A UEFI firmware section. |
28 | | * |
29 | | * See also: [class@FuFirmware] |
30 | | */ |
31 | | |
32 | | typedef struct { |
33 | | guint8 type; |
34 | | gchar *user_interface; |
35 | | } FuEfiSectionPrivate; |
36 | | |
37 | 186k | G_DEFINE_TYPE_WITH_PRIVATE(FuEfiSection, fu_efi_section, FU_TYPE_FIRMWARE) |
38 | 187k | #define GET_PRIVATE(o) (fu_efi_section_get_instance_private(o)) |
39 | | |
40 | | static void |
41 | | fu_efi_section_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn) |
42 | 0 | { |
43 | 0 | FuEfiSection *self = FU_EFI_SECTION(firmware); |
44 | 0 | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
45 | |
|
46 | 0 | fu_xmlb_builder_insert_kx(bn, "type", priv->type); |
47 | 0 | if (priv->user_interface != NULL) |
48 | 0 | fu_xmlb_builder_insert_kv(bn, "user_interface", priv->user_interface); |
49 | 0 | if (flags & FU_FIRMWARE_EXPORT_FLAG_INCLUDE_DEBUG) { |
50 | 0 | fu_xmlb_builder_insert_kv(bn, |
51 | 0 | "name", |
52 | 0 | fu_efi_guid_to_name(fu_firmware_get_id(firmware))); |
53 | 0 | fu_xmlb_builder_insert_kv(bn, |
54 | 0 | "type_name", |
55 | 0 | fu_efi_section_type_to_string(priv->type)); |
56 | 0 | } |
57 | 0 | } |
58 | | |
59 | | static gboolean |
60 | | fu_efi_section_parse_volume_image(FuEfiSection *self, |
61 | | FuInputStream *stream, |
62 | | FuFirmwareParseFlags flags, |
63 | | GError **error) |
64 | 1.78k | { |
65 | 1.78k | g_autoptr(FuFirmware) img = fu_efi_volume_new(); |
66 | 1.78k | if (!fu_firmware_parse_stream(img, |
67 | 1.78k | stream, |
68 | 1.78k | 0x0, |
69 | 1.78k | flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH, |
70 | 1.78k | error)) { |
71 | 1.41k | return FALSE; |
72 | 1.41k | } |
73 | 379 | return fu_firmware_add_image(FU_FIRMWARE(self), img, error); |
74 | 1.78k | } |
75 | | |
76 | | static gboolean |
77 | | fu_efi_section_parse_lzma_sections(FuEfiSection *self, |
78 | | FuInputStream *stream, |
79 | | FuFirmwareParseFlags flags, |
80 | | GError **error) |
81 | 0 | { |
82 | 0 | g_autoptr(GBytes) blob = NULL; |
83 | 0 | g_autoptr(GBytes) blob_uncomp = NULL; |
84 | 0 | g_autoptr(FuInputStream) stream_uncomp = NULL; |
85 | | |
86 | | /* parse all sections */ |
87 | 0 | blob = fu_input_stream_read_bytes(stream, 0, G_MAXSIZE, NULL, error); |
88 | 0 | if (blob == NULL) |
89 | 0 | return FALSE; |
90 | 0 | blob_uncomp = fu_lzma_decompress_bytes(blob, 128 * FU_MB, error); |
91 | 0 | if (blob_uncomp == NULL) { |
92 | 0 | g_prefix_error_literal(error, "failed to decompress: "); |
93 | 0 | return FALSE; |
94 | 0 | } |
95 | 0 | stream_uncomp = fu_memory_input_stream_new_from_bytes(blob_uncomp); |
96 | 0 | if (!fu_efi_parse_sections(FU_FIRMWARE(self), stream_uncomp, 0, flags, error)) { |
97 | 0 | g_prefix_error_literal(error, "failed to parse sections: "); |
98 | 0 | return FALSE; |
99 | 0 | } |
100 | 0 | return TRUE; |
101 | 0 | } |
102 | | |
103 | | static gboolean |
104 | | fu_efi_section_parse_user_interface(FuEfiSection *self, |
105 | | FuInputStream *stream, |
106 | | FuFirmwareParseFlags flags, |
107 | | GError **error) |
108 | 790 | { |
109 | 790 | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
110 | 790 | g_autoptr(GByteArray) buf = NULL; |
111 | | |
112 | 790 | if (priv->user_interface != NULL) { |
113 | 0 | g_set_error(error, |
114 | 0 | FWUPD_ERROR, |
115 | 0 | FWUPD_ERROR_INTERNAL, |
116 | 0 | "UI already set as %s for section", |
117 | 0 | priv->user_interface); |
118 | 0 | return FALSE; |
119 | 0 | } |
120 | 790 | buf = fu_input_stream_read_byte_array(stream, 0x0, G_MAXSIZE, NULL, error); |
121 | 790 | if (buf == NULL) |
122 | 7 | return FALSE; |
123 | 783 | priv->user_interface = fu_utf16_to_utf8_byte_array(buf, G_LITTLE_ENDIAN, error); |
124 | 783 | if (priv->user_interface == NULL) |
125 | 76 | return FALSE; |
126 | 707 | return TRUE; |
127 | 783 | } |
128 | | |
129 | | static gboolean |
130 | | fu_efi_section_parse_version(FuEfiSection *self, |
131 | | FuInputStream *stream, |
132 | | FuFirmwareParseFlags flags, |
133 | | GError **error) |
134 | 1.58k | { |
135 | 1.58k | guint16 version_raw = 0; |
136 | 1.58k | g_autofree gchar *version = NULL; |
137 | 1.58k | g_autoptr(GByteArray) buf = NULL; |
138 | | |
139 | 1.58k | if (!fu_input_stream_read_u16(stream, 0x0, &version_raw, G_LITTLE_ENDIAN, error)) { |
140 | 8 | g_prefix_error_literal(error, "failed to read raw version: "); |
141 | 8 | return FALSE; |
142 | 8 | } |
143 | 1.57k | fu_firmware_set_version_raw(FU_FIRMWARE(self), version_raw); |
144 | 1.57k | buf = fu_input_stream_read_byte_array(stream, sizeof(guint16), G_MAXSIZE, NULL, error); |
145 | 1.57k | if (buf == NULL) { |
146 | 4 | g_prefix_error_literal(error, "failed to read version buffer: "); |
147 | 4 | return FALSE; |
148 | 4 | } |
149 | 1.57k | version = fu_utf16_to_utf8_byte_array(buf, G_LITTLE_ENDIAN, error); |
150 | 1.57k | if (version == NULL) { |
151 | 43 | g_prefix_error_literal(error, "failed to convert to UTF-16: "); |
152 | 43 | return FALSE; |
153 | 43 | } |
154 | 1.52k | fu_firmware_set_version(FU_FIRMWARE(self), version); /* nocheck:set-version */ |
155 | 1.52k | return TRUE; |
156 | 1.57k | } |
157 | | |
158 | | static gboolean |
159 | | fu_efi_section_parse_compression_sections(FuEfiSection *self, |
160 | | FuInputStream *stream, |
161 | | FuFirmwareParseFlags flags, |
162 | | GError **error) |
163 | 3.62k | { |
164 | 3.62k | g_autoptr(FuStructEfiSectionCompression) st = NULL; |
165 | 3.62k | st = fu_struct_efi_section_compression_parse_stream(stream, 0x0, error); |
166 | 3.62k | if (st == NULL) |
167 | 24 | return FALSE; |
168 | 3.60k | if (fu_struct_efi_section_compression_get_compression_type(st) == |
169 | 3.60k | FU_EFI_COMPRESSION_TYPE_NOT_COMPRESSED) { |
170 | 717 | if (!fu_efi_parse_sections(FU_FIRMWARE(self), stream, st->buf->len, flags, error)) { |
171 | 64 | g_prefix_error_literal(error, "failed to parse sections: "); |
172 | 64 | return FALSE; |
173 | 64 | } |
174 | 2.88k | } else { |
175 | 2.88k | g_autoptr(FuFirmware) lz77_decompressor = fu_efi_lz77_decompressor_new(); |
176 | 2.88k | g_autoptr(FuInputStream) lz77_stream = NULL; |
177 | 2.88k | if (!fu_firmware_parse_stream(lz77_decompressor, |
178 | 2.88k | stream, |
179 | 2.88k | st->buf->len, |
180 | 2.88k | flags, |
181 | 2.88k | error)) |
182 | 1.48k | return FALSE; |
183 | 1.40k | lz77_stream = fu_firmware_get_stream(lz77_decompressor, error); |
184 | 1.40k | if (lz77_stream == NULL) |
185 | 0 | return FALSE; |
186 | 1.40k | if (!fu_efi_parse_sections(FU_FIRMWARE(self), lz77_stream, 0, flags, error)) { |
187 | 463 | g_prefix_error_literal(error, "failed to parse sections: "); |
188 | 463 | return FALSE; |
189 | 463 | } |
190 | 1.40k | } |
191 | 1.59k | return TRUE; |
192 | 3.60k | } |
193 | | |
194 | | static const gchar * |
195 | | fu_efi_section_freeform_subtype_guid_to_string(const gchar *guid) |
196 | 514 | { |
197 | 514 | struct { |
198 | 514 | const gchar *guid; |
199 | 514 | const gchar *str; |
200 | 514 | } freeform_guids[] = { |
201 | 514 | {"00781ca1-5de3-405f-abb8-379c3c076984", "AmiRomLayoutGuid"}, |
202 | 514 | {"20feebde-e739-420e-ae31-77e2876508c0", "IntelRstOprom"}, |
203 | 514 | {"224d6eb4-307f-45ba-9dc3-fe9fc6b38148", "IntelEntRaidController"}, |
204 | 514 | {"2ebe0275-6458-4af9-91ed-d3f4edb100aa", "SignOn"}, |
205 | 514 | {"380b6b4f-1454-41f2-a6d3-61d1333e8cb4", "IntelGop"}, |
206 | 514 | {"50339d20-c90a-4bb2-9aff-d8a11b23bc15", "I219?Oprom"}, |
207 | 514 | {"88a15a4f-977d-4682-b17c-da1f316c1f32", "RomLayout"}, |
208 | 514 | {"9bec7109-6d7a-413a-8e4b-019ced0503e1", "AmiBoardInfoSectionGuid"}, |
209 | 514 | {"ab56dc60-0057-11da-a8db-000102eee626", "?BuildData"}, |
210 | 514 | {"c5a4306e-e247-4ecd-a9d8-5b1985d3dcda", "?Oprom"}, |
211 | 514 | {"c9352cc3-a354-44e5-8776-b2ed8dd781ec", "IntelEntRaidController"}, |
212 | 514 | {"d46346ca-82a1-4cde-9546-77c86f893888", "?Oprom"}, |
213 | 514 | {"e095affe-d4cd-4289-9b48-28f64e3d781d", "IntelRstOprom"}, |
214 | 514 | {"fe612b72-203c-47b1-8560-a66d946eb371", "setupdata"}, |
215 | 514 | {NULL, NULL}, |
216 | 514 | }; |
217 | 7.71k | for (guint i = 0; freeform_guids[i].guid != NULL; i++) { |
218 | 7.19k | if (g_strcmp0(guid, freeform_guids[i].guid) == 0) |
219 | 0 | return freeform_guids[i].str; |
220 | 7.19k | } |
221 | 514 | return NULL; |
222 | 514 | } |
223 | | |
224 | | static gboolean |
225 | | fu_efi_section_parse_freeform_subtype_guid(FuEfiSection *self, |
226 | | FuInputStream *stream, |
227 | | FuFirmwareParseFlags flags, |
228 | | GError **error) |
229 | 527 | { |
230 | 527 | const gchar *guid_ui; |
231 | 527 | g_autofree gchar *guid_str = NULL; |
232 | 527 | g_autoptr(FuStructEfiSectionFreeformSubtypeGuid) st = NULL; |
233 | | |
234 | 527 | st = fu_struct_efi_section_freeform_subtype_guid_parse_stream(stream, 0x0, error); |
235 | 527 | if (st == NULL) |
236 | 13 | return FALSE; |
237 | | |
238 | | /* no idea */ |
239 | 514 | guid_str = fwupd_guid_to_string(fu_struct_efi_section_freeform_subtype_guid_get_guid(st), |
240 | 514 | FWUPD_GUID_FLAG_MIXED_ENDIAN); |
241 | 514 | guid_ui = fu_efi_section_freeform_subtype_guid_to_string(guid_str); |
242 | 514 | if (guid_ui != NULL) { |
243 | 0 | g_debug("ignoring FREEFORM_SUBTYPE_GUID %s [%s]", guid_str, guid_ui); |
244 | 0 | return TRUE; |
245 | 0 | } |
246 | 514 | g_debug("unknown FREEFORM_SUBTYPE_GUID %s", guid_str); |
247 | 514 | return TRUE; |
248 | 514 | } |
249 | | |
250 | | static gboolean |
251 | | fu_efi_section_parse(FuFirmware *firmware, |
252 | | FuInputStream *stream, |
253 | | FuFirmwareParseFlags flags, |
254 | | GError **error) |
255 | 59.1k | { |
256 | 59.1k | FuEfiSection *self = FU_EFI_SECTION(firmware); |
257 | 59.1k | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
258 | 59.1k | gsize offset = 0; |
259 | 59.1k | gsize streamsz = 0; |
260 | 59.1k | gsize stlen = 0; |
261 | 59.1k | guint32 size; |
262 | 59.1k | g_autoptr(FuStructEfiSection) st = NULL; |
263 | 59.1k | g_autoptr(FuInputStream) partial_stream = NULL; |
264 | | |
265 | | /* parse */ |
266 | 59.1k | st = fu_struct_efi_section_parse_stream(stream, offset, error); |
267 | 59.1k | if (st == NULL) |
268 | 95 | return FALSE; |
269 | | |
270 | | /* use extended size */ |
271 | 59.0k | if (fu_struct_efi_section_get_size(st) == 0xFFFFFF) { |
272 | 117 | g_autoptr(FuStructEfiSection2) st2 = NULL; |
273 | 117 | st2 = fu_struct_efi_section2_parse_stream(stream, offset, error); |
274 | 117 | if (st2 == NULL) |
275 | 19 | return FALSE; |
276 | 98 | priv->type = fu_struct_efi_section2_get_type(st2); |
277 | 98 | size = fu_struct_efi_section2_get_extended_size(st2); |
278 | 98 | stlen = st2->buf->len; |
279 | 58.9k | } else { |
280 | 58.9k | priv->type = fu_struct_efi_section_get_type(st); |
281 | 58.9k | size = fu_struct_efi_section_get_size(st); |
282 | 58.9k | stlen = st->buf->len; |
283 | 58.9k | } |
284 | 59.0k | if (size < stlen) { |
285 | 304 | g_set_error(error, |
286 | 304 | FWUPD_ERROR, |
287 | 304 | FWUPD_ERROR_INTERNAL, |
288 | 304 | "invalid section size, got 0x%x", |
289 | 304 | (guint)size); |
290 | 304 | return FALSE; |
291 | 304 | } |
292 | | |
293 | | /* sanity check */ |
294 | 58.7k | if (!fu_input_stream_size(stream, &streamsz, error)) |
295 | 0 | return FALSE; |
296 | 58.7k | if (size > streamsz) { |
297 | 489 | g_set_error(error, |
298 | 489 | FWUPD_ERROR, |
299 | 489 | FWUPD_ERROR_INTERNAL, |
300 | 489 | "invalid section size, got 0x%x from stream of size 0x%x", |
301 | 489 | (guint)size, |
302 | 489 | (guint)streamsz); |
303 | 489 | return FALSE; |
304 | 489 | } |
305 | | |
306 | | /* name */ |
307 | 58.2k | if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED) { |
308 | 3.87k | gsize offset_delta; |
309 | 3.87k | g_autofree gchar *guid_str = NULL; |
310 | 3.87k | g_autoptr(FuStructEfiSectionGuidDefined) st_def = NULL; |
311 | 3.87k | st_def = fu_struct_efi_section_guid_defined_parse_stream(stream, stlen, error); |
312 | 3.87k | if (st_def == NULL) |
313 | 14 | return FALSE; |
314 | 3.85k | guid_str = fwupd_guid_to_string(fu_struct_efi_section_guid_defined_get_name(st_def), |
315 | 3.85k | FWUPD_GUID_FLAG_MIXED_ENDIAN); |
316 | 3.85k | fu_firmware_set_id(firmware, guid_str); |
317 | 3.85k | if (fu_struct_efi_section_guid_defined_get_offset(st_def) < st_def->buf->len) { |
318 | 23 | g_set_error(error, |
319 | 23 | FWUPD_ERROR, |
320 | 23 | FWUPD_ERROR_INTERNAL, |
321 | 23 | "invalid section size, got 0x%x", |
322 | 23 | (guint)fu_struct_efi_section_guid_defined_get_offset(st_def)); |
323 | 23 | return FALSE; |
324 | 23 | } |
325 | 3.83k | if (fu_struct_efi_section_guid_defined_get_offset(st_def) > size) { |
326 | 76 | g_set_error(error, |
327 | 76 | FWUPD_ERROR, |
328 | 76 | FWUPD_ERROR_INTERNAL, |
329 | 76 | "invalid section offset 0x%x, greater than size 0x%x", |
330 | 76 | (guint)fu_struct_efi_section_guid_defined_get_offset(st_def), |
331 | 76 | (guint)size); |
332 | 76 | return FALSE; |
333 | 76 | } |
334 | 3.75k | offset_delta = fu_struct_efi_section_guid_defined_get_offset(st_def) - stlen; |
335 | 3.75k | if (!fu_size_checked_inc(&offset, offset_delta, error)) { |
336 | 0 | g_prefix_error_literal(error, "section offset overflow: "); |
337 | 0 | return FALSE; |
338 | 0 | } |
339 | 3.75k | } |
340 | | |
341 | | /* create blob */ |
342 | 58.1k | if (!fu_size_checked_inc(&offset, stlen, error)) { |
343 | 0 | g_prefix_error_literal(error, "section offset overflow: "); |
344 | 0 | return FALSE; |
345 | 0 | } |
346 | 58.1k | partial_stream = fu_partial_input_stream_new(stream, offset, size - offset, error); |
347 | 58.1k | if (partial_stream == NULL) { |
348 | 0 | g_prefix_error_literal(error, "failed to cut data: "); |
349 | 0 | return FALSE; |
350 | 0 | } |
351 | 58.1k | fu_firmware_set_offset(firmware, offset); |
352 | 58.1k | fu_firmware_set_size(firmware, size); |
353 | 58.1k | if (!fu_firmware_set_stream(firmware, partial_stream, error)) |
354 | 0 | return FALSE; |
355 | | |
356 | | /* nested volume */ |
357 | 58.1k | if (priv->type == FU_EFI_SECTION_TYPE_VOLUME_IMAGE) { |
358 | 1.78k | if (!fu_efi_section_parse_volume_image(self, partial_stream, flags, error)) { |
359 | 1.41k | g_prefix_error_literal(error, "failed to parse nested volume: "); |
360 | 1.41k | return FALSE; |
361 | 1.41k | } |
362 | 56.3k | } else if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED && |
363 | 3.75k | g_strcmp0(fu_firmware_get_id(firmware), FU_EFI_SECTION_GUID_LZMA_COMPRESS) == |
364 | 3.75k | 0) { |
365 | 0 | if (!fu_efi_section_parse_lzma_sections(self, partial_stream, flags, error)) { |
366 | 0 | g_prefix_error_literal(error, "failed to parse lzma section: "); |
367 | 0 | return FALSE; |
368 | 0 | } |
369 | 56.3k | } else if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED && |
370 | 3.75k | g_strcmp0(fu_firmware_get_id(firmware), |
371 | 3.75k | "ced4eac6-49f3-4c12-a597-fc8c33447691") == 0) { |
372 | 34 | g_debug("ignoring %s [0x%x] EFI section as self test", |
373 | 34 | fu_efi_section_type_to_string(priv->type), |
374 | 34 | priv->type); |
375 | 56.2k | } else if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED) { |
376 | | #ifndef HAVE_FUZZER |
377 | | g_warning("no idea how to decompress encapsulation section of type %s", |
378 | | fu_firmware_get_id(firmware)); |
379 | | #endif |
380 | 52.5k | } else if (priv->type == FU_EFI_SECTION_TYPE_USER_INTERFACE) { |
381 | 790 | if (!fu_efi_section_parse_user_interface(self, partial_stream, flags, error)) { |
382 | 83 | g_prefix_error_literal(error, "failed to parse user interface: "); |
383 | 83 | return FALSE; |
384 | 83 | } |
385 | 51.7k | } else if (priv->type == FU_EFI_SECTION_TYPE_VERSION) { |
386 | 1.58k | if (!fu_efi_section_parse_version(self, partial_stream, flags, error)) { |
387 | 55 | g_prefix_error_literal(error, "failed to parse version: "); |
388 | 55 | return FALSE; |
389 | 55 | } |
390 | 50.1k | } else if (priv->type == FU_EFI_SECTION_TYPE_COMPRESSION) { |
391 | 3.62k | if (!fu_efi_section_parse_compression_sections(self, |
392 | 3.62k | partial_stream, |
393 | 3.62k | flags, |
394 | 3.62k | error)) { |
395 | 2.03k | g_prefix_error_literal(error, "failed to parse compression: "); |
396 | 2.03k | return FALSE; |
397 | 2.03k | } |
398 | 46.5k | } else if (priv->type == FU_EFI_SECTION_TYPE_FREEFORM_SUBTYPE_GUID) { |
399 | 527 | if (!fu_efi_section_parse_freeform_subtype_guid(self, |
400 | 527 | partial_stream, |
401 | 527 | flags, |
402 | 527 | error)) { |
403 | 13 | g_prefix_error_literal(error, "failed to parse compression: "); |
404 | 13 | return FALSE; |
405 | 13 | } |
406 | 46.0k | } else if (priv->type == FU_EFI_SECTION_TYPE_PEI_DEPEX || |
407 | 44.9k | priv->type == FU_EFI_SECTION_TYPE_DXE_DEPEX || |
408 | 44.3k | priv->type == FU_EFI_SECTION_TYPE_MM_DEPEX || |
409 | 43.3k | priv->type == FU_EFI_SECTION_TYPE_PE32 || priv->type == FU_EFI_SECTION_TYPE_TE || |
410 | 41.7k | priv->type == FU_EFI_SECTION_TYPE_RAW) { |
411 | 9.07k | g_debug("ignoring %s [0x%x] EFI section", |
412 | 9.07k | fu_efi_section_type_to_string(priv->type), |
413 | 9.07k | priv->type); |
414 | 36.9k | } else { |
415 | | #ifndef HAVE_FUZZER |
416 | | g_warning("no idea how to parse %s [0x%x] EFI section", |
417 | | fu_efi_section_type_to_string(priv->type), |
418 | | priv->type); |
419 | | #endif |
420 | 36.9k | } |
421 | | |
422 | | /* success */ |
423 | 54.5k | return TRUE; |
424 | 58.1k | } |
425 | | |
426 | | static GByteArray * |
427 | | fu_efi_section_write(FuFirmware *firmware, GError **error) |
428 | 9.44k | { |
429 | 9.44k | FuEfiSection *self = FU_EFI_SECTION(firmware); |
430 | 9.44k | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
431 | 9.44k | g_autoptr(FuStructEfiSection) st = fu_struct_efi_section_new(); |
432 | 9.44k | g_autoptr(GBytes) blob = NULL; |
433 | | |
434 | | /* simple blob for now */ |
435 | 9.44k | blob = fu_firmware_get_bytes_with_patches(firmware, error); |
436 | 9.44k | if (blob == NULL) |
437 | 149 | return NULL; |
438 | | |
439 | | /* header */ |
440 | 9.29k | if (priv->type == FU_EFI_SECTION_TYPE_GUID_DEFINED) { |
441 | 1.98k | fwupd_guid_t guid = {0x0}; |
442 | 1.98k | g_autoptr(FuStructEfiSectionGuidDefined) st_def = |
443 | 1.98k | fu_struct_efi_section_guid_defined_new(); |
444 | 1.98k | if (!fwupd_guid_from_string(fu_firmware_get_id(firmware), |
445 | 1.98k | &guid, |
446 | 1.98k | FWUPD_GUID_FLAG_MIXED_ENDIAN, |
447 | 1.98k | error)) |
448 | 0 | return NULL; |
449 | 1.98k | fu_struct_efi_section_guid_defined_set_name(st_def, &guid); |
450 | 1.98k | fu_struct_efi_section_guid_defined_set_offset(st_def, |
451 | 1.98k | st->buf->len + st_def->buf->len); |
452 | 1.98k | fu_byte_array_append_array(st->buf, st_def->buf); |
453 | 1.98k | } |
454 | 9.29k | fu_struct_efi_section_set_type(st, priv->type); |
455 | 9.29k | fu_struct_efi_section_set_size(st, st->buf->len + g_bytes_get_size(blob)); |
456 | | |
457 | | /* blob */ |
458 | 9.29k | fu_byte_array_append_bytes(st->buf, blob); |
459 | 9.29k | return g_steal_pointer(&st->buf); |
460 | 9.29k | } |
461 | | |
462 | | static gboolean |
463 | | fu_efi_section_build(FuFirmware *firmware, XbNode *n, GError **error) |
464 | 0 | { |
465 | 0 | FuEfiSection *self = FU_EFI_SECTION(firmware); |
466 | 0 | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
467 | 0 | const gchar *str; |
468 | 0 | guint64 tmp; |
469 | | |
470 | | /* simple properties */ |
471 | 0 | tmp = xb_node_query_text_as_uint(n, "type", NULL); |
472 | 0 | if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT8) |
473 | 0 | priv->type = tmp; |
474 | 0 | str = xb_node_query_text(n, "user_interface", NULL); |
475 | 0 | if (str != NULL) { |
476 | 0 | if (priv->user_interface != NULL) { |
477 | 0 | g_set_error(error, |
478 | 0 | FWUPD_ERROR, |
479 | 0 | FWUPD_ERROR_INTERNAL, |
480 | 0 | "UI already set as %s for section", |
481 | 0 | priv->user_interface); |
482 | 0 | return FALSE; |
483 | 0 | } |
484 | 0 | priv->user_interface = g_strdup(str); |
485 | 0 | } |
486 | | |
487 | | /* success */ |
488 | 0 | return TRUE; |
489 | 0 | } |
490 | | |
491 | | static void |
492 | | fu_efi_section_init(FuEfiSection *self) |
493 | 59.1k | { |
494 | 59.1k | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
495 | 59.1k | priv->type = FU_EFI_SECTION_TYPE_RAW; |
496 | 59.1k | fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_NO_AUTO_DETECTION); |
497 | | // fu_firmware_set_alignment (FU_FIRMWARE (self), FU_FIRMWARE_ALIGNMENT_8); |
498 | 59.1k | } |
499 | | |
500 | | static void |
501 | | fu_efi_section_finalize(GObject *object) |
502 | 59.1k | { |
503 | 59.1k | FuEfiSection *self = FU_EFI_SECTION(object); |
504 | 59.1k | FuEfiSectionPrivate *priv = GET_PRIVATE(self); |
505 | 59.1k | g_free(priv->user_interface); |
506 | 59.1k | G_OBJECT_CLASS(fu_efi_section_parent_class)->finalize(object); |
507 | 59.1k | } |
508 | | |
509 | | static void |
510 | | fu_efi_section_class_init(FuEfiSectionClass *klass) |
511 | 3 | { |
512 | 3 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
513 | 3 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
514 | 3 | object_class->finalize = fu_efi_section_finalize; |
515 | 3 | firmware_class->parse = fu_efi_section_parse; |
516 | 3 | firmware_class->write = fu_efi_section_write; |
517 | 3 | firmware_class->build = fu_efi_section_build; |
518 | 3 | firmware_class->export = fu_efi_section_export; |
519 | 3 | fu_firmware_add_image_gtype(firmware_class, FU_TYPE_EFI_VOLUME); |
520 | 3 | fu_firmware_add_image_gtype(firmware_class, FU_TYPE_EFI_SECTION); |
521 | 3 | #ifdef HAVE_FUZZER |
522 | 3 | fu_firmware_set_size_max(firmware_class, 1 * FU_MB); |
523 | 3 | fu_firmware_set_images_max(firmware_class, 10); |
524 | | #else |
525 | | fu_firmware_set_size_max(firmware_class, 1 * FU_GB); |
526 | | fu_firmware_set_images_max(firmware_class, 2000); |
527 | | #endif |
528 | 3 | } |
529 | | |
530 | | /** |
531 | | * fu_efi_section_new: |
532 | | * |
533 | | * Creates a new #FuFirmware |
534 | | * |
535 | | * Since: 2.0.0 |
536 | | **/ |
537 | | FuFirmware * |
538 | | fu_efi_section_new(void) |
539 | 59.1k | { |
540 | 59.1k | return FU_FIRMWARE(g_object_new(FU_TYPE_EFI_SECTION, NULL)); |
541 | 59.1k | } |