qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Ani Sinha <anisinha@redhat.com>
To: Igor Mammedov <imammedo@redhat.com>
Cc: qemu-devel@nongnu.org, peter.maydell@linaro.org,
	pbonzini@redhat.com,  mst@redhat.com, gaosong@loongson.cn,
	alistair.francis@wdc.com,  palmer@dabbelt.com,
	bin.meng@windriver.com, liwei1518@gmail.com,
	 dbarboza@ventanamicro.com, zhiwei_liu@linux.alibaba.com,
	philmd@linaro.org,  wangyanan55@huawei.com, eblake@redhat.com,
	armbru@redhat.com,  qemu-arm@nongnu.org, qemu-riscv@nongnu.org,
	f.ebner@proxmox.com
Subject: Re: [PATCH 07/19] smbios: avoid mangling user provided tables
Date: Mon, 4 Mar 2024 15:25:11 +0530 (IST)	[thread overview]
Message-ID: <bb38e2e8-d9dd-d552-469e-8d47196393c1@redhat.com> (raw)
In-Reply-To: <20240227154749.1818189-8-imammedo@redhat.com>



On Tue, 27 Feb 2024, Igor Mammedov wrote:

> currently smbios_entry_add() preserves internally '-smbios type='
> options but tables provided with '-smbios file=' are stored directly
> into blob that eventually will be exposed to VM. And then later
> QEMU adds default/'-smbios type' entries on top into the same blob.
>
> It makes impossible to generate tables more than once, hence
> 'immutable' guard was used.
> Make it possible to regenerate final blob by storing user provided
> blobs into a dedicated area (usr_blobs) and then copy it when
> composing final blob. Which also makes handling of -smbios
> options consistent.
>
> As side effect of this and previous commits there is no need to
> generate legacy smbios_entries at the time options are parsed.
> Instead compose smbios_entries on demand from  usr_blobs like
> it is done for non-legacy SMBIOS tables.
>

This patch is very dense and even after taking several iterations through
it, I am not confident that I have not missed anything.

> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
>  hw/smbios/smbios.c | 179 +++++++++++++++++++++++----------------------
>  1 file changed, 92 insertions(+), 87 deletions(-)
>
> diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c
> index c46fc93357..aa2cc5bdbd 100644
> --- a/hw/smbios/smbios.c
> +++ b/hw/smbios/smbios.c
> @@ -57,6 +57,14 @@ static size_t smbios_entries_len;
>  static bool smbios_uuid_encoded = true;
>  /* end: legacy structures & constants for <= 2.0 machines */
>
> +/*
> + * SMBIOS tables provided by user with '-smbios file=<foo>' option
> + */
> +uint8_t *usr_blobs;
> +size_t usr_blobs_len;
> +static GArray *usr_blobs_sizes;
> +static unsigned usr_table_max;
> +static unsigned usr_table_cnt;
>
>  uint8_t *smbios_tables;
>  size_t smbios_tables_len;
> @@ -67,7 +75,6 @@ static SmbiosEntryPointType smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_32;
>  static SmbiosEntryPoint ep;
>
>  static int smbios_type4_count = 0;
> -static bool smbios_immutable;
>  static bool smbios_have_defaults;
>  static uint32_t smbios_cpuid_version, smbios_cpuid_features;
>
> @@ -569,9 +576,8 @@ static void smbios_build_type_1_fields(void)
>
>  uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
>  {
> -    /* drop unwanted version of command-line file blob(s) */
> -    g_free(smbios_tables);
> -    smbios_tables = NULL;
> +    int i;
> +    size_t usr_offset;
>
>      /* also complain if fields were given for types > 1 */
>      if (find_next_bit(have_fields_bitmap,
> @@ -581,12 +587,33 @@ uint8_t *smbios_get_table_legacy(uint32_t expected_t4_count, size_t *length)
>          exit(1);
>      }
>
> -    if (!smbios_immutable) {
> -        smbios_build_type_0_fields();
> -        smbios_build_type_1_fields();
> -        smbios_validate_table(expected_t4_count);
> -        smbios_immutable = true;
> +    g_free(smbios_entries);
> +    smbios_entries_len = sizeof(uint16_t);
> +    smbios_entries = g_malloc0(smbios_entries_len);
> +
> +    for (i = 0, usr_offset = 0; usr_blobs_sizes && i < usr_blobs_sizes->len;
> +         i++)
> +    {
> +        struct smbios_table *table;
> +        struct smbios_structure_header *header;
> +        size_t size = g_array_index(usr_blobs_sizes, size_t, i);
> +
> +        header = (struct smbios_structure_header *)(usr_blobs + usr_offset);
> +        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
> +                                                   size + sizeof(*table));
> +        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
> +        table->header.type = SMBIOS_TABLE_ENTRY;
> +        table->header.length = cpu_to_le16(sizeof(*table) + size);
> +        memcpy(table->data, header, size);
> +        smbios_entries_len += sizeof(*table) + size;
> +        (*(uint16_t *)smbios_entries) =
> +            cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
> +        usr_offset += size;
>      }
> +
> +    smbios_build_type_0_fields();
> +    smbios_build_type_1_fields();
> +    smbios_validate_table(expected_t4_count);
>      *length = smbios_entries_len;
>      return smbios_entries;
>  }
> @@ -1094,67 +1121,67 @@ void smbios_get_tables(MachineState *ms,
>  {
>      unsigned i, dimm_cnt, offset;
>
> -    /* drop unwanted (legacy) version of command-line file blob(s) */
> -    g_free(smbios_entries);
> -    smbios_entries = NULL;
> +    g_free(smbios_tables);
> +    smbios_tables = g_memdup2(usr_blobs, usr_blobs_len);

Why can't we do a memdup even for the legacy case instead of memcpy?

Secondly, here and other places we should check for NULL returns.
https://docs.gtk.org/glib/func.memdup2.html
return from memdup2 can be null.


> +    smbios_tables_len = usr_blobs_len;
> +    smbios_table_max = usr_table_max;
> +    smbios_table_cnt = usr_table_cnt;
>
> -    if (!smbios_immutable) {
> -        smbios_build_type_0_table();
> -        smbios_build_type_1_table();
> -        smbios_build_type_2_table();
> -        smbios_build_type_3_table();
> +    smbios_build_type_0_table();
> +    smbios_build_type_1_table();
> +    smbios_build_type_2_table();
> +    smbios_build_type_3_table();
>
> -        assert(ms->smp.sockets >= 1);
> +    assert(ms->smp.sockets >= 1);
>
> -        for (i = 0; i < ms->smp.sockets; i++) {
> -            smbios_build_type_4_table(ms, i);
> -        }
> +    for (i = 0; i < ms->smp.sockets; i++) {
> +        smbios_build_type_4_table(ms, i);
> +    }
>
> -        smbios_build_type_8_table();
> -        smbios_build_type_11_table();
> +    smbios_build_type_8_table();
> +    smbios_build_type_11_table();
>
>  #define MAX_DIMM_SZ (16 * GiB)
>  #define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \
>                                          : ((current_machine->ram_size - 1) % MAX_DIMM_SZ) + 1)
>
> -        dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
> +    dimm_cnt = QEMU_ALIGN_UP(current_machine->ram_size, MAX_DIMM_SZ) /
> +               MAX_DIMM_SZ;
>
> -        /*
> -         * The offset determines if we need to keep additional space between
> -         * table 17 and table 19 header handle numbers so that they do
> -         * not overlap. For example, for a VM with larger than 8 TB guest
> -         * memory and DIMM like chunks of 16 GiB, the default space between
> -         * the two tables (T19_BASE - T17_BASE = 512) is not enough.
> -         */
> -        offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
> -                 dimm_cnt - (T19_BASE - T17_BASE) : 0;
> +    /*
> +     * The offset determines if we need to keep additional space between
> +     * table 17 and table 19 header handle numbers so that they do
> +     * not overlap. For example, for a VM with larger than 8 TB guest
> +     * memory and DIMM like chunks of 16 GiB, the default space between
> +     * the two tables (T19_BASE - T17_BASE = 512) is not enough.
> +     */
> +    offset = (dimm_cnt > (T19_BASE - T17_BASE)) ? \
> +             dimm_cnt - (T19_BASE - T17_BASE) : 0;
>
> -        smbios_build_type_16_table(dimm_cnt);
> +    smbios_build_type_16_table(dimm_cnt);
>
> -        for (i = 0; i < dimm_cnt; i++) {
> -            smbios_build_type_17_table(i, GET_DIMM_SZ);
> -        }
> +    for (i = 0; i < dimm_cnt; i++) {
> +        smbios_build_type_17_table(i, GET_DIMM_SZ);
> +    }
>
> -        for (i = 0; i < mem_array_size; i++) {
> -            smbios_build_type_19_table(i, offset, mem_array[i].address,
> -                                       mem_array[i].length);
> -        }
> +    for (i = 0; i < mem_array_size; i++) {
> +        smbios_build_type_19_table(i, offset, mem_array[i].address,
> +                                   mem_array[i].length);
> +    }
>
> -        /*
> -         * make sure 16 bit handle numbers in the headers of tables 19
> -         * and 32 do not overlap.
> -         */
> -        assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
> +    /*
> +     * make sure 16 bit handle numbers in the headers of tables 19
> +     * and 32 do not overlap.
> +     */
> +    assert((mem_array_size + offset) < (T32_BASE - T19_BASE));
>
> -        smbios_build_type_32_table();
> -        smbios_build_type_38_table();
> -        smbios_build_type_41_table(errp);
> -        smbios_build_type_127_table();
> +    smbios_build_type_32_table();
> +    smbios_build_type_38_table();
> +    smbios_build_type_41_table(errp);
> +    smbios_build_type_127_table();
>
> -        smbios_validate_table(ms->smp.sockets);
> -        smbios_entry_point_setup();
> -        smbios_immutable = true;
> -    }
> +    smbios_validate_table(ms->smp.sockets);
> +    smbios_entry_point_setup();
>
>      /* return tables blob and entry point (anchor), and their sizes */
>      *tables = smbios_tables;
> @@ -1254,13 +1281,10 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
>  {
>      const char *val;
>
> -    assert(!smbios_immutable);
> -
>      val = qemu_opt_get(opts, "file");
>      if (val) {
>          struct smbios_structure_header *header;
> -        int size;
> -        struct smbios_table *table; /* legacy mode only */
> +        size_t size;
>
>          if (!qemu_opts_validate(opts, qemu_smbios_file_opts, errp)) {
>              return;
> @@ -1277,9 +1301,9 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
>           * (except in legacy mode, where the second '\0' is implicit and
>           *  will be inserted by the BIOS).
>           */
> -        smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
> -        header = (struct smbios_structure_header *)(smbios_tables +
> -                                                    smbios_tables_len);
> +        usr_blobs = g_realloc(usr_blobs, usr_blobs_len + size);
> +        header = (struct smbios_structure_header *)(usr_blobs +
> +                                                    usr_blobs_len);
>
>          if (load_image_size(val, (uint8_t *)header, size) != size) {
>              error_setg(errp, "Failed to load SMBIOS file %s", val);
> @@ -1300,34 +1324,15 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
>              smbios_type4_count++;
>          }
>
> -        smbios_tables_len += size;
> -        if (size > smbios_table_max) {
> -            smbios_table_max = size;
> +        if (!usr_blobs_sizes) {
> +            usr_blobs_sizes = g_array_new(false, false, sizeof(size_t));
>          }
> -        smbios_table_cnt++;
> -
> -        /* add a copy of the newly loaded blob to legacy smbios_entries */
> -        /* NOTE: This code runs before smbios_set_defaults(), so we don't
> -         *       yet know which mode (legacy vs. aggregate-table) will be
> -         *       required. We therefore add the binary blob to both legacy
> -         *       (smbios_entries) and aggregate (smbios_tables) tables, and
> -         *       delete the one we don't need from smbios_set_defaults(),
> -         *       once we know which machine version has been requested.
> -         */
> -        if (!smbios_entries) {
> -            smbios_entries_len = sizeof(uint16_t);
> -            smbios_entries = g_malloc0(smbios_entries_len);
> +        g_array_append_val(usr_blobs_sizes, size);
> +        usr_blobs_len += size;
> +        if (size > usr_table_max) {
> +            usr_table_max = size;
>          }
> -        smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
> -                                                   size + sizeof(*table));
> -        table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
> -        table->header.type = SMBIOS_TABLE_ENTRY;
> -        table->header.length = cpu_to_le16(sizeof(*table) + size);
> -        memcpy(table->data, header, size);
> -        smbios_entries_len += sizeof(*table) + size;
> -        (*(uint16_t *)smbios_entries) =
> -                cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
> -        /* end: add a copy of the newly loaded blob to legacy smbios_entries */
> +        usr_table_cnt++;
>
>          return;
>      }
> --
> 2.39.3
>
>



  reply	other threads:[~2024-03-04  9:56 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-27 15:47 [PATCH 00/19] Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS Igor Mammedov
2024-02-27 15:47 ` [PATCH 01/19] tests: smbios: make it possible to write SMBIOS only test Igor Mammedov
2024-02-28  9:35   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 02/19] tests: smbios: add test for -smbios type=11 option Igor Mammedov
2024-02-28  9:55   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 03/19] tests: smbios: add test for legacy mode CLI options Igor Mammedov
2024-02-28 11:11   ` Ani Sinha
2024-02-28 13:59     ` Igor Mammedov
2024-02-28 14:18   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 04/19] smbios: cleanup smbios_get_tables() from legacy handling Igor Mammedov
2024-02-28 11:27   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 05/19] smbios: get rid of smbios_smp_sockets global Igor Mammedov
2024-02-29  7:51   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 06/19] smbios: get rid of smbios_legacy global Igor Mammedov
2024-02-29 10:53   ` Ani Sinha
2024-02-29 14:29     ` Igor Mammedov
2024-03-01  8:33       ` Ani Sinha
2024-03-04 17:38   ` Daniel Henrique Barboza
2024-02-27 15:47 ` [PATCH 07/19] smbios: avoid mangling user provided tables Igor Mammedov
2024-03-04  9:55   ` Ani Sinha [this message]
2024-03-04 14:17     ` Igor Mammedov
2024-02-27 15:47 ` [PATCH 08/19] smbios: don't check type4 structures in legacy mode Igor Mammedov
2024-03-04  7:16   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 09/19] smbios: build legacy mode code only for 'pc' machine Igor Mammedov
2024-03-04 10:55   ` Ani Sinha
2024-03-04 14:23     ` Igor Mammedov
2024-03-04 16:43       ` Igor Mammedov
2024-02-27 15:47 ` [PATCH 10/19] smbios: handle errors consistently Igor Mammedov
2024-03-04 11:14   ` Ani Sinha
2024-03-04 13:39     ` Igor Mammedov
2024-03-04 13:53       ` Ani Sinha
2024-02-27 15:47 ` [PATCH 11/19] smbios: clear smbios_tables pointer after freeing Igor Mammedov
2024-03-04 13:54   ` Ani Sinha
2024-03-04 14:25     ` Igor Mammedov
2024-02-27 15:47 ` [PATCH 12/19] get rid of global smbios_ep_type Igor Mammedov
2024-03-04 17:38   ` Daniel Henrique Barboza
2024-03-05  8:39   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 13/19] smbios: extend smbios-entry-point-type with 'auto' value Igor Mammedov
2024-02-27 17:00   ` Markus Armbruster
2024-03-05  9:15   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 14/19] smbios: in case of entry point is 'auto' try to build v2 tables 1st Igor Mammedov
2024-03-05  6:00   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 15/19] smbios: error out when building type 4 table is not possible Igor Mammedov
2024-03-05 11:36   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 16/19] smbios: clear smbios_type4_count before building tables Igor Mammedov
2024-02-27 15:47 ` [PATCH 17/19] tests: acpi/smbios: whitelist expected blobs Igor Mammedov
2024-02-27 15:47 ` [PATCH 18/19] pc/q35: set SMBIOS entry point type to 'auto' by default Igor Mammedov
2024-03-05 12:21   ` Ani Sinha
2024-02-27 15:47 ` [PATCH 19/19] tests: acpi: update expected SSDT.dimmpxm blob Igor Mammedov
2024-02-27 15:49 ` [PATCH 00/19] Workaround Windows failing to find 64bit SMBIOS entry point with SeaBIOS Michael S. Tsirkin
2024-02-29 13:18 ` Fiona Ebner
2024-03-01 13:55   ` Fiona Ebner
2024-03-05 10:08 ` Michael S. Tsirkin
2024-03-05 10:32   ` Igor Mammedov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bb38e2e8-d9dd-d552-469e-8d47196393c1@redhat.com \
    --to=anisinha@redhat.com \
    --cc=alistair.francis@wdc.com \
    --cc=armbru@redhat.com \
    --cc=bin.meng@windriver.com \
    --cc=dbarboza@ventanamicro.com \
    --cc=eblake@redhat.com \
    --cc=f.ebner@proxmox.com \
    --cc=gaosong@loongson.cn \
    --cc=imammedo@redhat.com \
    --cc=liwei1518@gmail.com \
    --cc=mst@redhat.com \
    --cc=palmer@dabbelt.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=wangyanan55@huawei.com \
    --cc=zhiwei_liu@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).