diff --git a/contrib/ci/oss-fuzz.py b/contrib/ci/oss-fuzz.py index d878660af..71767a727 100755 --- a/contrib/ci/oss-fuzz.py +++ b/contrib/ci/oss-fuzz.py @@ -313,6 +313,7 @@ def _build(bld: Builder) -> None: Fuzzer("hailuck-kbd", srcdir="hailuck", globstr="ihex*"), Fuzzer("ifd", srcdir="intel-spi"), Fuzzer("pixart", srcdir="pixart-rf", pattern="pxi-firmware"), + Fuzzer("redfish-smbios", srcdir="redfish", pattern="redfish-smbios"), Fuzzer("solokey"), Fuzzer("synaprom", srcdir="synaptics-prometheus"), Fuzzer("synaptics-mst"), diff --git a/libfwupdplugin/fu-fuzzer-firmware.c.in b/libfwupdplugin/fu-fuzzer-firmware.c.in index 05e79cbb7..e3d81f7c1 100644 --- a/libfwupdplugin/fu-fuzzer-firmware.c.in +++ b/libfwupdplugin/fu-fuzzer-firmware.c.in @@ -10,7 +10,7 @@ int LLVMFuzzerTestOneInput (const guint8 *data, gsize size) { - g_autoptr(FuFirmware) firmware = @FIRMWARENEW@ (); + g_autoptr(FuFirmware) firmware = FU_FIRMWARE (@FIRMWARENEW@ ()); g_autoptr(GBytes) fw = g_bytes_new (data, size); gboolean ret = fu_firmware_parse (firmware, fw, FWUPD_INSTALL_FLAG_NONE, NULL); if (!ret && fu_firmware_has_flag (firmware, FU_FIRMWARE_FLAG_HAS_CHECKSUM)) { diff --git a/plugins/redfish/fu-plugin-redfish.c b/plugins/redfish/fu-plugin-redfish.c index da6f34d48..d02d41b49 100644 --- a/plugins/redfish/fu-plugin-redfish.c +++ b/plugins/redfish/fu-plugin-redfish.c @@ -10,6 +10,7 @@ #include "fu-redfish-client.h" #include "fu-redfish-common.h" +#include "fu-redfish-smbios.h" struct FuPluginData { FuRedfishClient *client; @@ -118,6 +119,7 @@ fu_plugin_init (FuPlugin *plugin) FuPluginData *data = fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); data->client = fu_redfish_client_new (); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_add_firmware_gtype (plugin, NULL, FU_TYPE_REDFISH_SMBIOS); } void diff --git a/plugins/redfish/fu-redfish-client.c b/plugins/redfish/fu-redfish-client.c index 93717d25d..06b89fad3 100644 --- a/plugins/redfish/fu-redfish-client.c +++ b/plugins/redfish/fu-redfish-client.c @@ -14,6 +14,7 @@ #include "fu-redfish-client.h" #include "fu-redfish-common.h" +#include "fu-redfish-smbios.h" struct _FuRedfishClient { @@ -428,166 +429,6 @@ fu_redfish_client_set_uefi_credentials (FuRedfishClient *self, GError **error) return TRUE; } -static void -fu_redfish_client_parse_interface_data (const guint8 *buf, guint8 sz) -{ - switch (buf[0]) { - case REDFISH_INTERFACE_TYPE_USB_NEWORK: - g_debug ("USB Network Interface"); - /* - * uint16 idVendor(2-bytes) - * uint16 idProduct(2-bytes) - * uint8 SerialNumberLen: - * uint8 DescriptorType: - * uint8* SerialNumber: - */ - break; - case REDFISH_INTERFACE_TYPE_PCI_NEWORK: - g_debug ("PCI Network Interface"); - /* - * uint16 VendorID - * uint16 DeviceID - * uint16 Subsystem_Vendor_ID - * uint16 Subsystem_ID - */ - break; - default: - break; - } -} - -typedef struct __attribute__((packed)) { - guint8 service_uuid[16]; - guint8 host_ip_assignment_type; - guint8 host_ip_address_format; - guint8 host_ip_address[16]; - guint8 host_ip_mask[16]; - guint8 service_ip_assignment_type; - guint8 service_ip_address_format; - guint8 service_ip_address[16]; - guint8 service_ip_mask[16]; - guint16 service_ip_port; - guint32 service_ip_vlan_id; - guint8 service_hostname_len; - /* service_hostname; */ -} RedfishProtocolDataOverIp; - -static gboolean -fu_redfish_client_parse_protocol_data (FuRedfishClient *self, - const guint8 *buf, - guint8 sz, - GError **error) -{ - RedfishProtocolDataOverIp *pr; - if (sz < sizeof(RedfishProtocolDataOverIp)) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "protocol data too small"); - return FALSE; - } - pr = (RedfishProtocolDataOverIp *) buf; - - /* parse the hostname and port */ - if (pr->service_ip_assignment_type == REDFISH_IP_ASSIGNMENT_TYPE_STATIC || - pr->service_ip_assignment_type == REDFISH_IP_ASSIGNMENT_TYPE_AUTO_CONFIG) { - if (pr->service_ip_address_format == REDFISH_IP_ADDRESS_FORMAT_V4) { - g_autofree gchar *tmp = NULL; - tmp = fu_redfish_common_buffer_to_ipv4 (pr->service_ip_address); - fu_redfish_client_set_hostname (self, tmp); - } else if (pr->service_ip_address_format == REDFISH_IP_ADDRESS_FORMAT_V6) { - g_autofree gchar *tmp = NULL; - tmp = fu_redfish_common_buffer_to_ipv6 (pr->service_ip_address); - fu_redfish_client_set_hostname (self, tmp); - } else { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "address format is invalid"); - return FALSE; - } - fu_redfish_client_set_port (self, pr->service_ip_port); - } else { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "DHCP address formats not supported (%0x2)", - pr->service_ip_assignment_type); - return FALSE; - } - - return TRUE; -} - -static gboolean -fu_redfish_client_set_smbios_interfaces (FuRedfishClient *self, - GBytes *smbios_table, - GError **error) -{ - const guint8 *buf; - gsize sz = 0; - - /* check size */ - buf = g_bytes_get_data (smbios_table, &sz); - if (sz < 0x09) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "SMBIOS entry too small: %" G_GSIZE_FORMAT, - sz); - return FALSE; - } - - /* check interface type */ - if (buf[0x04] != REDFISH_CONTROLLER_INTERFACE_TYPE_NETWORK_HOST) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "only Network Host Interface supported"); - return FALSE; - } - - /* check length */ - if (buf[0x05] > sz - 0x08) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "interface specific data too large %u > %" G_GSIZE_FORMAT, - buf[0x05], sz - 0x08); - return FALSE; - } - - /* parse data, for not just for debugging */ - if (buf[0x05] > 0) - fu_redfish_client_parse_interface_data (&buf[0x06], buf[0x05]); - - /* parse protocol records */ - for (guint8 i = 0x07 + buf[0x05]; i < sz - 1; i++) { - guint8 protocol_id = buf[i]; - guint8 protocol_sz = buf[i+1]; - if (protocol_sz > sz - buf[0x05] + 0x07) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "protocol length too large"); - return FALSE; - } - if (protocol_id == REDFISH_PROTOCOL_REDFISH_OVER_IP) { - if (!fu_redfish_client_parse_protocol_data (self, - &buf[i+2], - protocol_sz, - error)) - return FALSE; - } else { - g_debug ("ignoring unsupported protocol ID %02x", - protocol_id); - } - i += protocol_sz - 1; - } - - return TRUE; -} - G_DEFINE_AUTOPTR_CLEANUP_FUNC(curl_mime, curl_mime_free) gboolean @@ -720,11 +561,27 @@ fu_redfish_client_setup (FuRedfishClient *self, GBytes *smbios_table, GError **e if (smbios_table != NULL) { g_autoptr(GError) error_smbios = NULL; g_autoptr(GError) error_uefi = NULL; - if (!fu_redfish_client_set_smbios_interfaces (self, - smbios_table, - &error_smbios)) { + g_autoptr(FuRedfishSmbios) redfish_smbios = fu_redfish_smbios_new (); + + if (!fu_firmware_parse (FU_FIRMWARE (redfish_smbios), + smbios_table, + FWUPD_INSTALL_FLAG_NONE, + &error_smbios)) { g_debug ("failed to get connection URI automatically: %s", error_smbios->message); + } else { + const gchar *hostname = fu_redfish_smbios_get_ip_addr (redfish_smbios); + if (hostname == NULL) + hostname = fu_redfish_smbios_get_hostname (redfish_smbios); + if (hostname == NULL) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "no hostname"); + return FALSE; + } + fu_redfish_client_set_hostname (self, hostname); + fu_redfish_client_set_port (self, fu_redfish_smbios_get_port (redfish_smbios)); } if (!fu_redfish_client_set_uefi_credentials (self, &error_uefi)) { g_debug ("failed to get username and password automatically: %s", diff --git a/plugins/redfish/fu-redfish-common.c b/plugins/redfish/fu-redfish-common.c index 118fb77c6..49da016a7 100644 --- a/plugins/redfish/fu-redfish-common.c +++ b/plugins/redfish/fu-redfish-common.c @@ -36,4 +36,16 @@ fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer) return g_string_free (str, FALSE); } +gchar * +fu_redfish_common_buffer_to_mac (const guint8 *buffer) +{ + GString *str = g_string_new (NULL); + for (guint i = 0; i < 6; i++) { + g_string_append_printf (str, "%02X", buffer[i]); + if (i != 5) + g_string_append (str, ":"); + } + return g_string_free (str, FALSE); +} + /* vim: set noexpandtab: */ diff --git a/plugins/redfish/fu-redfish-common.h b/plugins/redfish/fu-redfish-common.h index 81fd8a4be..39a9fd3ff 100644 --- a/plugins/redfish/fu-redfish-common.h +++ b/plugins/redfish/fu-redfish-common.h @@ -15,8 +15,10 @@ #define REDFISH_CONTROLLER_INTERFACE_TYPE_NETWORK_HOST 0x40 -#define REDFISH_INTERFACE_TYPE_USB_NEWORK 0x02 -#define REDFISH_INTERFACE_TYPE_PCI_NEWORK 0x03 +#define REDFISH_INTERFACE_TYPE_USB_NETWORK 0x02 +#define REDFISH_INTERFACE_TYPE_PCI_NETWORK 0x03 +#define REDFISH_INTERFACE_TYPE_USB_NETWORK_V2 0x04 +#define REDFISH_INTERFACE_TYPE_PCI_NETWORK_V2 0x05 #define REDFISH_IP_ASSIGNMENT_TYPE_STATIC 0x00 #define REDFISH_IP_ASSIGNMENT_TYPE_DHCP 0x02 @@ -40,3 +42,4 @@ /* shared */ gchar *fu_redfish_common_buffer_to_ipv4 (const guint8 *buffer); gchar *fu_redfish_common_buffer_to_ipv6 (const guint8 *buffer); +gchar *fu_redfish_common_buffer_to_mac (const guint8 *buffer); diff --git a/plugins/redfish/fu-redfish-smbios.c b/plugins/redfish/fu-redfish-smbios.c new file mode 100644 index 000000000..bf2ec6151 --- /dev/null +++ b/plugins/redfish/fu-redfish-smbios.c @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-redfish-common.h" +#include "fu-redfish-smbios.h" + +struct _FuRedfishSmbios { + FuFirmwareClass parent_instance; + guint16 port; + gchar *hostname; + gchar *mac_addr; + gchar *ip_addr; + guint16 vid; + guint16 pid; +}; + +G_DEFINE_TYPE (FuRedfishSmbios, fu_redfish_smbios, FU_TYPE_FIRMWARE) + +typedef struct __attribute__((packed)) { + guint8 service_uuid[16]; + guint8 host_ip_assignment_type; + guint8 host_ip_address_format; + guint8 host_ip_address[16]; + guint8 host_ip_mask[16]; + guint8 service_ip_assignment_type; + guint8 service_ip_address_format; + guint8 service_ip_address[16]; + guint8 service_ip_mask[16]; + guint16 service_ip_port; + guint32 service_ip_vlan_id; + guint8 service_hostname_len; + /* optional service_hostname goes here */ +} FuRedfishProtocolOverIp; + +guint16 +fu_redfish_smbios_get_port (FuRedfishSmbios *self) +{ + return self->port; +} + +const gchar * +fu_redfish_smbios_get_hostname (FuRedfishSmbios *self) +{ + return self->hostname; +} + +const gchar * +fu_redfish_smbios_get_ip_addr (FuRedfishSmbios *self) +{ + return self->ip_addr; +} + +static void +fu_redfish_smbios_set_hostname (FuRedfishSmbios *self, const gchar *hostname) +{ + g_free (self->hostname); + self->hostname = g_strdup (hostname); +} + +static void +fu_redfish_smbios_set_mac_addr (FuRedfishSmbios *self, const gchar *mac_addr) +{ + g_free (self->mac_addr); + self->mac_addr = g_strdup (mac_addr); +} + +static void +fu_redfish_smbios_set_ip_addr (FuRedfishSmbios *self, const gchar *ip_addr) +{ + g_free (self->ip_addr); + self->ip_addr = g_strdup (ip_addr); +} + +static void +fu_redfish_smbios_set_port (FuRedfishSmbios *self, guint16 port) +{ + self->port = port; +} + +static void +fu_redfish_smbios_export (FuFirmware *firmware, + FuFirmwareExportFlags flags, + XbBuilderNode *bn) +{ + FuRedfishSmbios *self = FU_REDFISH_SMBIOS (firmware); + fu_xmlb_builder_insert_kx (bn, "port", self->port); + fu_xmlb_builder_insert_kv (bn, "hostname", self->hostname); + fu_xmlb_builder_insert_kv (bn, "mac_addr", self->mac_addr); + fu_xmlb_builder_insert_kv (bn, "ip_addr", self->ip_addr); + fu_xmlb_builder_insert_kx (bn, "vid", self->vid); + fu_xmlb_builder_insert_kx (bn, "pid", self->pid); +} + +static gboolean +fu_redfish_smbios_build (FuFirmware *firmware, XbNode *n, GError **error) +{ + FuRedfishSmbios *self = FU_REDFISH_SMBIOS (firmware); + const gchar *tmp; + guint64 tmpu; + + /* optional properties */ + tmpu = xb_node_query_text_as_uint (n, "port", NULL); + if (tmpu != G_MAXUINT64) + fu_redfish_smbios_set_port (self, (guint16) tmpu); + tmpu = xb_node_query_text_as_uint (n, "vid", NULL); + if (tmpu != G_MAXUINT64) + self->vid = (guint16) tmpu; + tmpu = xb_node_query_text_as_uint (n, "pid", NULL); + if (tmpu != G_MAXUINT64) + self->pid = (guint16) tmpu; + tmp = xb_node_query_text (n, "hostname", NULL); + if (tmp != NULL) + fu_redfish_smbios_set_hostname (self, tmp); + tmp = xb_node_query_text (n, "mac_addr", NULL); + if (tmp != NULL) + fu_redfish_smbios_set_mac_addr (self, tmp); + tmp = xb_node_query_text (n, "ip_addr", NULL); + if (tmp != NULL) + fu_redfish_smbios_set_ip_addr (self, tmp); + + /* success */ + return TRUE; +} + +static gboolean +fu_redfish_smbios_parse_interface_data (FuRedfishSmbios *self, + GBytes *fw, gsize offset, + GError **error) +{ + gsize bufsz = 0; + gsize offset_mac_addr = 0x0; + gsize offset_vid_pid = 0x0; + guint8 interface_type = 0x0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* parse the data depending on the interface type */ + if (!fu_common_read_uint8_safe (buf, bufsz, offset, + &interface_type, error)) + return FALSE; + offset++; + switch (interface_type) { + case REDFISH_INTERFACE_TYPE_USB_NETWORK: + case REDFISH_INTERFACE_TYPE_PCI_NETWORK: + offset_vid_pid = 0x00; + break; + case REDFISH_INTERFACE_TYPE_USB_NETWORK_V2: + offset_vid_pid = 0x01; + offset_mac_addr = 0x06; + break; + case REDFISH_INTERFACE_TYPE_PCI_NETWORK_V2: + offset_vid_pid = 0x01; + offset_mac_addr = 0x09; + break; + default: + g_debug ("unknown Network Interface"); + break; + } + + /* MAC address */ + if (offset_mac_addr != 0x0) { + guint8 mac_addr[6] = { 0x0 }; + g_autofree gchar *mac_addr_str = NULL; + if (!fu_memcpy_safe (mac_addr, sizeof(mac_addr), 0x0, /* dst */ + buf, bufsz, offset + offset_mac_addr, /* src */ + sizeof(mac_addr), error)) + return FALSE; + mac_addr_str = fu_redfish_common_buffer_to_mac (mac_addr); + fu_redfish_smbios_set_mac_addr (self, mac_addr_str); + } + + /* VID:PID */ + if (offset_vid_pid != 0x0) { + if (!fu_common_read_uint16_safe (buf, bufsz, offset + offset_vid_pid, + &self->vid, G_LITTLE_ENDIAN, error)) + return FALSE; + if (!fu_common_read_uint16_safe (buf, bufsz, offset + offset_vid_pid + 0x02, + &self->pid, G_LITTLE_ENDIAN, error)) + return FALSE; + } + + /* success */ + return TRUE; +} + +static gboolean +fu_redfish_smbios_parse_over_ip (FuRedfishSmbios *self, + GBytes *fw, gsize offset, + GError **error) +{ + gsize bufsz = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + guint8 hostname_length = 0x0; + guint8 service_ip_address_format = 0x0; + guint16 service_ip_port = 0x0; + guint8 service_ip_address[16] = { 0x0 }; + + /* port */ + if (!fu_common_read_uint16_safe (buf, bufsz, + offset + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, + service_ip_port), + &service_ip_port, G_LITTLE_ENDIAN, error)) + return FALSE; + fu_redfish_smbios_set_port (self, service_ip_port); + + /* IP address */ + if (!fu_memcpy_safe (service_ip_address, sizeof(service_ip_address), 0x0, /* dst */ + buf, bufsz, offset + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, + service_ip_address), /* src */ + sizeof(service_ip_address), error)) + return FALSE; + if (!fu_common_read_uint8_safe (buf, bufsz, + offset + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, + service_ip_address_format), + &service_ip_address_format, error)) + return FALSE; + if (service_ip_address_format == REDFISH_IP_ADDRESS_FORMAT_V4) { + g_autofree gchar *tmp = NULL; + tmp = fu_redfish_common_buffer_to_ipv4 (service_ip_address); + fu_redfish_smbios_set_ip_addr (self, tmp); + } else if (service_ip_address_format == REDFISH_IP_ADDRESS_FORMAT_V6) { + g_autofree gchar *tmp = NULL; + tmp = fu_redfish_common_buffer_to_ipv6 (service_ip_address); + fu_redfish_smbios_set_ip_addr (self, tmp); + } else { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "address format is invalid"); + return FALSE; + } + + /* hostname */ + if (!fu_common_read_uint8_safe (buf, bufsz, + offset + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, + service_hostname_len), + &hostname_length, error)) + return FALSE; + if (hostname_length > 0) { + g_autofree gchar *hostname = g_malloc0 (hostname_length + 1); + if (!fu_memcpy_safe ((guint8 *) hostname, hostname_length, 0x0, /* dst */ + buf, bufsz, offset + sizeof(FuRedfishProtocolOverIp), /* src */ + hostname_length, error)) + return FALSE; + fu_redfish_smbios_set_hostname (self, hostname); + } + + /* success */ + return TRUE; +} + +static gboolean +fu_redfish_smbios_parse (FuFirmware *firmware, + GBytes *fw, + guint64 addr_start, + guint64 addr_end, + FwupdInstallFlags flags, + GError **error) +{ + FuRedfishSmbios *self = FU_REDFISH_SMBIOS (firmware); + gsize bufsz = 0; + gsize offset = 0; + guint8 protocol_rcds = 0; + const guint8 *buf = g_bytes_get_data (fw, &bufsz); + + /* check size */ + if (bufsz < 0x09) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "SMBIOS entry too small: %" G_GSIZE_FORMAT, + bufsz); + return FALSE; + } + + /* check type */ + if (buf[0x0] != REDFISH_SMBIOS_TABLE_TYPE) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "not Management Controller Host Interface"); + return FALSE; + } + if (buf[0x1] != bufsz) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "size of table 0x%x does not match binary 0x%x", + buf[0x1], (guint) bufsz); + return FALSE; + } + + /* check interface type */ + if (buf[0x04] != REDFISH_CONTROLLER_INTERFACE_TYPE_NETWORK_HOST) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "only Network Host Interface supported"); + return FALSE; + } + + /* check length */ + if (buf[0x05] > 0) { + if (!fu_redfish_smbios_parse_interface_data (self, fw, 0x06, error)) + return FALSE; + } + + /* parse protocol records */ + if (!fu_common_read_uint8_safe (buf, bufsz, 0x06 + buf[0x05], + &protocol_rcds, error)) + return FALSE; + offset = 0x07 + buf[0x05]; + g_debug ("protocol_rcds: %u", protocol_rcds); + for (guint i = 0; i < protocol_rcds; i++) { + guint8 protocol_id = 0; + guint8 protocol_sz = 0; + if (!fu_common_read_uint8_safe (buf, bufsz, offset, + &protocol_id, error)) + return FALSE; + if (!fu_common_read_uint8_safe (buf, bufsz, offset + 0x1, + &protocol_sz, error)) + return FALSE; + if (protocol_id == REDFISH_PROTOCOL_REDFISH_OVER_IP) { + if (!fu_redfish_smbios_parse_over_ip (self, fw, offset + 0x2, error)) + return FALSE; + } else { + g_debug ("ignoring protocol ID 0x%02x", protocol_id); + } + offset += protocol_sz + 1; + } + + /* success */ + return TRUE; +} + +static GBytes * +fu_redfish_smbios_write (FuFirmware *firmware, GError **error) +{ + FuRedfishProtocolOverIp proto = { 0x0 }; + FuRedfishSmbios *self = FU_REDFISH_SMBIOS (firmware); + gsize hostname_sz = 0; + g_autoptr(GByteArray) buf = g_byte_array_new (); + + if (self->hostname != NULL) + hostname_sz = strlen (self->hostname); + fu_byte_array_append_uint8 (buf, REDFISH_SMBIOS_TABLE_TYPE); + fu_byte_array_append_uint8 (buf, 0x6D + hostname_sz); /* length */ + fu_byte_array_append_uint16 (buf, 0x1234, G_LITTLE_ENDIAN); /* handle */ + fu_byte_array_append_uint8 (buf, REDFISH_CONTROLLER_INTERFACE_TYPE_NETWORK_HOST); + fu_byte_array_append_uint8 (buf, 0x09); /* iface datalen */ + fu_byte_array_append_uint8 (buf, REDFISH_INTERFACE_TYPE_USB_NETWORK); /* iface */ + fu_byte_array_append_uint16 (buf, self->vid, G_LITTLE_ENDIAN); /* iface:VID */ + fu_byte_array_append_uint16 (buf, self->pid, G_LITTLE_ENDIAN); /* iface:PID */ + fu_byte_array_append_uint8 (buf, 0x02); /* iface:serialsz */ + fu_byte_array_append_uint8 (buf, 0x03); /* iType */ + fu_byte_array_append_uint8 (buf, 'S'); /* iface:serial */ + fu_byte_array_append_uint8 (buf, 'n'); /* iface:serial */ + fu_byte_array_append_uint8 (buf, 0x1); /* nr protocol rcds */ + + /* protocol record */ + fu_byte_array_append_uint8 (buf, REDFISH_PROTOCOL_REDFISH_OVER_IP); + fu_byte_array_append_uint8 (buf, sizeof(FuRedfishProtocolOverIp) + hostname_sz); + if (!fu_common_write_uint16_safe ((guint8 *) &proto, sizeof(proto), + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, service_ip_port), + self->port, G_LITTLE_ENDIAN, error)) + return NULL; + if (!fu_common_write_uint8_safe ((guint8 *) &proto, sizeof(proto), + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, service_ip_address_format), + REDFISH_IP_ADDRESS_FORMAT_V4, error)) + return NULL; + if (!fu_common_write_uint8_safe ((guint8 *) &proto, sizeof(proto), + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, service_ip_assignment_type), + REDFISH_IP_ASSIGNMENT_TYPE_STATIC, error)) + return NULL; + if (self->hostname != NULL) + hostname_sz = strlen (self->hostname); + if (hostname_sz > 0) { + if (!fu_common_write_uint8_safe ((guint8 *) &proto, sizeof(proto), + G_STRUCT_OFFSET(FuRedfishProtocolOverIp, service_hostname_len), + hostname_sz, error)) { + g_prefix_error (error, "cannot write length: "); + return NULL; + } + } + g_byte_array_append (buf, (guint8 *) &proto, sizeof(proto)); + if (hostname_sz > 0) + g_byte_array_append (buf, (guint8 *) self->hostname, hostname_sz); + return g_byte_array_free_to_bytes (g_steal_pointer (&buf)); +} + +static void +fu_redfish_smbios_finalize (GObject *object) +{ + FuRedfishSmbios *self = FU_REDFISH_SMBIOS (object); + g_free (self->hostname); + g_free (self->mac_addr); + g_free (self->ip_addr); + G_OBJECT_CLASS (fu_redfish_smbios_parent_class)->finalize (object); +} + +static void +fu_redfish_smbios_init (FuRedfishSmbios *self) +{ +} + +static void +fu_redfish_smbios_class_init (FuRedfishSmbiosClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + FuFirmwareClass *klass_firmware = FU_FIRMWARE_CLASS (klass); + object_class->finalize = fu_redfish_smbios_finalize; + klass_firmware->parse = fu_redfish_smbios_parse; + klass_firmware->write = fu_redfish_smbios_write; + klass_firmware->build = fu_redfish_smbios_build; + klass_firmware->export = fu_redfish_smbios_export; +} + +FuRedfishSmbios * +fu_redfish_smbios_new (void) +{ + return FU_REDFISH_SMBIOS (g_object_new (FU_TYPE_REDFISH_SMBIOS, NULL)); +} diff --git a/plugins/redfish/fu-redfish-smbios.h b/plugins/redfish/fu-redfish-smbios.h new file mode 100644 index 000000000..b54bb6a22 --- /dev/null +++ b/plugins/redfish/fu-redfish-smbios.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_REDFISH_SMBIOS (fu_redfish_smbios_get_type ()) +G_DECLARE_FINAL_TYPE (FuRedfishSmbios, fu_redfish_smbios, FU, REDFISH_SMBIOS, FuFirmware) + +FuRedfishSmbios *fu_redfish_smbios_new (void); + +guint16 fu_redfish_smbios_get_port (FuRedfishSmbios *self); +const gchar *fu_redfish_smbios_get_hostname (FuRedfishSmbios *self); +const gchar *fu_redfish_smbios_get_ip_addr (FuRedfishSmbios *self); diff --git a/plugins/redfish/fu-self-test.c b/plugins/redfish/fu-self-test.c index bc4bdbef3..c423a9f95 100644 --- a/plugins/redfish/fu-self-test.c +++ b/plugins/redfish/fu-self-test.c @@ -17,11 +17,14 @@ fu_test_redfish_common_func (void) 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; g_autofree gchar *ipv4 = NULL; g_autofree gchar *ipv6 = NULL; + g_autofree gchar *maca = NULL; ipv4 = fu_redfish_common_buffer_to_ipv4 (buf); g_assert_cmpstr (ipv4, ==, "0.1.2.3"); ipv6 = fu_redfish_common_buffer_to_ipv6 (buf); g_assert_cmpstr (ipv6, ==, "00010203:04050607:08090a0b:0c0d0e0f"); + maca = fu_redfish_common_buffer_to_mac (buf); + g_assert_cmpstr (maca, ==, "00:01:02:03:04:05"); } int diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index 1c6fe0d71..61c2e42f3 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -9,7 +9,8 @@ shared_module('fu_plugin_redfish', sources : [ 'fu-plugin-redfish.c', 'fu-redfish-client.c', - 'fu-redfish-common.c', + 'fu-redfish-common.c', # fuzzing + 'fu-redfish-smbios.c', # fuzzing ], include_directories : [ root_incdir, @@ -41,6 +42,7 @@ if get_option('tests') 'fu-self-test.c', 'fu-redfish-client.c', 'fu-redfish-common.c', + 'fu-redfish-smbios.c', ], include_directories : [ root_incdir, diff --git a/src/fuzzing/firmware/redfish-smbios.bin b/src/fuzzing/firmware/redfish-smbios.bin new file mode 100644 index 000000000..048ab6c57 Binary files /dev/null and b/src/fuzzing/firmware/redfish-smbios.bin differ diff --git a/src/fuzzing/generate.py b/src/fuzzing/generate.py index 9ef163d41..5754e53cf 100755 --- a/src/fuzzing/generate.py +++ b/src/fuzzing/generate.py @@ -31,6 +31,7 @@ if __name__ == "__main__": ("ifd-no-bios.builder.xml", "ifd-no-bios.bin"), ("ihex.builder.xml", "ihex.hex"), ("pixart.builder.xml", "pixart.bin"), + ("redfish-smbios.builder.xml", "redfish-smbios.bin"), ("rmi-0x.builder.xml", "synaptics-rmi-0x.img"), ("rmi-10.builder.xml", "synaptics-rmi-10.img"), ("solokey.builder.xml", "solokey.json"), diff --git a/src/fuzzing/redfish-smbios.builder.xml b/src/fuzzing/redfish-smbios.builder.xml new file mode 100644 index 000000000..6368a0395 --- /dev/null +++ b/src/fuzzing/redfish-smbios.builder.xml @@ -0,0 +1,7 @@ + + 0x1234 + localhost + 0.0.0.0 + 0x9876 + 0x5678 +