Coverage Report

Created: 2026-04-09 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/plugins/synaptics-prometheus/fu-synaptics-prometheus-firmware.c
Line
Count
Source
1
/*
2
 * Copyright 2019 Richard Hughes <richard@hughsie.com>
3
 * Copyright 2019 Synaptics Inc
4
 *
5
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 */
7
8
#include "config.h"
9
10
#include <string.h>
11
12
#include "fu-synaptics-prometheus-firmware.h"
13
#include "fu-synaptics-prometheus-struct.h"
14
15
struct _FuSynapticsPrometheusFirmware {
16
  FuFirmware parent_instance;
17
  guint32 product_id;
18
  guint32 signature_size;
19
};
20
21
872
G_DEFINE_TYPE(FuSynapticsPrometheusFirmware, fu_synaptics_prometheus_firmware, FU_TYPE_FIRMWARE)
22
872
23
872
/* use only first 12 bit of 16 bits as tag value */
24
4.69k
#define FU_SYNAPTICS_PROMETHEUS_FIRMWARE_TAG_MAX 0xfff0
25
26
371
#define FU_SYNAPTICS_PROMETHEUS_FIRMWARE_COUNT_MAX 64
27
28
guint32
29
fu_synaptics_prometheus_firmware_get_product_id(FuSynapticsPrometheusFirmware *self)
30
0
{
31
0
  g_return_val_if_fail(FU_IS_SYNAPTICS_PROMETHEUS_FIRMWARE(self), 0x0);
32
0
  return self->product_id;
33
0
}
34
35
gboolean
36
fu_synaptics_prometheus_firmware_set_signature_size(FuSynapticsPrometheusFirmware *self,
37
                guint32 signature_size)
38
0
{
39
0
  g_return_val_if_fail(FU_IS_SYNAPTICS_PROMETHEUS_FIRMWARE(self), FALSE);
40
0
  self->signature_size = signature_size;
41
0
  return TRUE;
42
0
}
43
44
static void
45
fu_synaptics_prometheus_firmware_export(FuFirmware *firmware,
46
          FuFirmwareExportFlags flags,
47
          XbBuilderNode *bn)
48
0
{
49
0
  FuSynapticsPrometheusFirmware *self = FU_SYNAPTICS_PROMETHEUS_FIRMWARE(firmware);
50
0
  fu_xmlb_builder_insert_kx(bn, "product_id", self->product_id);
51
0
}
52
53
static gboolean
54
fu_synaptics_prometheus_firmware_parse(FuFirmware *firmware,
55
               GInputStream *stream,
56
               FuFirmwareParseFlags flags,
57
               GError **error)
58
371
{
59
371
  FuSynapticsPrometheusFirmware *self = FU_SYNAPTICS_PROMETHEUS_FIRMWARE(firmware);
60
371
  gsize offset = 0;
61
371
  gsize streamsz = 0;
62
63
371
  if (!fu_input_stream_size(stream, &streamsz, error))
64
0
    return FALSE;
65
371
  if (streamsz < self->signature_size + FU_STRUCT_SYNAPTICS_PROMETHEUS_HDR_SIZE) {
66
23
    g_set_error_literal(error,
67
23
            FWUPD_ERROR,
68
23
            FWUPD_ERROR_INVALID_DATA,
69
23
            "blob is too small to be firmware");
70
23
    return FALSE;
71
23
  }
72
348
  streamsz -= self->signature_size;
73
74
  /* parse each chunk */
75
4.82k
  while (offset < streamsz) {
76
4.69k
    guint32 hdrsz;
77
4.69k
    guint32 tag;
78
4.69k
    g_autoptr(FuFirmware) img = fu_firmware_new();
79
4.69k
    g_autoptr(FuFirmware) img_old = NULL;
80
4.69k
    g_autoptr(FuStructSynapticsPrometheusHdr) st_hdr = NULL;
81
4.69k
    g_autoptr(GInputStream) partial_stream = NULL;
82
83
    /* verify item header */
84
4.69k
    st_hdr = fu_struct_synaptics_prometheus_hdr_parse_stream(stream, offset, error);
85
4.69k
    if (st_hdr == NULL)
86
0
      return FALSE;
87
4.69k
    tag = fu_struct_synaptics_prometheus_hdr_get_tag(st_hdr);
88
4.69k
    if (tag >= FU_SYNAPTICS_PROMETHEUS_FIRMWARE_TAG_MAX) {
89
9
      g_set_error(error,
90
9
            FWUPD_ERROR,
91
9
            FWUPD_ERROR_INVALID_DATA,
92
9
            "tag 0x%04x is too large",
93
9
            tag);
94
9
      return FALSE;
95
9
    }
96
97
    /* sanity check */
98
4.68k
    img_old = fu_firmware_get_image_by_idx(firmware, tag, NULL);
99
4.68k
    if (img_old != NULL) {
100
14
      g_set_error(error,
101
14
            FWUPD_ERROR,
102
14
            FWUPD_ERROR_INVALID_DATA,
103
14
            "tag 0x%04x already present in image",
104
14
            tag);
105
14
      return FALSE;
106
14
    }
107
4.67k
    hdrsz = fu_struct_synaptics_prometheus_hdr_get_bufsz(st_hdr);
108
4.67k
    if (hdrsz == 0) {
109
18
      g_set_error(error,
110
18
            FWUPD_ERROR,
111
18
            FWUPD_ERROR_INVALID_DATA,
112
18
            "empty header for tag 0x%04x",
113
18
            tag);
114
18
      return FALSE;
115
18
    }
116
4.65k
    offset += st_hdr->buf->len;
117
4.65k
    partial_stream = fu_partial_input_stream_new(stream, offset, hdrsz, error);
118
4.65k
    if (partial_stream == NULL)
119
176
      return FALSE;
120
4.47k
    if (!fu_firmware_parse_stream(img, partial_stream, 0x0, flags, error))
121
0
      return FALSE;
122
4.47k
    g_debug("adding 0x%04x (%s) with size 0x%04x",
123
4.47k
      tag,
124
4.47k
      fu_synaptics_prometheus_firmware_tag_to_string(tag),
125
4.47k
      hdrsz);
126
4.47k
    fu_firmware_set_idx(img, tag);
127
4.47k
    fu_firmware_set_id(img, fu_synaptics_prometheus_firmware_tag_to_string(tag));
128
4.47k
    if (!fu_firmware_add_image(firmware, img, error))
129
1
      return FALSE;
130
131
    /* metadata */
132
4.47k
    if (tag == FU_SYNAPTICS_PROMETHEUS_FIRMWARE_TAG_MFW_UPDATE_HEADER) {
133
158
      g_autofree gchar *version = NULL;
134
158
      g_autoptr(FuStructSynapticsPrometheusMfwHdr) st_mfw = NULL;
135
158
      st_mfw = fu_struct_synaptics_prometheus_mfw_hdr_parse_stream(stream,
136
158
                         offset,
137
158
                         error);
138
158
      if (st_mfw == NULL)
139
0
        return FALSE;
140
158
      self->product_id =
141
158
          fu_struct_synaptics_prometheus_mfw_hdr_get_product(st_mfw);
142
158
      version = g_strdup_printf(
143
158
          "%u.%u",
144
158
          fu_struct_synaptics_prometheus_mfw_hdr_get_vmajor(st_mfw),
145
158
          fu_struct_synaptics_prometheus_mfw_hdr_get_vminor(st_mfw));
146
158
      fu_firmware_set_version(firmware, version);
147
158
    }
148
149
    /* next item */
150
4.47k
    offset += hdrsz;
151
4.47k
  }
152
130
  return TRUE;
153
348
}
154
155
static GByteArray *
156
fu_synaptics_prometheus_firmware_write(FuFirmware *firmware, GError **error)
157
130
{
158
130
  FuSynapticsPrometheusFirmware *self = FU_SYNAPTICS_PROMETHEUS_FIRMWARE(firmware);
159
130
  g_autoptr(GByteArray) buf = g_byte_array_new();
160
130
  g_autoptr(FuStructSynapticsPrometheusHdr) st_hdr = fu_struct_synaptics_prometheus_hdr_new();
161
130
  g_autoptr(FuStructSynapticsPrometheusMfwHdr) st_mfw =
162
130
      fu_struct_synaptics_prometheus_mfw_hdr_new();
163
130
  g_autoptr(GBytes) payload = NULL;
164
165
  /* add header */
166
130
  fu_struct_synaptics_prometheus_hdr_set_tag(
167
130
      st_hdr,
168
130
      FU_SYNAPTICS_PROMETHEUS_FIRMWARE_TAG_MFW_UPDATE_HEADER);
169
130
  fu_struct_synaptics_prometheus_hdr_set_bufsz(st_hdr, st_mfw->buf->len);
170
130
  g_byte_array_append(buf, st_hdr->buf->data, st_hdr->buf->len);
171
130
  fu_struct_synaptics_prometheus_mfw_hdr_set_product(st_mfw, self->product_id);
172
130
  fu_byte_array_append_array(buf, st_mfw->buf);
173
174
  /* add payload */
175
130
  payload = fu_firmware_get_bytes_with_patches(firmware, error);
176
130
  if (payload == NULL)
177
130
    return NULL;
178
0
  fu_struct_synaptics_prometheus_hdr_set_tag(
179
0
      st_hdr,
180
0
      FU_SYNAPTICS_PROMETHEUS_FIRMWARE_TAG_MFW_UPDATE_PAYLOAD);
181
0
  fu_struct_synaptics_prometheus_hdr_set_bufsz(st_hdr, g_bytes_get_size(payload));
182
0
  g_byte_array_append(buf, st_hdr->buf->data, st_hdr->buf->len);
183
0
  fu_byte_array_append_bytes(buf, payload);
184
185
  /* add signature */
186
0
  for (guint i = 0; i < self->signature_size; i++)
187
0
    fu_byte_array_append_uint8(buf, 0xff);
188
0
  return g_steal_pointer(&buf);
189
130
}
190
191
static gboolean
192
fu_synaptics_prometheus_firmware_build(FuFirmware *firmware, XbNode *n, GError **error)
193
0
{
194
0
  FuSynapticsPrometheusFirmware *self = FU_SYNAPTICS_PROMETHEUS_FIRMWARE(firmware);
195
0
  guint64 tmp;
196
197
  /* simple properties */
198
0
  tmp = xb_node_query_text_as_uint(n, "product_id", NULL);
199
0
  if (tmp != G_MAXUINT64 && tmp <= G_MAXUINT32)
200
0
    self->product_id = tmp;
201
202
  /* success */
203
0
  return TRUE;
204
0
}
205
206
static void
207
fu_synaptics_prometheus_firmware_init(FuSynapticsPrometheusFirmware *self)
208
371
{
209
371
  fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_HAS_VID_PID);
210
371
  fu_firmware_add_image_gtype(FU_FIRMWARE(self), FU_TYPE_FIRMWARE);
211
371
  fu_firmware_set_images_max(FU_FIRMWARE(self), FU_SYNAPTICS_PROMETHEUS_FIRMWARE_COUNT_MAX);
212
371
  self->signature_size = FU_SYNAPTICS_PROMETHEUS_FIRMWARE_PROMETHEUS_SIGSIZE;
213
371
}
214
215
static void
216
fu_synaptics_prometheus_firmware_class_init(FuSynapticsPrometheusFirmwareClass *klass)
217
1
{
218
1
  FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass);
219
1
  firmware_class->parse = fu_synaptics_prometheus_firmware_parse;
220
1
  firmware_class->write = fu_synaptics_prometheus_firmware_write;
221
1
  firmware_class->export = fu_synaptics_prometheus_firmware_export;
222
1
  firmware_class->build = fu_synaptics_prometheus_firmware_build;
223
1
}
224
225
FuFirmware *
226
fu_synaptics_prometheus_firmware_new(void)
227
0
{
228
0
  return FU_FIRMWARE(g_object_new(FU_TYPE_SYNAPTICS_PROMETHEUS_FIRMWARE, NULL));
229
0
}