From: Sean Christopherson <seanjc@google.com>
To: Sean Christopherson <seanjc@google.com>,
Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>,
Sashiko Bot <sashiko-bot@kernel.org>
Subject: [PATCH v3 03/21] KVM: x86: Allow userspace to set KVM's max supported guest TSC frequency
Date: Wed, 30 Sep 2026 10:36:17 -0700 [thread overview]
Message-ID: <20260930173635.3362655-4-seanjc@google.com> (raw)
In-Reply-To: <20260930173635.3362655-1-seanjc@google.com>
Reject KVM_SET_TSC_KHZ if the incoming frequency is strictly greater than
KVM's max supported frequency, not if the frequency is greater than *or*
equal to the max frequency. The effective off-by-one bug came about via
(dubious) review feedback, which also subtly collided with a functional
change in later versions of the original TSC scaling series.
In v2 of the original TSC scaling series[1], KVM set its absolute min/max
to [1, UINT_MAX], i.e. allowed any value that would fit in the u32 passed
to KVM_SET_TSC_KHZ[2].
min = max(1ULL, __scale_tsc(tsc_khz, TSC_RATIO_MIN));
max = min(0xffffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
That prompted Avi to suggest rejecting the "equals" case, presumably
because the check would always succeed given an absolute max of UINT_MAX?
But even that doesn't hold up to scrutiny, as allowing the actual min/max
isn't inherently unsafe. Regardless, that feedback was taken and applied
to future versions, but only for the maximum, not the minimum.
> +
> + r = -EINVAL;
> + if (user_tsc_khz< kvm_min_guest_tsc_khz ||
> + user_tsc_khz> kvm_max_guest_tsc_khz)
<= and >= are probably safer.
v3 of the series[3] then also realized that allowing UINT_MAX would lead to
undesirable interactions with KVM_GET_TSC_KHZ, which returns a *signed*
32-bit integer that is implicitly converted into a signed 64-bit value on
64-bit kernels. I.e. allowing a value greater than INT_MAX would result
in userspace observing a negative value when doing KVM_GET_TSC_KHZ after
KVM_SET_TSC_KHZ.
/*
* Make sure the user can only configure tsc_khz values that
* fit into a signed integer.
* A min value is not calculated needed because it will always
* be 1 on all machines and a value of 0 is used to disable
* tsc-scaling for the vcpu.
*/
max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
kvm_max_guest_tsc_khz = max;
v3 also dropped the explicit minimum tracking, as both AMD and Intel
support a minimum *fractional* ratio of 1, i.e. AMD and Intel support a
minimum frequency of "host / 2^32" and "host / 2^48" respectively. And
because KVM_GET_TSC_KHZ (and KVM itself) only supports frequencies that fit
in a signed 32-bit integer, even AMD's more coarse-grained ratio can scale
down any host frequency to '1', i.e. KVM can always support a minimum
frequency of 1KHz. Rather than explicitly reject a frequency of 1KHz,
v3 simply dropped the minimum check, i.e. ignored the "<=" suggestion, but
kept the ">=" side of things.
As a result, KVM now has a bizarre uABI where KVM_SET_TSC_KHZ tops out at
INT_MAX-1 for no discernible reason. Fix the off-by-one flaw to provide a
less weird uABI, and so that KVM_SET_TSC_KHZ accepts the maximum possible
value that can be returned by KVM_GET_TSC_KHZ (without running afoul of
casting issues; KVM doesn't actually sanity check that tsc_khz fits in a
signed 32-bit value, which is a non-issue in practice because the units are
KHz, not Hz, i.e. KVM_GET_TSC_KHZ is fine until CPUs with a TSC frequency
greater than ~2.147PHz come along).
Note, in practice, no real world VMM is likely to care. As above, running
afoul of the off-by-one issue would mean trying to configure a virtual TSC
frequency that is three orders of magnitude greater than what current CPUs
support.
Opportunistically explain *why* KVM restricts KVM_SET_TSC_KHZ to values
that fit in a signed integer, as it requires far too much spelunking to
piece together the connection to KVM_GET_TSC_KHZ.
Link: https://lore.kernel.org/all/1300952424-32014-1-git-send-email-joerg.roedel@amd.com [1]
Link: https://lore.kernel.org/all/1300952424-32014-7-git-send-email-joerg.roedel@amd.com [2]
Link: https://lore.kernel.org/all/1301042691-22929-7-git-send-email-joerg.roedel@amd.com [3]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/x86.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 037c7ea5c5a7..1d25ffcf9273 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3718,7 +3718,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
user_tsc_khz = (u32)arg;
if (kvm_caps.has_tsc_control &&
- user_tsc_khz >= kvm_caps.max_guest_tsc_khz)
+ user_tsc_khz > kvm_caps.max_guest_tsc_khz)
goto out;
if (user_tsc_khz == 0)
@@ -4685,7 +4685,7 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
user_tsc_khz = (u32)arg;
if (kvm_caps.has_tsc_control &&
- user_tsc_khz >= kvm_caps.max_guest_tsc_khz)
+ user_tsc_khz > kvm_caps.max_guest_tsc_khz)
goto out;
if (user_tsc_khz == 0)
@@ -7174,7 +7174,8 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
if (kvm_caps.has_tsc_control) {
/*
* Make sure the user can only configure tsc_khz values that
- * fit into a signed integer.
+ * fit into a signed integer, otherwise KVM_GET_TSC_KHZ would
+ * return a negative value and confuse userspace.
* A min value is not calculated because it will always
* be 1 on all machines.
*/
--
2.56.0.rc1.315.gc6ed9934b7-goog
next prev parent reply other threads:[~2026-09-30 17:37 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-30 17:36 [PATCH v3 00/21] KVM: x86: Fix nested TSC scaling edge cases Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 01/21] KVM: x86: Saturate L2's TSC frequency if it exceeds hardware supports Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 02/21] KVM: SVM: Fallback to the default TSC ratio if KVM tries to use a bad multiplier Sean Christopherson
2026-09-30 17:36 ` Sean Christopherson [this message]
2026-09-30 17:36 ` [PATCH v3 04/21] KVM: selftests: Use KVM's pRNG to randomize L1's TSC ratio in TSC scaling test Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 05/21] KVM: selftests: Drop redundant VMWRITE of TSC_MULTIPLIER_HIGH Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 06/21] KVM: selftests: Drop unnecessary use of PRIu64 in nested TSC scaling test Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 07/21] KVM: selftests: Randomize L2's scale factor " Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 08/21] KVM: selftests: Rename TSC freq checkers " Sean Christopherson
2026-09-30 17:45 ` sashiko-bot
2026-09-30 18:00 ` Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 09/21] KVM: selftests: Extract guts of nested TSC scaling test to helper function Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 10/21] KVM: selftests: Track L2 multiplier, not scale-up factor, in nested TSC test Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 11/21] KVM: selftests: Print out the failing L{0,1,2} level in nested TSC scaling test Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 12/21] KVM: selftests: Allow +/- 1 tolerance if expected TSC frequency is <100 Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 13/21] KVM: selftests: Use KVM's reported TSC KHz as L0's frequency (sanity checked) Sean Christopherson
2026-09-30 17:52 ` sashiko-bot
2026-09-30 18:08 ` Sean Christopherson
2026-10-02 23:43 ` Jim Mattson
2026-10-06 5:37 ` Sean Christopherson
2026-10-06 21:57 ` Jim Mattson
2026-10-07 6:04 ` Sean Christopherson
2026-10-07 17:25 ` Jim Mattson
2026-09-30 17:36 ` [PATCH v3 14/21] KVM: selftests: Explicitly pass TSC frequencies to guts of TSC scaling test Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 15/21] KVM: selftests: Sanity check KVM's default TSC freq in nested " Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 16/21] KVM: selftests: Test L1 "up" and L2 "down" " Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 17/21] KVM: selftests: Verify that KVM saturates L2 TSC freq on {under,over}flow Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 18/21] KVM: selftests: Test non-zero TSC offset on SVM in nested TSC scaling test Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 19/21] KVM: selftests: Randomize L2's TSC offset in the " Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 20/21] KVM: selftests: Use GUEST_SYNC2() in " Sean Christopherson
2026-09-30 17:36 ` [PATCH v3 21/21] KVM: selftests: Spell out UCALL in nested TSC scaling test's enums Sean Christopherson
2026-10-02 21:07 ` [PATCH v3 00/21] KVM: x86: Fix nested TSC scaling edge cases Sean Christopherson
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=20260930173635.3362655-4-seanjc@google.com \
--to=seanjc@google.com \
--cc=amirmohammad.eftekhar@cispa.de \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=sashiko-bot@kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.