From nobody Sat Sep 26 20:30:55 2026 Received: from va-2-26.ptr.blmpb.com (va-2-26.ptr.blmpb.com [209.127.231.26]) (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 62D2D3C1D40 for ; Mon, 31 Aug 2026 04:55:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.127.231.26 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788152146; cv=none; b=TMHvtb8zMNSFyaW1DP0rnVmhkkA4htnSEINwlf7J4KYZPpbFZiVX+VGps5ILOJED2IQL6NUrmUM88uhb3wMe0rGsC515i6qfazRYVohznfe9SVSw57tr/uqh0er76VbCe31Rj7aEM/mVSfbE7UIbCi80wWkj82AHAE9SxyU/Yo0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788152146; c=relaxed/simple; bh=Ax64etgIAtuiMSY9v0hJJ+Zy8ZscVg0ooBhAR4GMufM=; h=Date:To:Content-Type:From:Subject:Mime-Version:Cc:Message-Id; b=BUkompkXPQjZPhw0LQZmSV78VRO8EKIASmxPCJ8iyQX4OLA29k2iKPuS4nxBqxKZUklk7knZFO8qaap7y3PHEvhaR5ua43+3oPixwREQaS+kZVGXhzi9Xkpq7Msa4JltQuW19+6/2ZLg5jxSkquO7Ik4nNT7y63JcarQ04XpXRo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=moonshot.ai; spf=pass smtp.mailfrom=moonshot.ai; dkim=pass (2048-bit key) header.d=moonshot.ai header.i=@moonshot.ai header.b=Y37iTFxD; arc=none smtp.client-ip=209.127.231.26 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=moonshot.ai Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=moonshot.ai Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=moonshot.ai header.i=@moonshot.ai header.b="Y37iTFxD" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; s=feishu2510091218; d=moonshot.ai; t=1788152133; h=from:subject: mime-version:from:date:message-id:subject:to:cc:reply-to:content-type: mime-version:in-reply-to:message-id; bh=JTNBYzTVvEFBkVlvhYr+tJv6fEBe1dkT+9DimDVSK0U=; b=Y37iTFxDgy266GXCcKQQApdWhoWvqVDz00PXimcy94eEbjNdGtHBXPFyRrBZv3NOkYDX74 R/CANjOx8Kq5YsCKHGwAkM5mNYPXRo9wov2t6FOOnn1d1UQtm9zXJQmbG6iPt8YzSYIgSA eI44Ps0AJwWxlb3hQv/fUgnF9uReON2EqmagClyI1/wg8MrWFyK8H/OqrArsZ5GJpYeEwQ 7Q5sOOTH1PKrAoPIWpP6rXwmhDG5QIWYxhXM3NJ2bS+xAJT0x1VhqHKo3vnpUVu1hs1G/b B2ah/huySN0tdtn4JJQYblsi7/BQ9ZgAnBAk2iqfYBJDYjmU5Uli36nA+H0yYQ== Date: Mon, 31 Aug 2026 12:55:06 +0800 X-Original-From: Yilin Zhang Received: from dev.msh-dev.svc.cluster.local ([117.157.206.135]) by smtp.feishu.cn with ESMTPS; Mon, 31 Aug 2026 12:55:30 +0800 X-Mailer: git-send-email 2.34.1 To: , From: "Yilin Zhang" Subject: [PATCH] ALSA: pcm: Serialize PCM mmap with buffer reallocation to fix page UAF 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 Cc: "Yilin Zhang" , , , , "Kimi Security Team" Message-Id: <20260831045506.889070-1-yilinzhang@moonshot.ai> X-Lms-Return-Path: Content-Type: text/plain; charset="utf-8" snd_pcm_hw_params() and snd_pcm_hw_free() guard buffer reallocation with an mmap_count check performed under the PCM stream lock, but the lock is released long before the buffer is actually freed: snd_pcm_sync_stop(), constraint refinement and do_free_pages() all happen in between. snd_pcm_mmap_data(), on the other hand, takes no lock at all: it validates against the old buffer's state and dma_bytes, remaps its pages into the VMA, and only then increments mmap_count. A concurrent mmap() can therefore slip in between the check and the free. remap_pfn_range() installs writable PTEs for the old buffer's pages without taking page references, and the subsequent do_free_pages() returns those pages to the page allocator while the VMA still maps them. This leaves a stale, writable mapping of freed pages: a page-level use-after-free that can be leveraged for local privilege escalation. Make snd_pcm_mmap_data() participate in the buffer-access scheme introduced for hw_params/hw_free: acquire runtime->buffer_accessing before validating and remapping, and release it afterwards. Buffer reallocation already fails with -EBUSY while accessors are active, and the mmap side now fails with -EBUSY while a reallocation is in progress, so the validate/remap sequence and the check/free sequence can no longer interleave. A reproducer that turns this race into a stale writable mapping of the freed DMA buffer pages is available on request. Reported-by: Kimi Security Team Fixes: 92ee3c60ec9f ("ALSA: pcm: Fix races among concurrent hw_params and h= w_free calls") Signed-off-by: Yilin Zhang --- sound/core/pcm_native.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3937,20 +3937,33 @@ return -EINVAL; } runtime =3D substream->runtime; - if (runtime->state =3D=3D SNDRV_PCM_STATE_OPEN) - return -EBADFD; - if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) - return -ENXIO; + /* don't race with buffer reallocation in hw_params/hw_free */ + if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) + return -EBUSY; + if (runtime->state =3D=3D SNDRV_PCM_STATE_OPEN) { + err =3D -EBADFD; + goto out; + } + if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) { + err =3D -ENXIO; + goto out; + } if (runtime->access =3D=3D SNDRV_PCM_ACCESS_RW_INTERLEAVED || - runtime->access =3D=3D SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) - return -EINVAL; + runtime->access =3D=3D SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { + err =3D -EINVAL; + goto out; + } size =3D area->vm_end - area->vm_start; offset =3D area->vm_pgoff << PAGE_SHIFT; dma_bytes =3D PAGE_ALIGN(runtime->dma_bytes); - if ((size_t)size > dma_bytes) - return -EINVAL; - if (offset > dma_bytes - size) - return -EINVAL; + if ((size_t)size > dma_bytes) { + err =3D -EINVAL; + goto out; + } + if (offset > dma_bytes - size) { + err =3D -EINVAL; + goto out; + } =20 area->vm_ops =3D &snd_pcm_vm_ops_data; area->vm_private_data =3D substream; @@ -3960,6 +3973,8 @@ err =3D snd_pcm_lib_default_mmap(substream, area); if (!err) atomic_inc(&substream->mmap_count); +out: + atomic_dec(&runtime->buffer_accessing); return err; } EXPORT_SYMBOL(snd_pcm_mmap_data); --=20 2.43.0