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