KVM: selftests: Fix dynamic generation of configuration names
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 13 Dec 2023 12:21:35 +0000 (07:21 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 13 Dec 2023 12:27:36 +0000 (07:27 -0500)
When we dynamically generate a name for a configuration in get-reg-list
we use strcat() to append to a buffer allocated using malloc() but we
never initialise that buffer. Since malloc() offers no guarantees
regarding the contents of the memory it returns this can lead to us
corrupting, and likely overflowing, the buffer:

  vregs: PASS
  vregs+pmu: PASS
  sve: PASS
  sve+pmu: PASS
  vregs+pauth_address+pauth_generic: PASS
  X?vr+gspauth_addre+spauth_generi+pmu: PASS

The bug is that strcat() should have been strcpy(), and that replacement
would be enough to fix it, but there are other things in the function
that leave something to be desired.  In particular, an (incorrectly)
empty config would cause an out of bounds access to c->name[-1].
Since the strcpy() call relies on c->name[0..len-1] being initialized,
enforce that invariant throughout the function.

Fixes: 2f9ace5d4557 ("KVM: arm64: selftests: get-reg-list: Introduce vcpu configs")
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Co-developed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Message-Id: <20231211-kvm-get-reg-list-str-init-v3-1-6554c71c77b1@kernel.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
tools/testing/selftests/kvm/get-reg-list.c

index be7bf522443478613b7bf8e65ed942d57246c637..8274ef04301f6704528293206603efca9690b29c 100644 (file)
@@ -71,11 +71,12 @@ static const char *config_name(struct vcpu_reg_list *c)
        for_each_sublist(c, s) {
                if (!strcmp(s->name, "base"))
                        continue;
-               strcat(c->name + len, s->name);
-               len += strlen(s->name) + 1;
-               c->name[len - 1] = '+';
+               if (len)
+                       c->name[len++] = '+';
+               strcpy(c->name + len, s->name);
+               len += strlen(s->name);
        }
-       c->name[len - 1] = '\0';
+       c->name[len] = '\0';
 
        return c->name;
 }