From nobody Sat Feb 7 21:11:10 2026 Received: from mail-oa1-f69.google.com (mail-oa1-f69.google.com [209.85.160.69]) (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 A5FD5212FB3 for ; Fri, 9 Jan 2026 16:23:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767975814; cv=none; b=EEt/c62K/Vm68xQsH8MGK1kp13v9H7nca+tDfeinRr/Njcxp8Rv1dn0Iqnim7LrS67Ah8WLpl6rd4KdsosrNtgPbEUMzRb8nuYpRzQ3SMXog92vzsawNyv9wk9kBNOb/I2VzwYye+lz/mOiYf8zq2He2sqzmF3aWEXIkZ9Bz+Uk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767975814; c=relaxed/simple; bh=TgH/963LYlVjVSTIgAHqoIrQgNJdr22gOqo5OwXKVy8=; h=MIME-Version:Date:In-Reply-To:Message-ID:Subject:From:To: Content-Type; b=YDjI1/zFdwFR5SyAcxN6Aigj1D9/J9YjXyve5qbNi1iYkqowSGC7CIa/RGFys0N+MxLYk1WYsOoeYqoNCUmy7hcfZqmRJALODuySO5x/xxCNrcRA0MqW79yrBt+Qb6Zw91oqgO9dVtnrf+whDWB7mdpmpmWF8NJa66xM6eyNNsM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com; arc=none smtp.client-ip=209.85.160.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com Received: by mail-oa1-f69.google.com with SMTP id 586e51a60fabf-3f9ac407848so7762619fac.2 for ; Fri, 09 Jan 2026 08:23:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767975811; x=1768580611; h=to:from:subject:message-id:in-reply-to:date:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=KDWNkkc/kXDpovOcEGvCLF+jxPP1Dk7DoHcNbR2c7Gs=; b=sw8l6SDDGEG6DRtfYv4HEJ8BJlZfll2fAOlSSscbeBxhve26DKbvJhOV8OcsML7aEW 3kFqxuCcrej81xARJCdc6M0WygntuPF+7H3aMU89rpijMrZByyfpXXIoZGNuh93kEL28 QxLWr44Pbgd+4X7wxFI516fFMm/Vc3P8Eq4vlrcNpjyqJtlTmZ3uJz7myMnoouclP70r yVcQH0nX6eOyCx3UyM9TRzTWkm0FkOBWh2UGqwCOMDokhrlkKlanchSP+Mor0LP+YIWn lUA9dDr7r1CKjJ4npaUJkxBtw0jCyCKwcE8p1DCwUjdm9WkuyBUotJuzc5CyPKc8hlho pPbA== X-Gm-Message-State: AOJu0YwcitY4qb1SraM9N9QDRSHOE7ERc6+rc8JJmYUInAg/b4GT4Wd2 9MK11c7zVeGb3wkrvDNqYzeS9YILluHzRbquSoqW7Fp5+m9ln1ZwsncWI+QCr5+Y2o6viuM4OY0 6URo7PgVNzeXD0tTwH9/vC4qnYpXhKsyhOPohkblQaoubvzQKfhupPN0kuvI= X-Google-Smtp-Source: AGHT+IH7Qp5ECu4nzXSsGkg6D3Bw/uo0fadOock29ykKhpFk//8zjS54Wutg9mki3/m4R1mzwJ0XSi73oJoLqK6+/QyGDkBixgqS Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Received: by 2002:a05:6820:1c91:b0:659:9a49:8fbc with SMTP id 006d021491bc7-65f54f73a66mr5867582eaf.53.1767975811691; Fri, 09 Jan 2026 08:23:31 -0800 (PST) Date: Fri, 09 Jan 2026 08:23:31 -0800 In-Reply-To: <6960c2f0.050a0220.1c677c.03be.GAE@google.com> X-Google-Appengine-App-Id: s~syzkaller X-Google-Appengine-App-Id-Alias: syzkaller Message-ID: <69612b83.050a0220.1c677c.03cf.GAE@google.com> Subject: Forwarded: [PATCH] mm/swap_cgroup: fix kernel BUG in swap_cgroup_record From: syzbot To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: [PATCH] mm/swap_cgroup: fix kernel BUG in swap_cgroup_record Author: kartikey406@gmail.com #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.gi= t master When using MADV_PAGEOUT, pages can remain in swapcache with their swap entries assigned. If MADV_PAGEOUT is called again on these pages, they reuse the same swap entries, causing memcg1_swapout() to call swap_cgroup_record() with an already-recorded entry. The existing code assumes swap entries are always being recorded for the first time (oldid =3D=3D 0), triggering VM_BUG_ON when it encounters an already-recorded entry: ------------[ cut here ]------------ kernel BUG at mm/swap_cgroup.c:78! Oops: invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 0 UID: 0 PID: 6176 Comm: syz.0.30 Not tainted RIP: 0010:swap_cgroup_record+0x19c/0x1c0 mm/swap_cgroup.c:78 Call Trace: memcg1_swapout+0x2fa/0x830 mm/memcontrol-v1.c:623 __remove_mapping+0xac5/0xe30 mm/vmscan.c:773 shrink_folio_list+0x2786/0x4f40 mm/vmscan.c:1528 reclaim_folio_list+0xeb/0x4e0 mm/vmscan.c:2208 reclaim_pages+0x454/0x520 mm/vmscan.c:2245 madvise_cold_or_pageout_pte_range+0x19a0/0x1ce0 mm/madvise.c:563 ... do_madvise+0x1bc/0x270 mm/madvise.c:2030 __do_sys_madvise mm/madvise.c:2039 This bug occurs because pages in swapcache can be targeted by MADV_PAGEOUT multiple times without being swapped in between. Each time, the same swap entry is reused, but swap_cgroup_record() expects to only record new, unused entries. Fix this by checking if the swap entry already has the correct cgroup ID recorded before attempting to record it. Add a new helper function swap_cgroup_lookup() to read the current cgroup ID without modifying it. In memcg1_swapout(), check if the entry is already correctly recorded and return early if so, avoiding unnecessary work and the crash. Only call swap_cgroup_record() when the entry needs to be set or updated. This approach is more efficient than making swap_cgroup_record() idempotent, as it avoids unnecessary atomic operations, reference count manipulations, and statistics updates when the entry is already correct. Link: https://syzkaller.appspot.com/bug?extid=3Dd97580a8cceb9b03c13e Reported-by: syzbot+d97580a8cceb9b03c13e@syzkaller.appspotmail.com Signed-off-by: Deepanshu Kartikey --- include/linux/swap_cgroup.h | 6 ++++++ mm/memcontrol-v1.c | 7 +++++++ mm/swap_cgroup.c | 18 ++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/include/linux/swap_cgroup.h b/include/linux/swap_cgroup.h index 91cdf12190a0..fd79e7bf8917 100644 --- a/include/linux/swap_cgroup.h +++ b/include/linux/swap_cgroup.h @@ -7,6 +7,7 @@ #if defined(CONFIG_MEMCG) && defined(CONFIG_SWAP) =20 extern void swap_cgroup_record(struct folio *folio, unsigned short id, swp= _entry_t ent); +extern unsigned short swap_cgroup_lookup(swp_entry_t ent); extern unsigned short swap_cgroup_clear(swp_entry_t ent, unsigned int nr_e= nts); extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent); extern int swap_cgroup_swapon(int type, unsigned long max_pages); @@ -19,6 +20,11 @@ void swap_cgroup_record(struct folio *folio, unsigned sh= ort id, swp_entry_t ent) { } =20 +static inline unsigned short swap_cgroup_lookup(swp_entry_t ent) +{ + return 0; +} + static inline unsigned short swap_cgroup_clear(swp_entry_t ent, unsigned int nr_ents) { diff --git a/mm/memcontrol-v1.c b/mm/memcontrol-v1.c index 56d27baf93ab..37899d156b2a 100644 --- a/mm/memcontrol-v1.c +++ b/mm/memcontrol-v1.c @@ -614,6 +614,7 @@ void memcg1_swapout(struct folio *folio, swp_entry_t en= try) { struct mem_cgroup *memcg, *swap_memcg; unsigned int nr_entries; + unsigned short oldid; =20 VM_BUG_ON_FOLIO(folio_test_lru(folio), folio); VM_BUG_ON_FOLIO(folio_ref_count(folio), folio); @@ -630,6 +631,12 @@ void memcg1_swapout(struct folio *folio, swp_entry_t e= ntry) if (!memcg) return; =20 + oldid =3D swap_cgroup_lookup(entry); + if (oldid =3D=3D mem_cgroup_id(memcg)) { + return; + } + VM_WARN_ON_ONCE(oldid !=3D 0); + /* * In case the memcg owning these pages has been offlined and doesn't * have an ID allocated to it anymore, charge the closest online diff --git a/mm/swap_cgroup.c b/mm/swap_cgroup.c index de779fed8c21..083eda4b67d6 100644 --- a/mm/swap_cgroup.c +++ b/mm/swap_cgroup.c @@ -51,6 +51,24 @@ static unsigned short __swap_cgroup_id_xchg(struct swap_= cgroup *map, return old_id; } =20 +unsigned short swap_cgroup_lookup(swp_entry_t ent) +{ + struct swap_cgroup *sc; + unsigned short id; + pgoff_t offset =3D swp_offset(ent); + unsigned short type =3D swp_type(ent); + + if (type >=3D MAX_SWAPFILES) + return 0; + + sc =3D swap_cgroup_ctrl[type].map; + if (!sc) + return 0; + id =3D (unsigned short)atomic_read(&sc[offset].ids); + return id; + +} + /** * swap_cgroup_record - record mem_cgroup for a set of swap entries. * These entries must belong to one single folio, and that folio --=20 2.43.0