From nobody Thu Apr 9 20:27:26 2026 Received: from mail-yw1-f182.google.com (mail-yw1-f182.google.com [209.85.128.182]) (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 3868F200110 for ; Thu, 5 Mar 2026 19:35:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772739326; cv=none; b=aRL69hSM13eT1j3acCLpR7yKRDOCJkRmSF+9dgMVSUrMpJhBwhdTJWnkG5RlcZCOScmp3s/yyq8+Xgy15kzPt9hJdB8gTomGz5e7BJF0zRtOBBHymzia38YTk2KYJCIs4YRC4xSP87fGV/ajNNU1ypyjmx2UCunyZU6EjL4YBU0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772739326; c=relaxed/simple; bh=PAvtlUAZJV23Ogtz1NgVoBzstnncqqGvH6vEP62bhE4=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=sLGxcf7U6Z5dG/X6Ldx1o2/w2FXvVI7OXreuy4ZDusyuxx0vA8sElIQcBkzUWaTQ/0AWuUHvrohJX9F8a6EFWY3euzm5//g3aPfk1yIrULNfk8PTIl66Wafag42npaHQPWDYGYOWwle+698B0E/FKW4V9kG9HvMi6g59aqSltHI= 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=UP/AhDOq; arc=none smtp.client-ip=209.85.128.182 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="UP/AhDOq" Received: by mail-yw1-f182.google.com with SMTP id 00721157ae682-794719afcd4so79292997b3.1 for ; Thu, 05 Mar 2026 11:35:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772739324; x=1773344124; 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=JUsSuBpeeeWw+tAHopXopwOdrzE4R0Nfqxb1XRb2Jes=; b=UP/AhDOq7lRRIGG8N9dVPMz5ZmRxqOVJT+jDANcldTi3VO+InAk+eTfKb/IUVh/ITs /4SY7j1GK6sSf7A3Kp5IBW3mjsBM28cU2u705i7plaw9NS5MpLaaSeG7kytZGzBP6Xp8 wu4vJjmNtBTjGzR9m4+ZqUQfWCcwLq9EXi3fb38n4YUuBR3mpxzKAleGtxpLMqMNTlDe tGMMayYgKshxO9THLz5hZf73qwin84q/CFY2use14L500S0r9Wwk7RJBDpPJktitby1m PUGkzP1C+TQ1L+rWyEp6uwrsinY/2+pCyDoa61qCJE45gJnNVQo0sSSHWgRo6GcFph1H v8xg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772739324; x=1773344124; 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=JUsSuBpeeeWw+tAHopXopwOdrzE4R0Nfqxb1XRb2Jes=; b=IDE/bZBK0BthC7O6znsw8+oFWpfU39UnSItZAB94XypJ2u3T+RnIskt2F3uBPV4UtQ RkRgNFaf1xOUBGHCPpwoOT/Ye4et82jRQDF90surVPCjk7KIkBeEYE5X+Pv7auX/kMzx RZy+bVmjBEd/M2yBAgZYUnTsv+h0drRstfne0fdLSe/0k1GNi1e/mFLQxbvQgL+VHDc3 L438UGUU4qSHlOnN05+b4jthfIoGtwyLljE5+aFe2OCCtawx/r+G5R7fDHQxSbC9ThT4 rsjQvv/olTVbsN9IGLkIRFaLVPoDbDG0vJTozBzc34PIvKDmR1VX1UA3oekQbAKiX20e Maug== X-Forwarded-Encrypted: i=1; AJvYcCWDm/iBx92/beIcPj48nmTQduCIxCK3xKL/in4vW03Uumfus/5fPXea75tiaBHvYZQTrNHyaFO6toH9G7o=@vger.kernel.org X-Gm-Message-State: AOJu0YwwfW6Ge9wICodHPQqFPrvyl0TaW+EgZLvbX1u0dd204p4woSJs 0m78NgFaZIFXfmS6cAR7eG9C3qg7B21ZO4/UEv6JOL5WYm+F8oFdMsiF X-Gm-Gg: ATEYQzyhPAo+GKezQMSGjFodI/yrAOFMC9Ff5/mueDSJgiuGDv8z5Kky8XpqwnF7k2S qQR8usZzU0/JMqKz0UoPVEWQzhH05Kgg95QHHThqlwhXxB8Nk6A6rsNo47XZjdA+xIivEIUqCZe yck9xa9S3SCeQnARwg5L8UCUF88OxyjXMrjmvbn4QdTrCz4FjTruswu+YvX6GMGqH4wyyqIGRGW 57Zvw1hlDwWxvPiOzB4UgpqOTfPaCUsrC+mKCX10pJPWEoJy4p/bjeVeVvfhBM4iwEiUDs/FQK2 S5N9OzXR7Q+70JwpOvJnfJnMEWNSUAFOcdFpF+UZyLNTgMowiv3HgJiOQGrlG8BGwAE5Dr/ow20 Ntjty4AYwXQ54rpiauORee+iEgGhOwVwR+6nbClPBsGYwW1tR1kGhSI8/NHrVnd8bkbeEASfdKx evPF5AST7dod1pKCcmahBhNjGZaYMi7BmmzDAed5D6BINCiE5EBnGLFPV7 X-Received: by 2002:a05:690c:4d09:b0:798:5660:9314 with SMTP id 00721157ae682-798c6d23fd6mr52715547b3.64.1772739324161; Thu, 05 Mar 2026 11:35:24 -0800 (PST) Received: from desktop-linux.python-stargazer.ts.net ([50.168.180.218]) by smtp.gmail.com with ESMTPSA id 00721157ae682-79876a9004dsm92396307b3.6.2026.03.05.11.35.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 05 Mar 2026 11:35:23 -0800 (PST) From: Mehul Rao To: Jaroslav Kysela , Takashi Iwai Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Mehul Rao Subject: [PATCH] ALSA: pcm: fix use-after-free on linked stream runtime in snd_pcm_drain() Date: Thu, 5 Mar 2026 14:35:07 -0500 Message-ID: <20260305193508.311096-1-mehulrao@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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable In the drain loop, the local variable 'runtime' is reassigned to a linked stream's runtime (runtime =3D s->runtime at line 2157). After releasing the stream lock at line 2169, the code accesses runtime->no_period_wakeup, runtime->rate, and runtime->buffer_size (lines 2170-2178) =E2=80=94 all referencing the linked stream's runtime wit= hout any lock or refcount protecting its lifetime. A concurrent close() on the linked stream's fd triggers snd_pcm_release_substream() =E2=86=92 snd_pcm_drop() =E2=86=92 pcm_release_= private() =E2=86=92 snd_pcm_unlink() =E2=86=92 snd_pcm_detach_substream() =E2=86=92 k= free(runtime). No synchronization prevents kfree(runtime) from completing while the drain path dereferences the stale pointer. Fix by caching the needed runtime fields (no_period_wakeup, rate, buffer_size) into local variables while still holding the stream lock, and using the cached values after the lock is released. Fixes: f2b3614cefb6 ("ALSA: PCM - Don't check DMA time-out too shortly") Cc: stable@vger.kernel.org Signed-off-by: Mehul Rao --- sound/core/pcm_native.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 67cf6a0e1..5a64453da 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2144,6 +2144,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *s= ubstream, for (;;) { long tout; struct snd_pcm_runtime *to_check; + unsigned int drain_rate; + snd_pcm_uframes_t drain_bufsz; + bool drain_no_period_wakeup; + if (signal_pending(current)) { result =3D -ERESTARTSYS; break; @@ -2163,16 +2167,25 @@ static int snd_pcm_drain(struct snd_pcm_substream *= substream, snd_pcm_group_unref(group, substream); if (!to_check) break; /* all drained */ + /* + * Cache the runtime fields needed after unlock. + * A concurrent close() on the linked stream may free + * its runtime via snd_pcm_detach_substream() once we + * release the stream lock below. + */ + drain_no_period_wakeup =3D to_check->no_period_wakeup; + drain_rate =3D to_check->rate; + drain_bufsz =3D to_check->buffer_size; init_waitqueue_entry(&wait, current); set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&to_check->sleep, &wait); snd_pcm_stream_unlock_irq(substream); - if (runtime->no_period_wakeup) + if (drain_no_period_wakeup) tout =3D MAX_SCHEDULE_TIMEOUT; else { tout =3D 100; - if (runtime->rate) { - long t =3D runtime->buffer_size * 1100 / runtime->rate; + if (drain_rate) { + long t =3D drain_bufsz * 1100 / drain_rate; tout =3D max(t, tout); } tout =3D msecs_to_jiffies(tout); -- 2.48.1