Coverage Report

Created: 2025-10-13 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-efi-filesystem.c
Line
Count
Source
1
/*
2
 * Copyright 2021 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#include "config.h"
8
9
#include "fu-byte-array.h"
10
#include "fu-efi-file.h"
11
#include "fu-efi-filesystem.h"
12
#include "fu-input-stream.h"
13
#include "fu-partial-input-stream.h"
14
15
/**
16
 * FuEfiFilesystem:
17
 *
18
 * A UEFI filesystem.
19
 *
20
 * See also: [class@FuFirmware]
21
 */
22
23
21.7k
G_DEFINE_TYPE(FuEfiFilesystem, fu_efi_filesystem, FU_TYPE_FIRMWARE)
24
21.7k
25
21.7k
#define FU_EFI_FILESYSTEM_FILES_MAX 10000
26
21.7k
#define FU_EFI_FILESYSTEM_SIZE_MAX  0x10000000 /* 256 MB */
27
28
static gboolean
29
fu_efi_filesystem_parse(FuFirmware *firmware,
30
      GInputStream *stream,
31
      FuFirmwareParseFlags flags,
32
      GError **error)
33
5.68k
{
34
5.68k
  gsize offset = 0;
35
5.68k
  gsize streamsz = 0;
36
5.68k
  if (!fu_input_stream_size(stream, &streamsz, error))
37
0
    return FALSE;
38
32.5k
  while (offset < streamsz) {
39
31.8k
    g_autoptr(FuFirmware) img = fu_efi_file_new();
40
31.8k
    g_autoptr(GInputStream) stream_tmp = NULL;
41
31.8k
    gboolean is_freespace = TRUE;
42
43
    /* ignore free space */
44
47.7k
    for (guint i = 0; i < 0x18; i++) {
45
47.2k
      guint8 tmp = 0;
46
47.2k
      if (!fu_input_stream_read_u8(stream, offset + i, &tmp, error))
47
21
        return FALSE;
48
47.2k
      if (tmp != 0xff) {
49
31.2k
        is_freespace = FALSE;
50
31.2k
        break;
51
31.2k
      }
52
47.2k
    }
53
31.8k
    if (is_freespace) {
54
531
      g_debug("ignoring free space @0x%x of 0x%x",
55
531
        (guint)offset,
56
531
        (guint)streamsz);
57
531
      break;
58
531
    }
59
31.2k
    stream_tmp = fu_partial_input_stream_new(stream, offset, streamsz - offset, error);
60
31.2k
    if (stream_tmp == NULL) {
61
0
      g_prefix_error_literal(error, "failed to cut EFI file: ");
62
0
      return FALSE;
63
0
    }
64
31.2k
    if (!fu_firmware_parse_stream(img,
65
31.2k
                stream_tmp,
66
31.2k
                0x0,
67
31.2k
                flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
68
31.2k
                error)) {
69
4.40k
      g_prefix_error(error, "failed to parse EFI file at 0x%x: ", (guint)offset);
70
4.40k
      return FALSE;
71
4.40k
    }
72
26.8k
    fu_firmware_set_offset(firmware, offset);
73
26.8k
    if (!fu_firmware_add_image(firmware, img, error))
74
1
      return FALSE;
75
76
    /* next! */
77
26.8k
    offset += fu_firmware_get_size(img);
78
26.8k
  }
79
80
  /* success */
81
1.25k
  return TRUE;
82
5.68k
}
83
84
static GByteArray *
85
fu_efi_filesystem_write(FuFirmware *firmware, GError **error)
86
1.06k
{
87
1.06k
  g_autoptr(GByteArray) buf = g_byte_array_new();
88
1.06k
  g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware);
89
90
  /* sanity check */
91
1.06k
  if (fu_firmware_get_alignment(firmware) > FU_FIRMWARE_ALIGNMENT_1M) {
92
0
    g_set_error(error,
93
0
          FWUPD_ERROR,
94
0
          FWUPD_ERROR_INVALID_FILE,
95
0
          "alignment invalid, got 0x%02x",
96
0
          fu_firmware_get_alignment(firmware));
97
0
    return NULL;
98
0
  }
99
100
  /* add each file */
101
8.18k
  for (guint i = 0; i < images->len; i++) {
102
7.53k
    FuFirmware *img = g_ptr_array_index(images, i);
103
7.53k
    g_autoptr(GBytes) blob = NULL;
104
7.53k
    fu_firmware_set_offset(img, buf->len);
105
7.53k
    blob = fu_firmware_write(img, error);
106
7.53k
    if (blob == NULL)
107
410
      return NULL;
108
7.12k
    fu_byte_array_append_bytes(buf, blob);
109
7.12k
    fu_byte_array_align_up(buf, fu_firmware_get_alignment(firmware), 0xFF);
110
111
    /* sanity check */
112
7.12k
    if (buf->len > FU_EFI_FILESYSTEM_SIZE_MAX) {
113
0
      g_set_error(error,
114
0
            FWUPD_ERROR,
115
0
            FWUPD_ERROR_INVALID_FILE,
116
0
            "EFI filesystem too large, 0x%02x > 0x%02x",
117
0
            (guint)buf->len,
118
0
            (guint)FU_EFI_FILESYSTEM_SIZE_MAX);
119
0
      return NULL;
120
0
    }
121
7.12k
  }
122
123
  /* success */
124
650
  return g_steal_pointer(&buf);
125
1.06k
}
126
127
static void
128
fu_efi_filesystem_init(FuEfiFilesystem *self)
129
5.68k
{
130
5.68k
#ifdef HAVE_FUZZER
131
  /* if fuzzing, artificially limit the number of files to avoid using large amounts of RSS
132
   * when printing the FuEfiFilesystem XML output */
133
5.68k
  fu_firmware_set_images_max(FU_FIRMWARE(self), 50);
134
#else
135
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_EFI_FILESYSTEM_FILES_MAX);
136
#endif
137
5.68k
  fu_firmware_set_alignment(FU_FIRMWARE(self), FU_FIRMWARE_ALIGNMENT_8);
138
5.68k
  g_type_ensure(FU_TYPE_EFI_FILE);
139
5.68k
}
140
141
static void
142
fu_efi_filesystem_class_init(FuEfiFilesystemClass *klass)
143
2
{
144
2
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
145
2
  firmware_class->parse = fu_efi_filesystem_parse;
146
2
  firmware_class->write = fu_efi_filesystem_write;
147
2
}
148
149
/**
150
 * fu_efi_filesystem_new:
151
 *
152
 * Creates a new #FuFirmware
153
 *
154
 * Since: 2.0.0
155
 **/
156
FuFirmware *
157
fu_efi_filesystem_new(void)
158
2.17k
{
159
2.17k
  return FU_FIRMWARE(g_object_new(FU_TYPE_EFI_FILESYSTEM, NULL));
160
2.17k
}