From nobody Wed Jun 10 17:09:26 2026 Received: from mail-pf1-f182.google.com (mail-pf1-f182.google.com [209.85.210.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 56A7C2D46B3 for ; Wed, 10 Jun 2026 02:47:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781059671; cv=none; b=DD+30OBqzMM0jLDBtvzKQnMyqunf6rd94UqiGgzP2sdRxCmqsZ+2HR0vCRrQIHYbszyMLqa5wryTcE0K4VJ780S/LFgXljHDuLsPPoi9ELEsc9UnftJ5cqiSVPLDGVrvYNTrB9QFZIx4sqsSosYp3Kofc4iicI4gJvfSSOb63gw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781059671; c=relaxed/simple; bh=EmwEENtoFqSJaXhbeXaOdb7JSa4NSdl6KFlGyf8RnLs=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=hu2K6LLtWHGxuxn5WOat6JcfRIUHv9e5ziehccpd3Gh5IuWDLXS0bL5k3DAAov9p07N9dU+iPFYGYDe2nStB2zHrh8a/+AeQX8VO7/OAbb/dCjVcm3VOjL1QMtOCFtNKJ9yDxaep5hRionAAQHZQ5lbmHJBfnrQxbPPpr/tBdYg= 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=ngKwHOEU; arc=none smtp.client-ip=209.85.210.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="ngKwHOEU" Received: by mail-pf1-f182.google.com with SMTP id d2e1a72fcca58-84229481d44so2541074b3a.0 for ; Tue, 09 Jun 2026 19:47:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1781059669; x=1781664469; 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=35TuUoWijKrP5hbQ/BkJXPLs6qJVhLfUp5AnFRUjILI=; b=ngKwHOEUXKl9B9XPmrN2507ShuluPuI0i9DPfyk17QHQhEWrBAJcEIFwGSs6PBKTLx ZLJyIRTp4uc2qFP6uiiUOvrK84AO7yW/ththK4LU+AB+lrOb7M7DnfWoMFZMigUToMiS Xwj+cHliJUusrh9E4+Kpgw9G3tV2gyOD1wccprZhoVXwR2ycbzEkEy1Yp6X+Wo7WUSwg PjeLvxk1STg6xxQrGSo+HsJy9FEvPK2rEmgZbs5owvUSwAGr0dBkL30jaRXrAlfZSTgd B66l5FA4k/24fdYnPu5UEw4uhHTYyonpFheX0xsd3oEmWJtVlOFB1qNdZcwWFkTE/5/Q q57w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781059669; x=1781664469; 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=35TuUoWijKrP5hbQ/BkJXPLs6qJVhLfUp5AnFRUjILI=; b=crN6G5KToikq5w/1X5zx1Me6sgfHQcpfuuA3Gv+Vrzd4JFd+BwsPtw5F5x0+Pd+Teo WO90SPJvZ59TNaZjYB9liXI8pdFPrb7xpqMSy0JzyOsgMaoS29Sg0RIwbtfyaSvnLgs7 NyRCYoqdMtaMMdUE8ns9jlERXjHfpQPfzJtU2fwEubC5YHmgrB3HoeLpFe1YSgf0ClEX DKBzI//1FJWamIkzUarFHtCXCGnNbKs9rt87mdYB+rEb8r64Zd5CnQxky2UZyph8B/51 WmT6hH/D7x4g+WH2CC+8ox6oQSKsAGEUM7XuIHcUKxrtOanuwXraZZ4CZgK6ai5mTCaH YHGA== X-Forwarded-Encrypted: i=1; AFNElJ+ngHJZhvpsr8WKFsECLfvKSoziFSwJdrcxvIBTY32fogweT2IAhZFGEdZuDytGVnFuMJLdOnAcq4VjB7Y=@vger.kernel.org X-Gm-Message-State: AOJu0YyTcankxc7WKtRRmJk/qKGMnH9bAjoz/fXHL5TiTficN4jc0dBT CUKc6FHdRx61hZamu/Vffh1tIsgQYuMy8Xuu2B6/s3L/fcWlANfixfUm X-Gm-Gg: Acq92OEciiOr3n7iYHUKxoalsi/i6leHZB1PR+ZO0UzCpKI5r0LXTowOA/2CvhZ/xtA NHzLdR13TSxvHB28E87qz4XqyAZQCWIRiBsG31nPAy9jzRO3pAkcJxZT8PWBfFcFsWfktKEhB9q tM7i77bAbxqkxBgzShdeoBYBpCPjOWEspOA4KUhstCNIH1WR5vfZzDnQLEm3k4dThXu2Q8qDkSr pGezPp2ceplGkGrPfS8akh+9zkxK9ihzrXdwU/jOrIP9elh8WSf1AzwRokcZk0KRQd0OSMOMsne ZB8b1to0S+O/Wxw80Qe1S1/YaXyNPpcHg8c1v+K4ao0PJip9jXSCDudDkzmX4p7qFwchoRYEw5Q xGc/y/I2IdnwdubaNEKm8IFIctcgQezFlF+a+tv/1qjFELJQnw+n1pduSOQLRvVGZsKKF13AQDc EdU+z30kFnrOQnHElNqp6mZWnEs02wSOkVoZXKyZ6fKiiI1lJXr1gMxpp0aTPpj94Ka7it9eaIt eBXTPstBRMfQQSUuXYsmTTaH71fw4euR9Sh X-Received: by 2002:a05:6a00:12de:b0:842:5b66:3c7f with SMTP id d2e1a72fcca58-842b0a7d365mr23486559b3a.0.1781059669465; Tue, 09 Jun 2026 19:47:49 -0700 (PDT) Received: from secrnd-cstp.tailb7f510.ts.net ([125.131.91.97]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-84282916b10sm22882799b3a.58.2026.06.09.19.47.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 09 Jun 2026 19:47:48 -0700 (PDT) From: Sanghyun Park To: Yonghong Song , Alexei Starovoitov , Daniel Borkmann , Andrii Nakryiko Cc: Sanghyun Park , Martin KaFai Lau , Eduard Zingerman , Song Liu , Kumar Kartikeya Dwivedi , John Fastabend , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , Emil Tsalapatis , Puranjay Mohan , bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v4] bpf: Fix use-after-free on mm_struct in bpf_find_vma() Date: Wed, 10 Jun 2026 11:46:36 +0900 Message-ID: <20260610024637.343364-1-sanghyun.park.cnu@gmail.com> X-Mailer: git-send-email 2.48.1 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 Content-Type: text/plain; charset="utf-8" bpf_find_vma() reads task->mm and calls mmap_read_trylock(mm) without holding a reference on the mm. On a foreign task, a concurrent exit_mm() can free the mm_struct between the lockless read and the trylock, resulting in a use-after-free. mm_struct is not SLAB_TYPESAFE_BY_RCU. For the current task, task->mm is stable. For a foreign task, pin the mm under task->alloc_lock and release it with mmput_async(), mirroring commit d8e27d2d22b6 ("bpf: fix mm lifecycle in open-coded task_vma iterator"). Use spin_trylock() instead of get_task_mm() so BPF context does not block on alloc_lock. Reject irqs-disabled contexts and !CONFIG_MMU on the foreign-task path because dropping the mm reference is not safe there. Race: CPU0 (BPF program) CPU1 (exiting task) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D bpf_find_vma(foreign_task): mm =3D task->mm exit_mm(): task->mm =3D NULL mmput(mm) -> frees mm_struct mmap_read_trylock(mm) // UAF on mm Fixes: 7c7e3d31e785 ("bpf: Introduce helper bpf_find_vma") Signed-off-by: Sanghyun Park --- v4: - Use [PATCH bpf-next] subject as requested by Alexei. - Add the missing BPF maintainers/reviewers to Cc. v3: https://lore.kernel.org/bpf/20260609105216.3536839-1-sanghyun.park.cnu@= gmail.com/ - Drop get_task_mm()+mmput(); mirror d8e27d2d22b6 with alloc_lock trylock + mmput_async(). (Yonghong Song) - Reject irqs-disabled contexts on the foreign-task path. - Reject foreign-task path when !CONFIG_MMU: bpf_iter_mmput_async() falls back to mmput() which may sleep, and bpf_find_vma() can run in non-sleepable context. - Shorten the foreign-task rationale comment and trim the changelog body. - Fix the v2's whitespace damage. v2: https://lore.kernel.org/bpf/CAOrxSK5_7e4114VyfEU9htGi+UneuNt88fGVKOAa3_= ZenPOFkA@mail.gmail.com/ kernel/bpf/task_iter.c | 50 +++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c index fc5f463ca5..baee813290 100644 --- a/kernel/bpf/task_iter.c +++ b/kernel/bpf/task_iter.c @@ -754,12 +754,22 @@ static struct bpf_iter_reg task_vma_reg_info =3D { .show_fdinfo =3D bpf_iter_task_show_fdinfo, }; =20 +static inline void bpf_iter_mmput_async(struct mm_struct *mm) +{ +#ifdef CONFIG_MMU + mmput_async(mm); +#else + mmput(mm); +#endif +} + BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u64, start, bpf_callback_t, callback_fn, void *, callback_ctx, u64, flags) { struct mmap_unlock_irq_work *work =3D NULL; struct vm_area_struct *vma; bool irq_work_busy =3D false; + bool mmput_needed =3D false; struct mm_struct *mm; int ret =3D -ENOENT; =20 @@ -769,14 +779,38 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, = u64, start, if (!task) return -ENOENT; =20 - mm =3D task->mm; + if (task =3D=3D current) { + mm =3D task->mm; + } else { + /* + * Foreign task: pin task->mm against a concurrent exit_mm(). + * Use trylock on alloc_lock instead of get_task_mm()'s + * blocking task_lock() to avoid deadlocking the target task. + */ + if (!IS_ENABLED(CONFIG_MMU)) + return -EOPNOTSUPP; + if (irqs_disabled()) + return -EBUSY; + if (!spin_trylock(&task->alloc_lock)) + return -EBUSY; + mm =3D task->mm; + if (mm && !(task->flags & PF_KTHREAD)) { + mmget(mm); + mmput_needed =3D true; + } else { + mm =3D NULL; + } + spin_unlock(&task->alloc_lock); + } if (!mm) return -ENOENT; =20 irq_work_busy =3D bpf_mmap_unlock_get_irq_work(&work); =20 - if (irq_work_busy || !mmap_read_trylock(mm)) - return -EBUSY; + if (irq_work_busy || !mmap_read_trylock(mm)) { + ret =3D -EBUSY; + goto out; + } =20 vma =3D find_vma(mm, start); =20 @@ -786,6 +820,9 @@ BPF_CALL_5(bpf_find_vma, struct task_struct *, task, u6= 4, start, ret =3D 0; } bpf_mmap_unlock_mm(work, mm); +out: + if (mmput_needed) + bpf_iter_mmput_async(mm); return ret; } =20 @@ -800,15 +837,6 @@ const struct bpf_func_proto bpf_find_vma_proto =3D { .arg5_type =3D ARG_ANYTHING, }; =20 -static inline void bpf_iter_mmput_async(struct mm_struct *mm) -{ -#ifdef CONFIG_MMU - mmput_async(mm); -#else - mmput(mm); -#endif -} - struct bpf_iter_task_vma_kern_data { struct task_struct *task; struct mm_struct *mm; --=20 2.48.1