From nobody Sat Jul 25 19:28:42 2026 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) (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 6756227AC4C for ; Tue, 14 Jul 2026 13:34:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=195.135.223.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784036094; cv=none; b=Yi4BVSH5YqA3wPPchPmUAnTZY6L/vzTZJqLy03pwMaldlpZexKWF/TcPdznOFevnaOdXOOvUaU6RNmC1koBLA6q7ziz7rTTINqfKjY2auUO3UP6ZIAjOCEsZHLcixt+T/FQSZxA9+fp/EcQA+jLHljrFRVU6WOpvwcZRvKcbuuQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784036094; c=relaxed/simple; bh=2pXtAqp5Qhcyd+FPkZ5jN2Jy1K73DjOFfD5vRqAp8hg=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=pHA3WcrhumLG+Arf5dZ2efyReB1iP3TwyFAqI/S/fs9u04dBRw+xzSuRc3MzjRrcNaXyXxD2RkAic06ClLPuyQIxuGbLlSIRReXUYglbmRL3ShiAqzPrdoHE6Zf8pZ0IRVFqFfP9KOpZJxPE4l5cikIw5LDykbFnYDFUnviOj3I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de; spf=pass smtp.mailfrom=suse.de; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=wfYOoOWS; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=QFWr1b4M; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b=a8CO2cT7; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b=Wne8P9Hc; arc=none smtp.client-ip=195.135.223.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=suse.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="wfYOoOWS"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="QFWr1b4M"; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.b="a8CO2cT7"; dkim=permerror (0-bit key) header.d=suse.de header.i=@suse.de header.b="Wne8P9Hc" Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 7E2E73DF4; Tue, 14 Jul 2026 13:34:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1784036090; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=2WaerAKYDmH5MPHIkL1T34Hptiy05I2EuvKf5/jZrPY=; b=wfYOoOWSIz2hqL0qalaRweFcfyeiIlMhGATZQskGWsXl/mixGW5123Pl9zROSNAnWIZDfQ 3DgNGyzagq2Gr0MHafQD7Y67LCFk26j8GCQCTlaxY5hfrOJBVrOXQfx7hc3pGqv+hUFCCl ylcpJMD6R0dWHCH+K1qnJoNjT88WVz8= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1784036090; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=2WaerAKYDmH5MPHIkL1T34Hptiy05I2EuvKf5/jZrPY=; b=QFWr1b4MvnJVQn5By7x/28b21fc5JxlrOE0ENPeUV1zigBlGHkCa8c12hd4Ot4wSXMjtVW l0Ospgk8HQXf5oDw== Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1784036089; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=2WaerAKYDmH5MPHIkL1T34Hptiy05I2EuvKf5/jZrPY=; b=a8CO2cT72ftc8/8q72YMvrO3F09Vw+gFrpt7kwy+yY/5ikg6ej2yCJJw/w9skhYF0VLOnt tYm8tkScULqlwINWbo1j9QBO48zFtg5k+Bn+CKvFjfNoy1azoK9J2SyYxe12O4PO6NYDXs mDIH7l3+NQgqfzIdZc6K4hcLNTXQues= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1784036089; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=2WaerAKYDmH5MPHIkL1T34Hptiy05I2EuvKf5/jZrPY=; b=Wne8P9HcMowDAacRfBWkhY2ABSnpbsqE4DKgcJp6X5zPpLZkjJBPW5HEvDPDIMCZiNi9K0 l6inS7fsQrTPrEBA== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 9DEE4779AE; Tue, 14 Jul 2026 13:34:48 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id BU9/I/g6VmqKZQAAD6G6ig (envelope-from ); Tue, 14 Jul 2026 13:34:48 +0000 From: =?UTF-8?q?Carlos=20L=C3=B3pez?= To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org Cc: =?UTF-8?q?Carlos=20L=C3=B3pez?= , Vitaly Kuznetsov , syzbot+3d5461510f8dc4adfe30@syzkaller.appspotmail.com, Sean Christopherson , Paolo Bonzini , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org (maintainer:X86 ARCHITECTURE (32-BIT AND 64-BIT)), "H. Peter Anvin" , Roman Kagan , Andrey Smetanin Subject: [PATCH v2] KVM: x86: hyper-v: Clamp stimer deadline to avoid livelock Date: Tue, 14 Jul 2026 15:32:13 +0200 Message-ID: <20260714133212.3916611-3-clopez@suse.de> X-Mailer: git-send-email 2.51.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Spam-Flag: NO X-Spam-Score: -1.80 X-Spamd-Result: default: False [-1.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MIME_TRACE(0.00)[0:+]; TAGGED_RCPT(0.00)[3d5461510f8dc4adfe30]; FUZZY_RATELIMITED(0.00)[rspamd.com]; RCVD_VIA_SMTP_AUTH(0.00)[]; ARC_NA(0.00)[]; RCVD_TLS_ALL(0.00)[]; TO_DN_SOME(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; RCPT_COUNT_SEVEN(0.00)[11]; TO_MATCH_ENVRCPT_ALL(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; RCVD_COUNT_TWO(0.00)[2]; DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:email,suse.de:mid,imap1.dmz-prg2.suse.org:helo] X-Spam-Level: Fix an issue where userspace or the guest can program an Hyper-V synthetic timer to have a deadline in the past via integer overflow, preventing the CPU from making progress and triggering an RCU stall. Hyper-V's SynIC exposes 4 per-vCPU synthetic timers to the guest, which are emulated by KVM. Each is programmed through the HV_X64_MSR_STIMERi_CONFIG and HV_X64_MSR_STIMERi_COUNT MSRs. Depending on CONFIG, COUNT represents either the absolute expiration time or the period of a periodic timer, both expressed in 100ns ticks. These timers may be set both by the guest (WRMSR) and the host (KVM_SET_MSRS). When the timer is enabled, stimer_start() translates COUNT to an absolute monotonic deadline and arms an hrtimer. If COUNT is set to a value close to U64_MAX, the deadline calculation can overflow. ktime_add_ns(ktime_now, 100 * (stimer->exp_time - time_now)) This can result in a CPU livelock. stimer_start() arms the timer via hrtimer_start() with a deadline in the past, which causes it to immediately fire. The stimer callback then raises KVM_RQ_HV_STIMER, with the intention of causing KVM to deliver a synthetic interrupt on the next vCPU guest enter. Then, once userspace issues KVM_RUN, vcpu_enter_guest() consumes the request, calling kvm_hv_process_stimers(). This would normally disable the timer via stimer_expiration() once the deadline is in the past. However, the deadline comparison is done between the KVM reference counter and stime->exp_time, which is a big value close to U64_MAX, so this never happens for a few thousand years. kvm_hv_process_timers() then re-arms the timer via stimer_start(), since it was not disabled, which again fires immediately. Before entering the guest, kvm_vcpu_exit_request() checks kvm_request_pending(), which returns true due to the newly raised KVM_REQ_HV_STIMER. Then vcpu_enter_guest() aborts the guest entry, returning early into vcpu_run(), which loops back again into vcpu_enter_guest(), restarting the cycle. Since there are no manual yields in this loop, a task with SCHED_FIFO may starve RCU grace-period kthreads, which exposes the stalls found by syzcaller: rcu: INFO: rcu_preempt detected stalls on CPUs/tasks: rcu: (detected by 1, t=3D10502 jiffies, g=3D14269, q=3D1142 ncpus=3D= 2) rcu: All QSes seen, last rcu_preempt kthread activity 10500 (4294965239= -4294954739), jiffies_till_next_fqs=3D1, root ->qsmask 0x0 rcu: rcu_preempt kthread starved for 10500 jiffies! g14269 f0x2 RCU_GP_= WAIT_FQS(5) ->state=3D0x0 ->cpu=3D0 rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now= expected behavior. ( ... ) Call Trace: __run_hrtimer kernel/time/hrtimer.c:1773 [inline] __hrtimer_run_queues+0x408/0xc30 kernel/time/hrtimer.c:1841 hrtimer_interrupt+0x45b/0xaa0 kernel/time/hrtimer.c:1903 local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1045 [inline] __sysvec_apic_timer_interrupt+0x102/0x3e0 arch/x86/kernel/apic/apic.c:= 1062 instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1056 [in= line] sysvec_apic_timer_interrupt+0xa1/0xc0 arch/x86/kernel/apic/apic.c:1056 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentr= y.h:697 RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h= :152 [inline] RIP: 0010:_raw_spin_unlock_irqrestore+0xa8/0x110 kernel/locking/spinloc= k.c:194 Code: 74 05 e8 0b f4 5f f6 48 c7 44 24 20 00 00 00 00 9c 8f 44 24 20 f6= 44 24 21 02 75 4f f7 c3 00 02 00 00 74 01 fb bf 01 00 00 00 23 6b 27 = f6 65 8b 05 7c 60 5a 07 85 c0 74 40 48 c7 04 24 0e 36 RSP: 0018:ffffc900040a7320 EFLAGS: 00000206 RAX: 5de15cb931505900 RBX: 0000000000000a06 RCX: 5de15cb931505900 RDX: 0000000000000007 RSI: ffffffff8daa9dc3 RDI: 0000000000000001 RBP: ffffc900040a73b0 R08: ffffffff8fc3d077 R09: 1ffffffff1f87a0e R10: dffffc0000000000 R11: fffffbfff1f87a0f R12: dffffc0000000000 R13: 0000000000000000 R14: ffff8880b8628240 R15: 1ffff92000814e64 hrtimer_start include/linux/hrtimer.h:259 [inline] stimer_start arch/x86/kvm/hyperv.c:682 [inline] kvm_hv_process_stimers+0xd0a/0x16a0 arch/x86/kvm/hyperv.c:893 vcpu_enter_guest arch/x86/kvm/x86.c:11193 [inline] vcpu_run+0x2240/0x76b0 arch/x86/kvm/x86.c:11639 kvm_arch_vcpu_ioctl_run+0x1148/0x1c90 arch/x86/kvm/x86.c:11984 kvm_vcpu_ioctl+0x99a/0xed0 virt/kvm/kvm_main.c:4492 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xfa/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f635278f749 Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89= f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 = ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007f635365c038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007f63529e5fa0 RCX: 00007f635278f749 RDX: 0000000000000000 RSI: 000000000000ae80 RDI: 0000000000000005 RBP: 00007f6352813f91 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f63529e6038 R14: 00007f63529e5fa0 R15: 00007ffd5b219358 Fix this by clamping the deadline computation to KTIME_MAX, which preserves the intent of arming a timer very far in the future. ktime_add_safe() already does this type of clamping, so use it after checking that that multiplying by the 100ns time tick also does not overflow. Reviewed-by: Vitaly Kuznetsov Reported-by: syzbot+3d5461510f8dc4adfe30@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=3D3d5461510f8dc4adfe30 Fixes: 1f4b34f825e8 ("kvm/x86: Hyper-V SynIC timers") Signed-off-by: Carlos L=C3=B3pez --- v2: * Use >=3D when checking for overflow (Vitaly Kuznetsov) * Collect Vitaly's Reviewed-by arch/x86/kvm/hyperv.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 39b58f56308b..944cfce109e6 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -630,6 +630,17 @@ static enum hrtimer_restart stimer_timer_callback(stru= ct hrtimer *timer) return HRTIMER_NORESTART; } =20 +/* + * Translate a stimer expiry given in 100ns reference ticks into an + * an absolute deadline. Saturates on overflow. + */ +static ktime_t stimer_add_delta(ktime_t now, u64 delta_100ns) +{ + if (delta_100ns >=3D KTIME_MAX / 100) + return KTIME_MAX; + return ktime_add_safe(now, 100 * delta_100ns); +} + /* * stimer_start() assumptions: * a) stimer->count is not equal to 0 @@ -639,6 +650,7 @@ static int stimer_start(struct kvm_vcpu_hv_stimer *stim= er) { u64 time_now; ktime_t ktime_now; + ktime_t deadline; =20 time_now =3D get_time_ref_counter(hv_stimer_to_vcpu(stimer)->kvm); ktime_now =3D ktime_get(); @@ -661,10 +673,8 @@ static int stimer_start(struct kvm_vcpu_hv_stimer *sti= mer) stimer->index, time_now, stimer->exp_time); =20 - hrtimer_start(&stimer->timer, - ktime_add_ns(ktime_now, - 100 * (stimer->exp_time - time_now)), - HRTIMER_MODE_ABS); + deadline =3D stimer_add_delta(ktime_now, stimer->exp_time - time_now); + hrtimer_start(&stimer->timer, deadline, HRTIMER_MODE_ABS); return 0; } stimer->exp_time =3D stimer->count; @@ -683,9 +693,9 @@ static int stimer_start(struct kvm_vcpu_hv_stimer *stim= er) stimer->index, time_now, stimer->count); =20 - hrtimer_start(&stimer->timer, - ktime_add_ns(ktime_now, 100 * (stimer->count - time_now)), - HRTIMER_MODE_ABS); + deadline =3D stimer_add_delta(ktime_now, stimer->count - time_now); + hrtimer_start(&stimer->timer, deadline, HRTIMER_MODE_ABS); + return 0; } =20 base-commit: 3aec122bdcaf6f8c4ecfc7f6adf6773015ced676 --=20 2.51.0