From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 538C33E6DC8; Thu, 1 Oct 2026 22:11:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790892695; cv=none; b=MnhlfUF3JveqdXnHqx3D77fWrzgfAAAfzAfGaom/AjtY5UD1toLVc5h8ZA9ni0IjoBFmbcUaE6Eg0LU4Y1MAPMIdQe/rriNZphf1Sa8chnF8WpHrPUiwwL6Y1ERvMqYKh2o2BwBoelvnOPINWd5PRgw4mUbgp63p7WgmZ3gXgfs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790892695; c=relaxed/simple; bh=M1GpfmOqv/E/m9hbv8WyCb/feL1sh3bnd9sNkWnd8Cs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NiGb/g5v8l/ibF0vZxtbYEAS0F0c41mNH6b90YSP4ZGsNiWO54ciAtA67/e304lBveKxEXRftnvEKDhEDmkJPqGWAQuZTrvG29dcIkwTeVQj2j9NSK81udpfyvWDIJOQlh6CD0H9Xn61N0NHbUJN4Gq5yKlXdP285cSFWdaewf0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=R+Rmb04G; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="R+Rmb04G" Received: from linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net (linux.microsoft.com [13.77.154.182]) by linux.microsoft.com (Postfix) with ESMTPSA id 06CC620B716E; Thu, 1 Oct 2026 15:10:41 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 06CC620B716E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1790892641; bh=J2lqp12ZXyyxIfAmAz0a9KLa1TySuoMMWxdWtCHbwv8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=R+Rmb04G5LflQlWanWotdMkq1qndgMDCMdjTsLMO4ofcD1yfv65dB/i20btKmlQtg ar1EihRYG6u0bGdqOG2s8PxP28gQxK78j/57i7YtOS57vSO6nPIQ9DbJoCwA0CsnsZ tgXuv/6hi/SjSDnd0MBEonMWYVVMEa27PjV+eGf4= From: Kameron Carr To: Haiyang Zhang , Wei Liu , Dexuan Cui , Long Li , Michael Kelley Cc: linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/4] Drivers: hv: vmbus: Bounds check the shared ring buffer indices Date: Thu, 1 Oct 2026 15:10:37 -0700 Message-ID: <20261001221040.1794904-2-kameroncarr@linux.microsoft.com> X-Mailer: git-send-email 2.43.7 In-Reply-To: <20261001221040.1794904-1-kameroncarr@linux.microsoft.com> References: <20261001221040.1794904-1-kameroncarr@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit In a CoCo VM the host is untrusted. Since the VMBus ring buffer read and write indices live in shared memory, the guest has to treat both as potentially malicious. hv_ringbuffer_write() copies into the ring at write_index with no bounds checking, so the host can make the guest write packet data at any offset up to 4 GiB past the start of the ring buffer. read_index matters too: the available space derived from both indices is the only bound on how much is copied, and an out-of-range index can make it far larger than the ring. The fix is to validate both indices before use and to use the validated snapshot instead of re-accessing. For invalid indices, hv_ringbuffer_write() logs and returns -EIO. Open-coding the bytes available arithmetic keeps the fix free of prerequisites; a later patch refactors it into a helper function. The unchecked write goes back to the commit in the Fixes tag, but the host is only untrusted in CoCo VMs, which Linux has supported since v5.12, so the stable tag starts at 5.15.x. This applies as-is to v5.15 and later. Fixes: 3e7ee4902fe6 ("Staging: hv: add the Hyper-V virtual bus") Cc: # 5.15.x Signed-off-by: Kameron Carr --- drivers/hv/ring_buffer.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 592a960..a18b309 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -70,15 +70,6 @@ static void hv_signal_on_write(u32 old_write, struct vmbus_channel *channel) } } -/* Get the next write location for the specified ring buffer. */ -static inline u32 -hv_get_next_write_location(struct hv_ring_buffer_info *ring_info) -{ - u32 next = ring_info->ring_buffer->write_index; - - return next; -} - /* Set the next write location for the specified ring buffer. */ static inline void hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, @@ -281,6 +272,7 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, u32 totalbytes_towrite = sizeof(u64); u32 next_write_location; u32 old_write; + u32 read_index; u64 prev_indices; unsigned long flags; struct hv_ring_buffer_info *outring_info = &channel->outbound; @@ -295,7 +287,20 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, spin_lock_irqsave(&outring_info->ring_lock, flags); - bytes_avail_towrite = hv_get_bytes_to_write(outring_info); + read_index = READ_ONCE(outring_info->ring_buffer->read_index); + old_write = READ_ONCE(outring_info->ring_buffer->write_index); + if (unlikely(read_index >= outring_info->ring_datasize || + old_write >= outring_info->ring_datasize)) { + spin_unlock_irqrestore(&outring_info->ring_lock, flags); + pr_err_ratelimited("outbound ring indices out of range: relid %u read %u write %u size %u\n", + channel->offermsg.child_relid, read_index, + old_write, outring_info->ring_datasize); + return -EIO; + } + + bytes_avail_towrite = old_write >= read_index ? + outring_info->ring_datasize - (old_write - read_index) : + read_index - old_write; /* * If there is only room for the packet, assume it is full. @@ -317,9 +322,7 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, channel->out_full_flag = false; /* Write to the ring buffer */ - next_write_location = hv_get_next_write_location(outring_info); - - old_write = next_write_location; + next_write_location = old_write; for (i = 0; i < kv_count; i++) { next_write_location = hv_copyto_ringbuffer(outring_info, -- 2.45.4