Coverage Report

Created: 2026-10-17 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-sbatlevel-section.c
Line
Count
Source
1
/*
2
 * Copyright 2023 Canonical Ltd.
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#define G_LOG_DOMAIN "FuFirmware"
8
9
#include "config.h"
10
11
#include "fu-byte-array.h"
12
#include "fu-common.h"
13
#include "fu-csv-firmware.h"
14
#include "fu-input-stream.h"
15
#include "fu-partial-input-stream.h"
16
#include "fu-sbatlevel-section-struct.h"
17
#include "fu-sbatlevel-section.h"
18
19
110
G_DEFINE_TYPE(FuSbatlevelSection, fu_sbatlevel_section, FU_TYPE_FIRMWARE);
20
110
21
110
static gboolean
22
110
fu_sbatlevel_section_add_entry(FuSbatlevelSection *self,
23
110
             FuInputStream *stream,
24
110
             gsize offset,
25
110
             const gchar *entry_name,
26
110
             guint64 entry_idx,
27
110
             FuFirmwareParseFlags flags,
28
110
             GError **error)
29
139
{
30
139
  gsize streamsz = 0;
31
139
  g_autoptr(FuFirmware) entry_fw = NULL;
32
139
  g_autoptr(FuInputStream) partial_stream = NULL;
33
34
  /* stop at the null terminator */
35
139
  if (!fu_input_stream_size(stream, &streamsz, error))
36
0
    return FALSE;
37
139
  if (offset >= streamsz) {
38
14
    g_set_error(error,
39
14
          FWUPD_ERROR,
40
14
          FWUPD_ERROR_INVALID_DATA,
41
14
          "offset 0x%x exceeds stream size 0x%x",
42
14
          (guint)offset,
43
14
          (guint)streamsz);
44
14
    return FALSE;
45
14
  }
46
27.8k
  for (guint i = offset; i < streamsz; i++) {
47
27.8k
    guint8 value = 0;
48
27.8k
    if (!fu_input_stream_read_u8(stream, i, &value, error))
49
0
      return FALSE;
50
27.8k
    if (value == 0x0) {
51
99
      streamsz = i - 1;
52
99
      break;
53
99
    }
54
27.8k
  }
55
56
125
  entry_fw = fu_csv_firmware_new();
57
125
  fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "$id");
58
125
  fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "component_generation");
59
125
  fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "date_stamp");
60
125
  fu_csv_firmware_set_write_column_ids(FU_CSV_FIRMWARE(entry_fw), FALSE);
61
62
125
  fu_firmware_set_idx(entry_fw, entry_idx);
63
125
  fu_firmware_set_id(entry_fw, entry_name);
64
125
  fu_firmware_set_offset(entry_fw, offset);
65
125
  partial_stream = fu_partial_input_stream_new(stream, offset, streamsz - offset, error);
66
125
  if (partial_stream == NULL) {
67
0
    g_prefix_error_literal(error, "failed to cut CSV section: ");
68
0
    return FALSE;
69
0
  }
70
125
  if (!fu_firmware_parse_stream(entry_fw, partial_stream, 0, flags, error)) {
71
1
    g_prefix_error(error, "failed to parse %s: ", entry_name);
72
1
    return FALSE;
73
1
  }
74
124
  if (!fu_firmware_add_image(FU_FIRMWARE(self), entry_fw, error))
75
0
    return FALSE;
76
77
  /* success */
78
124
  return TRUE;
79
124
}
80
81
static gboolean
82
fu_sbatlevel_section_parse(FuFirmware *firmware,
83
         FuInputStream *stream,
84
         FuFirmwareParseFlags flags,
85
         GError **error)
86
80
{
87
80
  FuSbatlevelSection *self = FU_SBATLEVEL_SECTION(firmware);
88
80
  g_autoptr(FuStructSbatLevelSectionHeader) st = NULL;
89
90
80
  st = fu_struct_sbat_level_section_header_parse_stream(stream, 0x0, error);
91
80
  if (st == NULL)
92
7
    return FALSE;
93
73
  if (!fu_sbatlevel_section_add_entry(
94
73
    self,
95
73
    stream,
96
73
    sizeof(guint32) + fu_struct_sbat_level_section_header_get_previous(st),
97
73
    "previous",
98
73
    0,
99
73
    flags,
100
73
    error))
101
7
    return FALSE;
102
66
  if (!fu_sbatlevel_section_add_entry(self,
103
66
              stream,
104
66
              sizeof(guint32) +
105
66
            fu_struct_sbat_level_section_header_get_latest(st),
106
66
              "latest",
107
66
              1,
108
66
              flags,
109
66
              error))
110
8
    return FALSE;
111
58
  return TRUE;
112
66
}
113
114
static GByteArray *
115
fu_sbatlevel_section_write(FuFirmware *firmware, GError **error)
116
15
{
117
15
  g_autoptr(FuFirmware) img_ltst = NULL;
118
15
  g_autoptr(FuFirmware) img_prev = NULL;
119
15
  g_autoptr(FuStructSbatLevelSectionHeader) st = fu_struct_sbat_level_section_header_new();
120
15
  g_autoptr(GByteArray) buf_ltst = NULL;
121
15
  g_autoptr(GByteArray) buf_prev = NULL;
122
123
  /* previous */
124
15
  fu_struct_sbat_level_section_header_set_previous(st, sizeof(guint32) * 2);
125
15
  img_prev = fu_firmware_get_image_by_id(firmware, "previous", error);
126
15
  if (img_prev == NULL)
127
2
    return NULL;
128
13
  buf_prev = fu_firmware_write_array(img_prev, error);
129
13
  if (buf_prev == NULL)
130
0
    return NULL;
131
13
  fu_byte_array_append_array(st->buf, buf_prev);
132
13
  fu_byte_array_append_uint8(st->buf, 0x0);
133
134
  /* latest */
135
13
  fu_struct_sbat_level_section_header_set_latest(st,
136
13
                   (sizeof(guint32) * 2) + buf_prev->len + 1);
137
13
  img_ltst = fu_firmware_get_image_by_id(firmware, "latest", error);
138
13
  if (img_ltst == NULL)
139
0
    return NULL;
140
13
  buf_ltst = fu_firmware_write_array(img_ltst, error);
141
13
  if (buf_ltst == NULL)
142
0
    return NULL;
143
13
  fu_byte_array_append_array(st->buf, buf_ltst);
144
13
  fu_byte_array_append_uint8(st->buf, 0x0);
145
146
  /* success */
147
13
  return g_steal_pointer(&st->buf);
148
13
}
149
150
static void
151
fu_sbatlevel_section_init(FuSbatlevelSection *self)
152
109
{
153
109
}
154
155
static void
156
fu_sbatlevel_section_class_init(FuSbatlevelSectionClass *klass)
157
1
{
158
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
159
1
  fu_firmware_add_image_gtype(firmware_class, FU_TYPE_CSV_FIRMWARE);
160
161
1
  fu_firmware_set_size_max(firmware_class, 10 * FU_KB);
162
1
  firmware_class->parse = fu_sbatlevel_section_parse;
163
1
  firmware_class->write = fu_sbatlevel_section_write;
164
1
  fu_firmware_set_images_max(firmware_class, 2);
165
1
}
166
167
FuFirmware *
168
fu_sbatlevel_section_new(void)
169
109
{
170
109
  return FU_FIRMWARE(g_object_new(FU_TYPE_SBATLEVEL_SECTION, NULL));
171
109
}