Coverage Report

Created: 2026-06-10 07:04

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
4.15k
G_DEFINE_TYPE(FuSbatlevelSection, fu_sbatlevel_section, FU_TYPE_FIRMWARE);
20
4.15k
21
4.15k
static gboolean
22
4.15k
fu_sbatlevel_section_add_entry(FuSbatlevelSection *self,
23
4.15k
             GInputStream *stream,
24
4.15k
             gsize offset,
25
4.15k
             const gchar *entry_name,
26
4.15k
             guint64 entry_idx,
27
4.15k
             FuFirmwareParseFlags flags,
28
4.15k
             GError **error)
29
4.15k
{
30
247
  gsize streamsz = 0;
31
247
  g_autoptr(FuFirmware) entry_fw = NULL;
32
247
  g_autoptr(GInputStream) partial_stream = NULL;
33
34
  /* stop at the null terminator */
35
247
  if (!fu_input_stream_size(stream, &streamsz, error))
36
0
    return FALSE;
37
247
  if (offset >= streamsz) {
38
49
    g_set_error(error,
39
49
          FWUPD_ERROR,
40
49
          FWUPD_ERROR_INVALID_DATA,
41
49
          "offset 0x%x exceeds stream size 0x%x",
42
49
          (guint)offset,
43
49
          (guint)streamsz);
44
49
    return FALSE;
45
49
  }
46
20.1k
  for (guint i = offset; i < streamsz; i++) {
47
20.0k
    guint8 value = 0;
48
20.0k
    if (!fu_input_stream_read_u8(stream, i, &value, error))
49
0
      return FALSE;
50
20.0k
    if (value == 0x0) {
51
175
      streamsz = i - 1;
52
175
      break;
53
175
    }
54
20.0k
  }
55
56
198
  entry_fw = fu_csv_firmware_new();
57
198
  fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "$id");
58
198
  fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "component_generation");
59
198
  fu_csv_firmware_add_column_id(FU_CSV_FIRMWARE(entry_fw), "date_stamp");
60
198
  fu_csv_firmware_set_write_column_ids(FU_CSV_FIRMWARE(entry_fw), FALSE);
61
62
198
  fu_firmware_set_idx(entry_fw, entry_idx);
63
198
  fu_firmware_set_id(entry_fw, entry_name);
64
198
  fu_firmware_set_offset(entry_fw, offset);
65
198
  partial_stream = fu_partial_input_stream_new(stream, offset, streamsz - offset, error);
66
198
  if (partial_stream == NULL) {
67
0
    g_prefix_error_literal(error, "failed to cut CSV section: ");
68
0
    return FALSE;
69
0
  }
70
198
  if (!fu_firmware_parse_stream(entry_fw, partial_stream, 0, flags, error)) {
71
4
    g_prefix_error(error, "failed to parse %s: ", entry_name);
72
4
    return FALSE;
73
4
  }
74
194
  if (!fu_firmware_add_image(FU_FIRMWARE(self), entry_fw, error))
75
0
    return FALSE;
76
77
  /* success */
78
194
  return TRUE;
79
194
}
80
81
static gboolean
82
fu_sbatlevel_section_parse(FuFirmware *firmware,
83
         GInputStream *stream,
84
         FuFirmwareParseFlags flags,
85
         GError **error)
86
185
{
87
185
  FuSbatlevelSection *self = FU_SBATLEVEL_SECTION(firmware);
88
185
  g_autoptr(FuStructSbatLevelSectionHeader) st = NULL;
89
90
185
  st = fu_struct_sbat_level_section_header_parse_stream(stream, 0x0, error);
91
185
  if (st == NULL)
92
48
    return FALSE;
93
137
  if (!fu_sbatlevel_section_add_entry(
94
137
    self,
95
137
    stream,
96
137
    sizeof(guint32) + fu_struct_sbat_level_section_header_get_previous(st),
97
137
    "previous",
98
137
    0,
99
137
    flags,
100
137
    error))
101
27
    return FALSE;
102
110
  if (!fu_sbatlevel_section_add_entry(self,
103
110
              stream,
104
110
              sizeof(guint32) +
105
110
            fu_struct_sbat_level_section_header_get_latest(st),
106
110
              "latest",
107
110
              1,
108
110
              flags,
109
110
              error))
110
26
    return FALSE;
111
84
  return TRUE;
112
110
}
113
114
static GByteArray *
115
fu_sbatlevel_section_write(FuFirmware *firmware, GError **error)
116
27
{
117
27
  g_autoptr(FuFirmware) img_ltst = NULL;
118
27
  g_autoptr(FuFirmware) img_prev = NULL;
119
27
  g_autoptr(FuStructSbatLevelSectionHeader) st = fu_struct_sbat_level_section_header_new();
120
27
  g_autoptr(GBytes) blob_ltst = NULL;
121
27
  g_autoptr(GBytes) blob_prev = NULL;
122
123
  /* previous */
124
27
  fu_struct_sbat_level_section_header_set_previous(st, sizeof(guint32) * 2);
125
27
  img_prev = fu_firmware_get_image_by_id(firmware, "previous", error);
126
27
  if (img_prev == NULL)
127
2
    return NULL;
128
25
  blob_prev = fu_firmware_write(img_prev, error);
129
25
  if (blob_prev == NULL)
130
0
    return NULL;
131
25
  fu_byte_array_append_bytes(st->buf, blob_prev);
132
25
  fu_byte_array_append_uint8(st->buf, 0x0);
133
134
  /* latest */
135
25
  fu_struct_sbat_level_section_header_set_latest(st,
136
25
                   (sizeof(guint32) * 2) +
137
25
                 g_bytes_get_size(blob_prev) + 1);
138
25
  img_ltst = fu_firmware_get_image_by_id(firmware, "latest", error);
139
25
  if (img_ltst == NULL)
140
0
    return NULL;
141
25
  blob_ltst = fu_firmware_write(img_ltst, error);
142
25
  if (blob_ltst == NULL)
143
0
    return NULL;
144
25
  fu_byte_array_append_bytes(st->buf, blob_ltst);
145
25
  fu_byte_array_append_uint8(st->buf, 0x0);
146
147
  /* success */
148
25
  return g_steal_pointer(&st->buf);
149
25
}
150
151
static void
152
fu_sbatlevel_section_init(FuSbatlevelSection *self)
153
222
{
154
222
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_CSV_FIRMWARE);
155
222
  fu_firmware_set_images_max(FU_FIRMWARE(self), 2);
156
222
  fu_firmware_set_size_max(FU_FIRMWARE(self), 10 * FU_KB);
157
222
}
158
159
static void
160
fu_sbatlevel_section_class_init(FuSbatlevelSectionClass *klass)
161
1
{
162
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
163
164
1
  firmware_class->parse = fu_sbatlevel_section_parse;
165
1
  firmware_class->write = fu_sbatlevel_section_write;
166
1
}
167
168
FuFirmware *
169
fu_sbatlevel_section_new(void)
170
222
{
171
222
  return FU_FIRMWARE(g_object_new(FU_TYPE_SBATLEVEL_SECTION, NULL));
172
222
}