/src/fwupd/libfwupdplugin/fu-json-firmware.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2025 Richard Hughes <richard@hughsie.com> |
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-common.h" |
12 | | #include "fu-json-firmware.h" |
13 | | |
14 | | /** |
15 | | * FuJsonFirmware: |
16 | | * |
17 | | * A "dummy" loader that just checks if the file can be parsed and written as JSON format. |
18 | | */ |
19 | | |
20 | | typedef struct { |
21 | | FwupdJsonNode *json_node; |
22 | | } FuJsonFirmwarePrivate; |
23 | | |
24 | 7.43k | G_DEFINE_TYPE_WITH_PRIVATE(FuJsonFirmware, fu_json_firmware, FU_TYPE_FIRMWARE) |
25 | 7.43k | #define GET_PRIVATE(o) (fu_json_firmware_get_instance_private(o)) |
26 | | |
27 | | static gboolean |
28 | | fu_json_firmware_parse(FuFirmware *firmware, |
29 | | GInputStream *stream, |
30 | | FuFirmwareParseFlags flags, |
31 | | GError **error) |
32 | 2.18k | { |
33 | 2.18k | FuJsonFirmware *self = FU_JSON_FIRMWARE(firmware); |
34 | 2.18k | FuJsonFirmwarePrivate *priv = GET_PRIVATE(self); |
35 | 2.18k | g_autoptr(FwupdJsonParser) json_parser = fwupd_json_parser_new(); |
36 | | |
37 | 2.18k | #ifdef HAVE_FUZZER |
38 | | /* make the fuzzer spend time on complexity, not depth or length -> OOM */ |
39 | 2.18k | fwupd_json_parser_set_max_depth(json_parser, 5); |
40 | 2.18k | fwupd_json_parser_set_max_items(json_parser, 10); |
41 | 2.18k | fwupd_json_parser_set_max_quoted(json_parser, 10); |
42 | | #else |
43 | | fwupd_json_parser_set_max_depth(json_parser, 50); |
44 | | fwupd_json_parser_set_max_items(json_parser, 10000); |
45 | | fwupd_json_parser_set_max_quoted(json_parser, 100000); |
46 | | #endif |
47 | | |
48 | | /* just load into memory, no extraction performed */ |
49 | 2.18k | priv->json_node = fwupd_json_parser_load_from_stream(json_parser, |
50 | 2.18k | stream, |
51 | 2.18k | FWUPD_JSON_LOAD_FLAG_NONE, |
52 | 2.18k | error); |
53 | 2.18k | if (priv->json_node == NULL) |
54 | 1.32k | return FALSE; |
55 | | |
56 | | /* success */ |
57 | 864 | return TRUE; |
58 | 2.18k | } |
59 | | |
60 | | static GByteArray * |
61 | | fu_json_firmware_write(FuFirmware *firmware, GError **error) |
62 | 864 | { |
63 | 864 | FuJsonFirmware *self = FU_JSON_FIRMWARE(firmware); |
64 | 864 | FuJsonFirmwarePrivate *priv = GET_PRIVATE(self); |
65 | 864 | g_autoptr(GByteArray) buf = g_byte_array_new(); |
66 | 864 | g_autoptr(GString) str = NULL; |
67 | | |
68 | | /* sanity check */ |
69 | 864 | if (priv->json_node == NULL) { |
70 | 0 | g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "no JSON node"); |
71 | 0 | return NULL; |
72 | 0 | } |
73 | | |
74 | | /* export with no padding */ |
75 | 864 | str = fwupd_json_node_to_string(priv->json_node, FWUPD_JSON_EXPORT_FLAG_NONE); |
76 | 864 | g_byte_array_append(buf, (const guint8 *)str->str, str->len); |
77 | 864 | return g_steal_pointer(&buf); |
78 | 864 | } |
79 | | |
80 | | static void |
81 | | fu_json_firmware_export(FuFirmware *firmware, FuFirmwareExportFlags flags, XbBuilderNode *bn) |
82 | 0 | { |
83 | 0 | FuJsonFirmware *self = FU_JSON_FIRMWARE(firmware); |
84 | 0 | FuJsonFirmwarePrivate *priv = GET_PRIVATE(self); |
85 | 0 | if (priv->json_node != NULL) { |
86 | 0 | g_autoptr(GString) str = |
87 | 0 | fwupd_json_node_to_string(priv->json_node, FWUPD_JSON_EXPORT_FLAG_NONE); |
88 | 0 | fu_xmlb_builder_insert_kv(bn, "json", str->str); |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | static gboolean |
93 | | fu_json_firmware_build(FuFirmware *firmware, XbNode *n, GError **error) |
94 | 0 | { |
95 | 0 | FuJsonFirmware *self = FU_JSON_FIRMWARE(firmware); |
96 | 0 | FuJsonFirmwarePrivate *priv = GET_PRIVATE(self); |
97 | 0 | const gchar *json; |
98 | 0 | g_autoptr(FwupdJsonParser) json_parser = fwupd_json_parser_new(); |
99 | | |
100 | | /* set appropriate limits */ |
101 | 0 | fwupd_json_parser_set_max_depth(json_parser, 10); |
102 | 0 | fwupd_json_parser_set_max_items(json_parser, 100); |
103 | 0 | fwupd_json_parser_set_max_quoted(json_parser, 10000); |
104 | | |
105 | | /* simple properties */ |
106 | 0 | json = xb_node_query_text(n, "json", error); |
107 | 0 | if (json == NULL) { |
108 | 0 | fwupd_error_convert(error); |
109 | 0 | return FALSE; |
110 | 0 | } |
111 | 0 | priv->json_node = |
112 | 0 | fwupd_json_parser_load_from_data(json_parser, json, FWUPD_JSON_LOAD_FLAG_NONE, error); |
113 | 0 | if (priv->json_node == NULL) |
114 | 0 | return FALSE; |
115 | | |
116 | | /* success */ |
117 | 0 | return TRUE; |
118 | 0 | } |
119 | | |
120 | | static void |
121 | | fu_json_firmware_init(FuJsonFirmware *self) |
122 | 2.18k | { |
123 | 2.18k | fu_firmware_add_flag(FU_FIRMWARE(self), FU_FIRMWARE_FLAG_NO_AUTO_DETECTION); |
124 | 2.18k | fu_firmware_set_size_max(FU_FIRMWARE(self), 128 * FU_MB); |
125 | 2.18k | } |
126 | | |
127 | | static void |
128 | | fu_json_firmware_finalize(GObject *obj) |
129 | 2.18k | { |
130 | 2.18k | FuJsonFirmware *self = FU_JSON_FIRMWARE(obj); |
131 | 2.18k | FuJsonFirmwarePrivate *priv = GET_PRIVATE(self); |
132 | 2.18k | if (priv->json_node != NULL) |
133 | 864 | fwupd_json_node_unref(priv->json_node); |
134 | 2.18k | G_OBJECT_CLASS(fu_json_firmware_parent_class)->finalize(obj); |
135 | 2.18k | } |
136 | | |
137 | | static void |
138 | | fu_json_firmware_class_init(FuJsonFirmwareClass *klass) |
139 | 1 | { |
140 | 1 | FuFirmwareClass *firmware_class = FU_FIRMWARE_CLASS(klass); |
141 | 1 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
142 | 1 | object_class->finalize = fu_json_firmware_finalize; |
143 | 1 | firmware_class->parse = fu_json_firmware_parse; |
144 | 1 | firmware_class->write = fu_json_firmware_write; |
145 | 1 | firmware_class->build = fu_json_firmware_build; |
146 | 1 | firmware_class->export = fu_json_firmware_export; |
147 | 1 | } |