From nobody Mon May 25 06:41:09 2026 Received: from mail-qv1-f49.google.com (mail-qv1-f49.google.com [209.85.219.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07D76288C2F for ; Sun, 17 May 2026 17:50:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779040218; cv=none; b=fNv6ou63E2IEcB+sLrx/wbl6bEBlL+YRY4nDrU6jR81mqwuqfktcYcGeP646eRo6IQE4pyapavPFaW6lfEdsC3DaEYTcHqb0Z+ojR+bWEUxVWX6XAGBkqIXpEQb0GdMuEF7LTuEGHYwj1bKEenatkmx2nmYhQbsY+Xz/w1iyMSI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779040218; c=relaxed/simple; bh=5hmkXCx2wWYh38pdsLtuClcdaCTRkzAepiYTtF1cs4w=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=WOt3T+nfah4tg62qASuuAflD2GEumEJLa5lbAbK0GHUNdj5eI/aJEf0OYj7QUiSXgWlrDN85OxJ+x10dJQTu9ExJgUfimF0Lc228yVoy2tpIrpRH3KQk2Q+Rw58jIu25M+ASRjmtOsPqhOA1g0GiLH+xSQNyL9ubOqnQ4v8docs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=G7zttHeJ; arc=none smtp.client-ip=209.85.219.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="G7zttHeJ" Received: by mail-qv1-f49.google.com with SMTP id 6a1803df08f44-8b9f2295a9dso19367686d6.3 for ; Sun, 17 May 2026 10:50:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779040216; x=1779645016; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=AEwo4MAtXfHhC/yEWJTYYWISTgdb20g3+/oxORWHNec=; b=G7zttHeJPBotEaGzOLDxDdyA2ppgYjdWwrJm+49q4X6oTgU3DF6M+2t7es478NJIcl UyW/bOt41n/ngOgoMOY/dr8bBp1BNFdiHb9hOiC2cDvY23jXr1kdHCQBwsETnu4h1Fer ZxcgcRHqHI+PhW4hKxDdTYb8uuWbk9Z5jccTOyqttY0mfJPj91gh2ALQ2auhqKY6q+tu zhx9nS8Eo8WTz90m8O+At/WSHPQNOPE9ew460gyg66jo0B/EORJF3gTEpw0tDb3PtaWb pNaJ8TXcamjUyGA6rFTX0eELhPPaOBH/3dLA/yJioumJj7sgIx0JJGqfcwEv1JO7vCk/ LWug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779040216; x=1779645016; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=AEwo4MAtXfHhC/yEWJTYYWISTgdb20g3+/oxORWHNec=; b=mRq2m+7RDYDpwSGcXeNkJhDsy60oJzkPkwmggT1FRCSaegjubX3+T+XSyxR7uhqp6u 7Vx5x7SwdpuAy9zYgZ8UDwpjg4fdj8isXXpeWRNFxqxTlKAx4gjI+FfXQ9eQHOy+iGUj sEaai+WCpBDBwStQSrv8MU7wYQSM4MPmuOBHVBWEvD/BkyC7+M1qBOmpx7Elg2hhastx txQ21qaNFst2/MmFmOJNiwVC9JR/F7XnjL1ORb2aP12zLFLB5Na19QuVZF7/WCUmRO9x MyilP6dcWRRZ5nzDd4DuZBOzberkCud7YX4k/bGvo61uJQ3V6cDuAMM2g8RFrbotxFbu vZtQ== X-Forwarded-Encrypted: i=1; AFNElJ8MIqc81u09kryzhtPkZnvvnHLDtjhD/y/KLGuanlCfV+X8UN2SL1dDkdW9jOvG3e6wt1RJcf3tGBejQAU=@vger.kernel.org X-Gm-Message-State: AOJu0YyADwJrx1wYg6I9U8/G0HAxzdYs5y3510lkbbyjiAxwU7Mr8XRD 5XtOUggiRwHqCkM6ayIk4DOPxY/2HIXteJQmoG8OG74MzzDihg65ySJ+lJeU12BQ X-Gm-Gg: Acq92OGRCp5SL7lw/LSWPXnbCC5OHgiKG+bNwLKSTlq+UYvgZNaWYQFAS7jtlHTghiA RHChPd4MWCkIZTmSzmYJ1zq+oKyVjVdu/Yj7FTeRBtL1b+WA78kVCvGFeRbCjIX2XiaEOu/byn0 dKe8RAWqCOwYG4611leT31acsnJrweJBI+WqGJvBb1kkP6vbW1/+P5Lj+poVIQSe940Eg7G0+iq Q93aZv5DRLKHC1FAhWSTUD7ZtWsUuSQSYHSSdgqPxlpCVOLDjnFnYuRKDTVh0yT+p51tuprUdqD xihFz7WhwyoKGo1MdH657p0L6i3QwhaYoXxc5nKAv4F2PJGNZN2Zxc/d4vWgYYS1RT5R40k3v7s CWKFJViWEAHKf+01MthVt4c6cLRcDs+NNrTQF9F3VAXePedRBr+s8kkaGGEcJD0Nhv2Mql+QidU sZRq21qFhepiFfwpBY3K7+6+916Gd4Y9BgEj+hsuE7SfAU48tfvaDKWfr9Btp/7lLsrZAahAdC1 TX+5XGVkTpxmImd4JoQg2zP9o+/fYmfkH9DwdkumgW5fLspV2dk9Q== X-Received: by 2002:a05:6214:4288:b0:8ac:a82c:1c43 with SMTP id 6a1803df08f44-8ca0f8fe1dcmr198672686d6.41.1779040215896; Sun, 17 May 2026 10:50:15 -0700 (PDT) Received: from server0.tail6e7dd.ts.net (c-68-48-65-54.hsd1.mi.comcast.net. [68.48.65.54]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8ca3609784bsm28551436d6.16.2026.05.17.10.50.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 17 May 2026 10:50:15 -0700 (PDT) From: Michael Bommarito To: Marc Zyngier , Oliver Upton Cc: Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH] KVM: arm64: vgic-its: reject restored DTE with out-of-range num_eventid_bits Date: Sun, 17 May 2026 13:49:55 -0400 Message-ID: <20260517174955.273004-1-michael.bommarito@gmail.com> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Userspace can trigger a host-side denial of service via KVM_DEV_ARM_ITS_RESTORE_TABLES. A Device Table Entry whose Size field encodes num_eventid_bits > VITS_TYPER_IDBITS reaches scan_its_table() with a sign-extended ~18 EiB length, where the loop holds the per-ITS mutex and never calls cond_resched(), pinning a host CPU for a time linear in registered guest memslot size. The accessor is any process that can open /dev/kvm and create a VM. The same out-of-range value also disables a subsequent live bounds check on EventID, as described below. The MAPD command handler already rejects this case in the live path: if (valid && num_eventid_bits > VITS_TYPER_IDBITS) return E_ITS_MAPD_ITTSIZE_OOR; vgic_its_restore_dte() reconstructs num_eventid_bits from the DTE Size field but does not apply the same cap, so userspace can install device state that the live MAPD path is documented to reject. The restored value is stored in dev->num_eventid_bits and is then used by vgic_its_restore_itt(): size_t max_size =3D BIT_ULL(dev->num_eventid_bits) * ite_esz; ret =3D scan_its_table(its, base, max_size, ite_esz, ...); scan_its_table() takes the size as int and assigns it to unsigned long in the callee: static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz, ...) { unsigned long len =3D size; For num_eventid_bits =3D 28 the size_t value 0x80000000 truncates to INT_MIN as int and sign-extends to ~18 EiB as unsigned long. The scan loop then walks the registered guest memslot one ite_esz at a time with the per-ITS mutex held and no cond_resched(). In a QEMU TCG arm64 guest at EL2 on v7.1-rc1, with an empty ITT, the ioctl returned -EFAULT after about 14 seconds with a 256 MiB memslot and about 56 seconds with a 1 GiB memslot (linear in memslot size). The per-iteration cost on native arm64 KVM hardware will differ; the loop shape, and so the linear scaling, will not. The same out-of-range num_eventid_bits also disables the live vgic_its_check_event_id() bounds check, because event_id is u32 and BIT_ULL(32) is unreachable in that comparison, leaving subsequent MAPI/MAPTI handling without an effective EventID cap. Mirror the MAPD cap in vgic_its_restore_dte() before allocating the device, so out-of-range restored DTEs are rejected with -EINVAL up front rather than triggering the int-truncated scan or installing a device whose num_eventid_bits silently disables the live bounds check. Sizes within [1, VITS_TYPER_IDBITS] are unaffected. Fixes: 57a9a117154c ("KVM: arm64: vgic-its: Device table save/restore") Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito --- arch/arm64/kvm/vgic/vgic-its.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 2ea9f1c7ebcd0..a5dcf9a6a2854 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -2307,6 +2307,15 @@ static int vgic_its_restore_dte(struct vgic_its *its= , u32 id, /* dte entry is valid */ offset =3D (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT; =20 + /* + * The MAPD command rejects this case; mirror the cap here so a + * restored DTE cannot install an out-of-range num_eventid_bits + * that vgic_its_restore_itt() would then convert into a + * sign-extended scan_its_table() length. + */ + if (num_eventid_bits > VITS_TYPER_IDBITS) + return -EINVAL; + if (!vgic_its_check_id(its, baser, id, NULL)) return -EINVAL; =20 --=20 2.53.0