Coverage Report

Created: 2025-07-11 06:31

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