firmware (and crypto) patches
- add the tls-cipher-suites object, - add the ability to QOM objects to produce data consumable by the fw_cfg device, - let the tls-cipher-suites object implement the FW_CFG_DATA_GENERATOR interface. This is required by EDK2 'HTTPS Boot' feature of OVMF to tell the guest which TLS ciphers it can use. CI jobs results: https://travis-ci.org/github/philmd/qemu/builds/704724619 https://gitlab.com/philmd/qemu/-/pipelines/162938106 https://cirrus-ci.com/build/4682977303068672 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAl8AsDQACgkQ4+MsLN6t wN4HLA//Sxi7iYWp3OygX1F7A9XpWxuWNVjThBJzao00y0qxWQ7G6l/YTDeNYOoD dE/HsyUd3QtvC6/c79zoqyOb5m+WtQNsQmHAO4LZdR16TPNvTdCZ2lNgWYRIjuHJ obvYy2ingKpnlzd5V1bioTlUw0AOchk86pMnTVAsoKPXWqsOrPB+PYmE9tFRxqVY 5WVW7rnhtcJ05ajeIWhgndhW7fM4lvoWdZyctTIhWttQ9WkhyKAYKHQrmgOcsbUp soOfK9oHRH1XuUsC0SHpPmUQbp/c5cyCS1D7nDuIe/lPNNfWCVeUKkny495Vgj4d nK6MI1PQ4Bw2VBfMMxO4dXl2rnzlVjSnXXUP56IdfZHlOr+5gPh7uZvfZXN3AmHC km9MBt2IWrDYAriMwHhqumzHMIFmNVdqdXaYZYzagwwFzy8VNLgzQEFQYHsIXtl3 7pfvZVtIbSfXFGfktY3vu4sBZNAAk3mAOc04faF3CuTvXp5m0Duc0boO38eLDCbp 5mV2uEUJ9zQzcSoLqfLGiYCBFX9C8XdjdX+u9gMHhNb04y5c6r/zZZKpH7ZfwEc1 WdwXzEor+h3yW06dV1WdOGlMUqVt3Xx9GaJBW57XbdMQQ2O2m+TfMcYLeVLsXtvf aHUKOZdBxRKFcbA7zARhZ4xyzNQVddz3+aTGpzpP/xIL4TXrzHQ= =QArU -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/fw_cfg-20200704' into staging firmware (and crypto) patches - add the tls-cipher-suites object, - add the ability to QOM objects to produce data consumable by the fw_cfg device, - let the tls-cipher-suites object implement the FW_CFG_DATA_GENERATOR interface. This is required by EDK2 'HTTPS Boot' feature of OVMF to tell the guest which TLS ciphers it can use. CI jobs results: https://travis-ci.org/github/philmd/qemu/builds/704724619 https://gitlab.com/philmd/qemu/-/pipelines/162938106 https://cirrus-ci.com/build/4682977303068672 # gpg: Signature made Sat 04 Jul 2020 17:37:08 BST # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd-gitlab/tags/fw_cfg-20200704: crypto/tls-cipher-suites: Produce fw_cfg consumable blob softmmu/vl: Allow -fw_cfg 'gen_id' option to use the 'etc/' namespace softmmu/vl: Let -fw_cfg option take a 'gen_id' argument hw/nvram/fw_cfg: Add the FW_CFG_DATA_GENERATOR interface crypto: Add tls-cipher-suites object Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
aecdfcc3f8
@ -13,6 +13,7 @@ crypto-obj-y += cipher.o
|
||||
crypto-obj-$(CONFIG_AF_ALG) += afalg.o
|
||||
crypto-obj-$(CONFIG_AF_ALG) += cipher-afalg.o
|
||||
crypto-obj-$(CONFIG_AF_ALG) += hash-afalg.o
|
||||
crypto-obj-$(CONFIG_GNUTLS) += tls-cipher-suites.o
|
||||
crypto-obj-y += tlscreds.o
|
||||
crypto-obj-y += tlscredsanon.o
|
||||
crypto-obj-y += tlscredspsk.o
|
||||
|
126
crypto/tls-cipher-suites.c
Normal file
126
crypto/tls-cipher-suites.c
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* QEMU TLS Cipher Suites
|
||||
*
|
||||
* Copyright (c) 2018-2020 Red Hat, Inc.
|
||||
*
|
||||
* Author: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "crypto/tlscreds.h"
|
||||
#include "crypto/tls-cipher-suites.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
* IANA registered TLS ciphers:
|
||||
* https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t data[2];
|
||||
} QEMU_PACKED IANA_TLS_CIPHER;
|
||||
|
||||
GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||
gnutls_priority_t pcache;
|
||||
GByteArray *byte_array;
|
||||
const char *err;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
trace_qcrypto_tls_cipher_suite_priority(creds->priority);
|
||||
ret = gnutls_priority_init(&pcache, creds->priority, &err);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Syntax error using priority '%s': %s",
|
||||
creds->priority, gnutls_strerror(ret));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
byte_array = g_byte_array_new();
|
||||
|
||||
for (i = 0;; i++) {
|
||||
int ret;
|
||||
unsigned idx;
|
||||
const char *name;
|
||||
IANA_TLS_CIPHER cipher;
|
||||
gnutls_protocol_t protocol;
|
||||
const char *version;
|
||||
|
||||
ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx);
|
||||
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
||||
break;
|
||||
}
|
||||
if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
name = gnutls_cipher_suite_info(idx, (unsigned char *)&cipher,
|
||||
NULL, NULL, NULL, &protocol);
|
||||
if (name == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
version = gnutls_protocol_get_name(protocol);
|
||||
g_byte_array_append(byte_array, cipher.data, 2);
|
||||
trace_qcrypto_tls_cipher_suite_info(cipher.data[0],
|
||||
cipher.data[1],
|
||||
version, name);
|
||||
}
|
||||
trace_qcrypto_tls_cipher_suite_count(byte_array->len);
|
||||
gnutls_priority_deinit(pcache);
|
||||
|
||||
return byte_array;
|
||||
}
|
||||
|
||||
static void qcrypto_tls_cipher_suites_complete(UserCreatable *uc,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(uc);
|
||||
|
||||
if (!creds->priority) {
|
||||
error_setg(errp, "'priority' property is not set");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static GByteArray *qcrypto_tls_cipher_suites_fw_cfg_gen_data(Object *obj,
|
||||
Error **errp)
|
||||
{
|
||||
return qcrypto_tls_cipher_suites_get_data(QCRYPTO_TLS_CIPHER_SUITES(obj),
|
||||
errp);
|
||||
}
|
||||
|
||||
static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(oc);
|
||||
|
||||
ucc->complete = qcrypto_tls_cipher_suites_complete;
|
||||
fwgc->get_data = qcrypto_tls_cipher_suites_fw_cfg_gen_data;
|
||||
}
|
||||
|
||||
static const TypeInfo qcrypto_tls_cipher_suites_info = {
|
||||
.parent = TYPE_QCRYPTO_TLS_CREDS,
|
||||
.name = TYPE_QCRYPTO_TLS_CIPHER_SUITES,
|
||||
.instance_size = sizeof(QCryptoTLSCreds),
|
||||
.class_size = sizeof(QCryptoTLSCredsClass),
|
||||
.class_init = qcrypto_tls_cipher_suites_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ TYPE_FW_CFG_DATA_GENERATOR_INTERFACE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void qcrypto_tls_cipher_suites_register_types(void)
|
||||
{
|
||||
type_register_static(&qcrypto_tls_cipher_suites_info);
|
||||
}
|
||||
|
||||
type_init(qcrypto_tls_cipher_suites_register_types);
|
@ -21,3 +21,8 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
|
||||
# tlssession.c
|
||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
|
||||
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
||||
|
||||
# tls-cipher-suites.c
|
||||
qcrypto_tls_cipher_suite_priority(const char *name) "priority: %s"
|
||||
qcrypto_tls_cipher_suite_info(uint8_t data0, uint8_t data1, const char *version, const char *name) "data=[0x%02x,0x%02x] version=%s name=%s"
|
||||
qcrypto_tls_cipher_suite_count(unsigned count) "count: %u"
|
||||
|
@ -219,7 +219,7 @@ To check the result, read the "control" field:
|
||||
|
||||
= Externally Provided Items =
|
||||
|
||||
As of v2.4, "file" fw_cfg items (i.e., items with selector keys above
|
||||
Since v2.4, "file" fw_cfg items (i.e., items with selector keys above
|
||||
FW_CFG_FILE_FIRST, and with a corresponding entry in the fw_cfg file
|
||||
directory structure) may be inserted via the QEMU command line, using
|
||||
the following syntax:
|
||||
@ -230,6 +230,13 @@ Or
|
||||
|
||||
-fw_cfg [name=]<item_name>,string=<string>
|
||||
|
||||
Since v5.1, QEMU allows some objects to generate fw_cfg-specific content,
|
||||
the content is then associated with a "file" item using the 'gen_id' option
|
||||
in the command line, using the following syntax:
|
||||
|
||||
-object <generator-type>,id=<generated_id>,[generator-specific-options] \
|
||||
-fw_cfg [name=]<item_name>,gen_id=<generated_id>
|
||||
|
||||
See QEMU man page for more documentation.
|
||||
|
||||
Using item_name with plain ASCII characters only is recommended.
|
||||
@ -251,4 +258,8 @@ Prefix "opt/org.qemu/" is reserved for QEMU itself.
|
||||
Use of names not beginning with "opt/" is potentially dangerous and
|
||||
entirely unsupported. QEMU will warn if you try.
|
||||
|
||||
Use of names not beginning with "opt/" is tolerated with 'gen_id' (that
|
||||
is, the warning is suppressed), but you must know exactly what you're
|
||||
doing.
|
||||
|
||||
All externally provided fw_cfg items are read-only to the guest.
|
||||
|
@ -1032,6 +1032,35 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
|
||||
const char *gen_id, Error **errp)
|
||||
{
|
||||
FWCfgDataGeneratorClass *klass;
|
||||
Error *local_err = NULL;
|
||||
GByteArray *array;
|
||||
Object *obj;
|
||||
gsize size;
|
||||
|
||||
obj = object_resolve_path_component(object_get_objects_root(), gen_id);
|
||||
if (!obj) {
|
||||
error_setg(errp, "Cannot find object ID '%s'", gen_id);
|
||||
return;
|
||||
}
|
||||
if (!object_dynamic_cast(obj, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)) {
|
||||
error_setg(errp, "Object ID '%s' is not a '%s' subclass",
|
||||
gen_id, TYPE_FW_CFG_DATA_GENERATOR_INTERFACE);
|
||||
return;
|
||||
}
|
||||
klass = FW_CFG_DATA_GENERATOR_GET_CLASS(obj);
|
||||
array = klass->get_data(obj, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
size = array->len;
|
||||
fw_cfg_add_file(s, filename, g_byte_array_free(array, TRUE), size);
|
||||
}
|
||||
|
||||
static void fw_cfg_machine_reset(void *opaque)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
@ -1333,12 +1362,18 @@ static const TypeInfo fw_cfg_mem_info = {
|
||||
.class_init = fw_cfg_mem_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo fw_cfg_data_generator_interface_info = {
|
||||
.parent = TYPE_INTERFACE,
|
||||
.name = TYPE_FW_CFG_DATA_GENERATOR_INTERFACE,
|
||||
.class_size = sizeof(FWCfgDataGeneratorClass),
|
||||
};
|
||||
|
||||
static void fw_cfg_register_types(void)
|
||||
{
|
||||
type_register_static(&fw_cfg_info);
|
||||
type_register_static(&fw_cfg_io_info);
|
||||
type_register_static(&fw_cfg_mem_info);
|
||||
type_register_static(&fw_cfg_data_generator_interface_info);
|
||||
}
|
||||
|
||||
type_init(fw_cfg_register_types)
|
||||
|
39
include/crypto/tls-cipher-suites.h
Normal file
39
include/crypto/tls-cipher-suites.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* QEMU TLS Cipher Suites Registry (RFC8447)
|
||||
*
|
||||
* Copyright (c) 2018-2020 Red Hat, Inc.
|
||||
*
|
||||
* Author: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_TLSCIPHERSUITES_H
|
||||
#define QCRYPTO_TLSCIPHERSUITES_H
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "crypto/tlscreds.h"
|
||||
|
||||
#define TYPE_QCRYPTO_TLS_CIPHER_SUITES "tls-cipher-suites"
|
||||
#define QCRYPTO_TLS_CIPHER_SUITES(obj) \
|
||||
OBJECT_CHECK(QCryptoTLSCipherSuites, (obj), TYPE_QCRYPTO_TLS_CIPHER_SUITES)
|
||||
|
||||
typedef struct QCryptoTLSCipherSuites {
|
||||
/* <private> */
|
||||
QCryptoTLSCreds parent_obj;
|
||||
/* <public> */
|
||||
} QCryptoTLSCipherSuites;
|
||||
|
||||
/**
|
||||
* qcrypto_tls_cipher_suites_get_data:
|
||||
* @obj: pointer to a TLS cipher suites object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Returns: reference to a byte array containing the data.
|
||||
* The caller should release the reference when no longer
|
||||
* required.
|
||||
*/
|
||||
GByteArray *qcrypto_tls_cipher_suites_get_data(QCryptoTLSCipherSuites *obj,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_TLSCIPHERSUITES_H */
|
@ -9,11 +9,36 @@
|
||||
#define TYPE_FW_CFG "fw_cfg"
|
||||
#define TYPE_FW_CFG_IO "fw_cfg_io"
|
||||
#define TYPE_FW_CFG_MEM "fw_cfg_mem"
|
||||
#define TYPE_FW_CFG_DATA_GENERATOR_INTERFACE "fw_cfg-data-generator"
|
||||
|
||||
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
|
||||
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
|
||||
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
|
||||
|
||||
#define FW_CFG_DATA_GENERATOR_CLASS(class) \
|
||||
OBJECT_CLASS_CHECK(FWCfgDataGeneratorClass, (class), \
|
||||
TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)
|
||||
#define FW_CFG_DATA_GENERATOR_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(FWCfgDataGeneratorClass, (obj), \
|
||||
TYPE_FW_CFG_DATA_GENERATOR_INTERFACE)
|
||||
|
||||
typedef struct FWCfgDataGeneratorClass {
|
||||
/*< private >*/
|
||||
InterfaceClass parent_class;
|
||||
/*< public >*/
|
||||
|
||||
/**
|
||||
* get_data:
|
||||
* @obj: the object implementing this interface
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Returns: reference to a byte array containing the data.
|
||||
* The caller should release the reference when no longer
|
||||
* required.
|
||||
*/
|
||||
GByteArray *(*get_data)(Object *obj, Error **errp);
|
||||
} FWCfgDataGeneratorClass;
|
||||
|
||||
typedef struct fw_cfg_file FWCfgFile;
|
||||
|
||||
#define FW_CFG_ORDER_OVERRIDE_VGA 70
|
||||
@ -263,6 +288,24 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
|
||||
void *fw_cfg_modify_file(FWCfgState *s, const char *filename, void *data,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* fw_cfg_add_from_generator:
|
||||
* @s: fw_cfg device being modified
|
||||
* @filename: name of new fw_cfg file item
|
||||
* @gen_id: name of object implementing FW_CFG_DATA_GENERATOR interface
|
||||
* @errp: pointer to a NULL initialized error object
|
||||
*
|
||||
* Add a new NAMED fw_cfg item with the content generated from the
|
||||
* @gen_id object. The data generated by the @gen_id object is copied
|
||||
* into the data structure of the fw_cfg device.
|
||||
* The next available (unused) selector key starting at FW_CFG_FILE_FIRST
|
||||
* will be used; also, a new entry will be added to the file directory
|
||||
* structure residing at key value FW_CFG_FILE_DIR, containing the item name,
|
||||
* data size, and assigned selector key value.
|
||||
*/
|
||||
void fw_cfg_add_from_generator(FWCfgState *s, const char *filename,
|
||||
const char *gen_id, Error **errp);
|
||||
|
||||
FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
|
||||
AddressSpace *dma_as);
|
||||
FWCfgState *fw_cfg_init_io(uint32_t iobase);
|
||||
|
@ -4579,6 +4579,43 @@ SRST
|
||||
string as described at
|
||||
https://gnutls.org/manual/html_node/Priority-Strings.html.
|
||||
|
||||
``-object tls-cipher-suites,id=id,priority=priority``
|
||||
Creates a TLS cipher suites object, which can be used to control
|
||||
the TLS cipher/protocol algorithms that applications are permitted
|
||||
to use.
|
||||
|
||||
The ``id`` parameter is a unique ID which frontends will use to
|
||||
access the ordered list of permitted TLS cipher suites from the
|
||||
host.
|
||||
|
||||
The ``priority`` parameter allows to override the global default
|
||||
priority used by gnutls. This can be useful if the system
|
||||
administrator needs to use a weaker set of crypto priorities for
|
||||
QEMU without potentially forcing the weakness onto all
|
||||
applications. Or conversely if one wants wants a stronger
|
||||
default for QEMU than for all other applications, they can do
|
||||
this through this parameter. Its format is a gnutls priority
|
||||
string as described at
|
||||
https://gnutls.org/manual/html_node/Priority-Strings.html.
|
||||
|
||||
An example of use of this object is to control UEFI HTTPS Boot.
|
||||
The tls-cipher-suites object exposes the ordered list of permitted
|
||||
TLS cipher suites from the host side to the guest firmware, via
|
||||
fw_cfg. The list is represented as an array of IANA_TLS_CIPHER
|
||||
objects. The firmware uses the IANA_TLS_CIPHER array for configuring
|
||||
guest-side TLS.
|
||||
|
||||
In the following example, the priority at which the host-side policy
|
||||
is retrieved is given by the ``priority`` property.
|
||||
Given that QEMU uses GNUTLS, ``priority=@SYSTEM`` may be used to
|
||||
refer to /etc/crypto-policies/back-ends/gnutls.config.
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
# |qemu_system| \
|
||||
-object tls-cipher-suites,id=mysuite0,priority=@SYSTEM \
|
||||
-fw_cfg name=etc/edk2/https/ciphers,gen_id=mysuite0
|
||||
|
||||
``-object filter-buffer,id=id,netdev=netdevid,interval=t[,queue=all|rx|tx][,status=on|off][,position=head|tail|id=<id>][,insert=behind|before]``
|
||||
Interval t can't be 0, this filter batches the packet delivery:
|
||||
all packets arriving in a given interval on netdev netdevid are
|
||||
|
37
softmmu/vl.c
37
softmmu/vl.c
@ -489,6 +489,11 @@ static QemuOptsList qemu_fw_cfg_opts = {
|
||||
.name = "string",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Sets content of the blob to be inserted from a string",
|
||||
}, {
|
||||
.name = "gen_id",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Sets id of the object generating the fw_cfg blob "
|
||||
"to be inserted",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
@ -2020,7 +2025,7 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
||||
{
|
||||
gchar *buf;
|
||||
size_t size;
|
||||
const char *name, *file, *str;
|
||||
const char *name, *file, *str, *gen_id;
|
||||
FWCfgState *fw_cfg = (FWCfgState *) opaque;
|
||||
|
||||
if (fw_cfg == NULL) {
|
||||
@ -2030,14 +2035,13 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
||||
name = qemu_opt_get(opts, "name");
|
||||
file = qemu_opt_get(opts, "file");
|
||||
str = qemu_opt_get(opts, "string");
|
||||
gen_id = qemu_opt_get(opts, "gen_id");
|
||||
|
||||
/* we need name and either a file or the content string */
|
||||
if (!(nonempty_str(name) && (nonempty_str(file) || nonempty_str(str)))) {
|
||||
error_setg(errp, "invalid argument(s)");
|
||||
return -1;
|
||||
}
|
||||
if (nonempty_str(file) && nonempty_str(str)) {
|
||||
error_setg(errp, "file and string are mutually exclusive");
|
||||
/* we need the name, and exactly one of: file, content string, gen_id */
|
||||
if (!nonempty_str(name) ||
|
||||
nonempty_str(file) + nonempty_str(str) + nonempty_str(gen_id) != 1) {
|
||||
error_setg(errp, "name, plus exactly one of file,"
|
||||
" string and gen_id, are needed");
|
||||
return -1;
|
||||
}
|
||||
if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) {
|
||||
@ -2045,13 +2049,28 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp)
|
||||
FW_CFG_MAX_FILE_PATH - 1);
|
||||
return -1;
|
||||
}
|
||||
if (strncmp(name, "opt/", 4) != 0) {
|
||||
if (nonempty_str(gen_id)) {
|
||||
/*
|
||||
* In this particular case where the content is populated
|
||||
* internally, the "etc/" namespace protection is relaxed,
|
||||
* so do not emit a warning.
|
||||
*/
|
||||
} else if (strncmp(name, "opt/", 4) != 0) {
|
||||
warn_report("externally provided fw_cfg item names "
|
||||
"should be prefixed with \"opt/\"");
|
||||
}
|
||||
if (nonempty_str(str)) {
|
||||
size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */
|
||||
buf = g_memdup(str, size);
|
||||
} else if (nonempty_str(gen_id)) {
|
||||
Error *local_err = NULL;
|
||||
|
||||
fw_cfg_add_from_generator(fw_cfg, name, gen_id, errp);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
GError *err = NULL;
|
||||
if (!g_file_get_contents(file, &buf, &size, &err)) {
|
||||
|
Loading…
Reference in New Issue
Block a user