Coverage Report

Created: 2026-10-17 07:48

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
5.56k
G_DEFINE_TYPE(FuEfiFilesystem, fu_efi_filesystem, FU_TYPE_FIRMWARE)
25
5.56k
26
5.56k
#define FU_EFI_FILESYSTEM_FILES_MAX 10000
27
6.96k
#define FU_EFI_FILESYSTEM_SIZE_MAX  (256 * FU_MB)
28
29
static gboolean
30
fu_efi_filesystem_parse(FuFirmware *firmware,
31
      FuInputStream *stream,
32
      FuFirmwareParseFlags flags,
33
      GError **error)
34
5.55k
{
35
5.55k
  gsize offset = 0;
36
5.55k
  gsize streamsz = 0;
37
5.55k
  if (!fu_input_stream_size(stream, &streamsz, error))
38
0
    return FALSE;
39
19.2k
  while (offset < streamsz) {
40
18.4k
    g_autoptr(FuFirmware) img = fu_efi_file_new();
41
18.4k
    g_autoptr(FuInputStream) stream_tmp = NULL;
42
18.4k
    gboolean is_freespace = TRUE;
43
44
    /* ignore free space */
45
32.2k
    for (guint i = 0; i < 0x18; i++) {
46
31.9k
      guint8 tmp = 0;
47
31.9k
      if (!fu_input_stream_read_u8(stream, offset + i, &tmp, error))
48
35
        return FALSE;
49
31.9k
      if (tmp != 0xff) {
50
18.0k
        is_freespace = FALSE;
51
18.0k
        break;
52
18.0k
      }
53
31.9k
    }
54
18.3k
    if (is_freespace) {
55
336
      g_debug("ignoring free space @0x%x of 0x%x",
56
336
        (guint)offset,
57
336
        (guint)streamsz);
58
336
      break;
59
336
    }
60
18.0k
    stream_tmp = fu_partial_input_stream_new(stream, offset, streamsz - offset, error);
61
18.0k
    if (stream_tmp == NULL) {
62
0
      g_prefix_error_literal(error, "failed to cut EFI file: ");
63
0
      return FALSE;
64
0
    }
65
18.0k
    if (!fu_firmware_parse_stream(img,
66
18.0k
                stream_tmp,
67
18.0k
                0x0,
68
18.0k
                flags | FU_FIRMWARE_PARSE_FLAG_NO_SEARCH,
69
18.0k
                error)) {
70
4.39k
      g_prefix_error(error, "failed to parse EFI file at 0x%x: ", (guint)offset);
71
4.39k
      return FALSE;
72
4.39k
    }
73
13.6k
    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
13.6k
    fu_firmware_set_offset(firmware, offset);
81
13.6k
    if (!fu_firmware_add_image(firmware, img, error))
82
3
      return FALSE;
83
84
    /* next! */
85
13.6k
    if (!fu_size_checked_inc(&offset, fu_firmware_get_size(img), error))
86
0
      return FALSE;
87
13.6k
  }
88
89
  /* success */
90
1.11k
  return TRUE;
91
5.55k
}
92
93
static GByteArray *
94
fu_efi_filesystem_write(FuFirmware *firmware, GError **error)
95
1.01k
{
96
1.01k
  g_autoptr(GByteArray) buf = g_byte_array_new();
97
1.01k
  g_autoptr(GPtrArray) images = fu_firmware_get_images(firmware);
98
99
  /* sanity check */
100
1.01k
  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
7.98k
  for (guint i = 0; i < images->len; i++) {
111
6.96k
    FuFirmware *img = g_ptr_array_index(images, i);
112
6.96k
    g_autoptr(GByteArray) buf_tmp = NULL;
113
114
6.96k
    fu_firmware_set_offset(img, buf->len);
115
6.96k
    buf_tmp = fu_firmware_write_array(img, error);
116
6.96k
    if (buf_tmp == NULL)
117
0
      return NULL;
118
6.96k
    fu_byte_array_append_array(buf, buf_tmp);
119
6.96k
    fu_byte_array_align_up(buf, fu_firmware_get_alignment(firmware), 0xFF);
120
121
    /* sanity check */
122
6.96k
    if (buf->len > FU_EFI_FILESYSTEM_SIZE_MAX) {
123
0
      g_set_error(error,
124
0
            FWUPD_ERROR,
125
0
            FWUPD_ERROR_INVALID_FILE,
126
0
            "EFI filesystem too large, 0x%02x > 0x%02x",
127
0
            buf->len,
128
0
            (guint)FU_EFI_FILESYSTEM_SIZE_MAX);
129
0
      return NULL;
130
0
    }
131
6.96k
  }
132
133
  /* success */
134
1.01k
  return g_steal_pointer(&buf);
135
1.01k
}
136
137
static void
138
fu_efi_filesystem_init(FuEfiFilesystem *self)
139
5.55k
{
140
5.55k
  fu_firmware_set_alignment(FU_FIRMWARE(self), FU_FIRMWARE_ALIGNMENT_8);
141
5.55k
}
142
143
static void
144
fu_efi_filesystem_class_init(FuEfiFilesystemClass *klass)
145
3
{
146
3
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
147
3
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_EFI_FILESYSTEM);
148
3
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_EFI_FILE);
149
3
  firmware_class->parse = fu_efi_filesystem_parse;
150
3
  firmware_class->write = fu_efi_filesystem_write;
151
3
#ifdef HAVE_FUZZER
152
3
  fu_firmware_set_images_max(firmware_class, 50);
153
3
  fu_firmware_set_size_max(firmware_class, 1 * FU_MB);
154
#else
155
  fu_firmware_set_images_max(firmware_class, FU_EFI_FILESYSTEM_FILES_MAX);
156
  fu_firmware_set_size_max(firmware_class, 1 * FU_GB);
157
#endif
158
3
}
159
160
/**
161
 * fu_efi_filesystem_new:
162
 *
163
 * Creates a new #FuFirmware
164
 *
165
 * Since: 2.0.0
166
 **/
167
FuFirmware *
168
fu_efi_filesystem_new(void)
169
2.48k
{
170
2.48k
  return FU_FIRMWARE(g_object_new(FU_TYPE_EFI_FILESYSTEM, NULL));
171
2.48k
}