target/loongarch/kvm: fix uninitialized val and unchecked GET in cpucfg2 check

kvm_check_cpucfg2() discards the return value of KVM_GET_DEVICE_ATTR and
uses the local val (the host cpucfg2 mask) without checking whether the
read succeeded. val is also declared without an initializer, so on a GET
failure env->cpucfg[2] &= val reads an uninitialized value.

The &= mask is best-effort feature negotiation: if KVM_HAS_DEVICE_ATTR
succeeds, a GET failure is most likely a copy_{from,to}_user issue, not a
reason to fail the whole register sync. Check the GET return value, warn and
skip the mask on failure (the guest keeps the cpucfg2 it already has), and
initialize val to 0.

Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Reviewed-by: Bibo Mao <maobibo@loongson.cn>
Message-ID: <20260626052742.810726-2-cui.tao@linux.dev>
Signed-off-by: Song Gao <gaosong@loongson.cn>
This commit is contained in:
Tao Cui
2026-06-26 13:27:39 +08:00
committed by Song Gao
parent 94826ec137
commit bf7f2ee96f

View File

@@ -725,7 +725,7 @@ static int kvm_loongarch_get_cpucfg(CPUState *cs)
static int kvm_check_cpucfg2(CPUState *cs)
{
int ret;
uint64_t val;
uint64_t val = 0;
struct kvm_device_attr attr = {
.group = KVM_LOONGARCH_VCPU_CPUCFG,
.attr = 2,
@@ -736,8 +736,17 @@ static int kvm_check_cpucfg2(CPUState *cs)
ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, &attr);
if (!ret) {
kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
env->cpucfg[2] &= val;
/*
* The &= mask is best-effort feature negotiation. If HAS succeeded,
* a GET failure is most likely a copy_{from,to}_user issue; warn and
* keep the cpucfg2 the guest already has rather than failing the sync.
*/
int r = kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, &attr);
if (r) {
warn_report("CPUCFG2: KVM_GET_DEVICE_ATTR: %s", strerror(errno));
} else {
env->cpucfg[2] &= val;
}
if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) {
/* The FP minimal version is 1. */