mirror of
https://git.proxmox.com/git/fwupd
synced 2025-06-24 18:45:47 +00:00
redfish: Split out the SMBIOS table parsing
This makes it more robust against corrupted data, and also adds support for fuzzing.
This commit is contained in:
parent
5acee72213
commit
6ff0ae2bc4
@ -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"),
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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: */
|
||||
|
@ -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);
|
||||
|
428
plugins/redfish/fu-redfish-smbios.c
Normal file
428
plugins/redfish/fu-redfish-smbios.c
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#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));
|
||||
}
|
18
plugins/redfish/fu-redfish-smbios.h
Normal file
18
plugins/redfish/fu-redfish-smbios.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fwupdplugin.h>
|
||||
|
||||
#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);
|
@ -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
|
||||
|
@ -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,
|
||||
|
BIN
src/fuzzing/firmware/redfish-smbios.bin
Normal file
BIN
src/fuzzing/firmware/redfish-smbios.bin
Normal file
Binary file not shown.
@ -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"),
|
||||
|
7
src/fuzzing/redfish-smbios.builder.xml
Normal file
7
src/fuzzing/redfish-smbios.builder.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<firmware gtype="FuRedfishSmbios">
|
||||
<port>0x1234</port>
|
||||
<hostname>localhost</hostname>
|
||||
<ip_addr>0.0.0.0</ip_addr>
|
||||
<vid>0x9876</vid>
|
||||
<pid>0x5678</pid>
|
||||
</firmware>
|
Loading…
Reference in New Issue
Block a user