Coverage Report

Created: 2026-05-30 06:50

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-common.h"
11
#include "fu-efi-file.h"
12
#include "fu-efi-filesystem.h"
13
#include "fu-input-stream.h"
14
#include "fu-partial-input-stream.h"
15
16
/**
17
 * FuEfiFilesystem:
18
 *
19
 * A UEFI filesystem.
20
 *
21
 * See also: [class@FuFirmware]
22
 */
23
24
46.6k
G_DEFINE_TYPE(FuEfiFilesystem, fu_efi_filesystem, FU_TYPE_FIRMWARE)
25
46.6k
26
46.6k
#define FU_EFI_FILESYSTEM_FILES_MAX 10000
27
46.6k
#define FU_EFI_FILESYSTEM_SIZE_MAX  (256 * FU_MB)
28
29
static gboolean
30
fu_efi_filesystem_parse(FuFirmware *firmware,
31
      GInputStream *stream,
32
      FuFirmwareParseFlags flags,
33
      GError **error)
34
5.03k
{
35
5.03k
  gsize offset = 0;
36
5.03k
  gsize streamsz = 0;
37
5.03k
  if (!fu_input_stream_size(stream, &streamsz, error))
38
0
    return FALSE;
39
10.3k
  while (offset < streamsz) {
40
9.47k
    g_autoptr(FuFirmware) img = fu_efi_file_new();
41
9.47k
    g_autoptr(GInputStream) stream_tmp = NULL;
42
9.47k
    gboolean is_freespace = TRUE;
43
44
    /* ignore free space */
45
17.3k
    for (guint i = 0; i < 0x18; i++) {
46
17.3k
      guint8 tmp = 0;
47
17.3k
      if (!fu_input_stream_read_u8(stream, offset + i, &tmp, error))
48
33
        return FALSE;
49
17.2k
      if (tmp != 0xff) {
50
9.39k
        is_freespace = FALSE;
51
9.39k
        break;
52
9.39k
      }
53
17.2k
    }
54
9.44k
    if (is_freespace) {
55
52
      g_debug("ignoring free space @0x%x of 0x%x",
56
52
        (guint)offset,
57
52
        (guint)streamsz);
58
52
      break;
59
52
    }
60
9.39k
    stream_tmp = fu_partial_input_stream_new(stream, offset, streamsz - offset, error);
61
9.39k
    if (stream_tmp == NULL) {
62
0
      g_prefix_error_literal(error, "failed to cut EFI file: ");
63
0
      return FALSE;
64
0
    }
65
9.39k
    if (!fu_firmware_parse_stream(img,
66
9.39k
                stream_tmp,
67
9.39k
                0x0,
68
9.39k
                flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
69
9.39k
                error)) {
70
4.03k
      g_prefix_error(error, "failed to parse EFI file at 0x%x: ", (guint)offset);
71
4.03k
      return FALSE;
72
4.03k
    }
73
5.35k
    if (fu_firmware_get_size(img) == 0) {
74
0
      g_set_error_literal(error,
75
0
              FWUPD_ERROR,
76
0
              FWUPD_ERROR_INVALID_FILE,
77
0
              "EFI file has invalid size of 0");
78
0
      return FALSE;
79
0
    }
80
5.35k
    fu_firmware_set_offset(firmware, offset);
81
5.35k
    if (!fu_firmware_add_image(firmware, img, error))
82
1
      return FALSE;
83
84
    /* next! */
85
5.35k
    if (!fu_size_checked_inc(&offset, fu_firmware_get_size(img), error))
86
0
      return FALSE;
87
5.35k
  }
88
89
  /* success */
90
961
  return TRUE;
91
5.03k
}
92
93
static GByteArray *
94
fu_efi_filesystem_write(FuFirmware *firmware, GError **error)
95
885
{
96
885
  g_autoptr(GByteArray) buf = g_byte_array_new();
97
885
  g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware);
98
99
  /* sanity check */
100
885
  if (fu_firmware_get_alignment(firmware) > FU_FIRMWARE_ALIGNMENT_1M) {
101
0
    g_set_error(error,
102
0
          FWUPD_ERROR,
103
0
          FWUPD_ERROR_INVALID_FILE,
104
0
          "alignment invalid, got 0x%02x",
105
0
          fu_firmware_get_alignment(firmware));
106
0
    return NULL;
107
0
  }
108
109
  /* add each file */
110
3.05k
  for (guint i = 0; i < images->len; i++) {
111
2.42k
    FuFirmware *img = g_ptr_array_index(images, i);
112
2.42k
    g_autoptr(GBytes) blob = NULL;
113
2.42k
    fu_firmware_set_offset(img, buf->len);
114
2.42k
    blob = fu_firmware_write(img, error);
115
2.42k
    if (blob == NULL)
116
258
      return NULL;
117
2.17k
    fu_byte_array_append_bytes(buf, blob);
118
2.17k
    fu_byte_array_align_up(buf, fu_firmware_get_alignment(firmware), 0xFF);
119
120
    /* sanity check */
121
2.17k
    if (buf->len > FU_EFI_FILESYSTEM_SIZE_MAX) {
122
0
      g_set_error(error,
123
0
            FWUPD_ERROR,
124
0
            FWUPD_ERROR_INVALID_FILE,
125
0
            "EFI filesystem too large, 0x%02x > 0x%02x",
126
0
            (guint)buf->len,
127
0
            (guint)FU_EFI_FILESYSTEM_SIZE_MAX);
128
0
      return NULL;
129
0
    }
130
2.17k
  }
131
132
  /* success */
133
627
  return g_steal_pointer(&buf);
134
885
}
135
136
static void
137
fu_efi_filesystem_init(FuEfiFilesystem *self)
138
5.03k
{
139
5.03k
#ifdef HAVE_FUZZER
140
  /* if fuzzing, artificially limit the number of files to avoid using large amounts of RSS
141
   * when printing the FuEfiFilesystem XML output */
142
5.03k
  fu_firmware_set_images_max(FU_FIRMWARE(self), 50);
143
5.03k
  fu_firmware_set_size_max(FU_FIRMWARE(self), 1 * FU_MB);
144
#else
145
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_EFI_FILESYSTEM_FILES_MAX);
146
  fu_firmware_set_size_max(FU_FIRMWARE(self), 1 * FU_GB);
147
#endif
148
5.03k
  fu_firmware_set_alignment(FU_FIRMWARE(self), FU_FIRMWARE_ALIGNMENT_8);
149
5.03k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_FILESYSTEM);
150
5.03k
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_EFI_FILE);
151
5.03k
}
152
153
static void
154
fu_efi_filesystem_class_init(FuEfiFilesystemClass *klass)
155
2
{
156
2
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
157
2
  firmware_class->parse = fu_efi_filesystem_parse;
158
2
  firmware_class->write = fu_efi_filesystem_write;
159
2
}
160
161
/**
162
 * fu_efi_filesystem_new:
163
 *
164
 * Creates a new #FuFirmware
165
 *
166
 * Since: 2.0.0
167
 **/
168
FuFirmware *
169
fu_efi_filesystem_new(void)
170
1.34k
{
171
1.34k
  return FU_FIRMWARE(g_object_new(FU_TYPE_EFI_FILESYSTEM, NULL));
172
1.34k
}