From nobody Wed Dec 17 16:02:48 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A97BC05052 for ; Fri, 18 Aug 2023 06:07:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358018AbjHRGGr (ORCPT ); Fri, 18 Aug 2023 02:06:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34086 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358010AbjHRGGM (ORCPT ); Fri, 18 Aug 2023 02:06:12 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 74E5F3A9A for ; Thu, 17 Aug 2023 23:06:00 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id D24E363DA9 for ; Fri, 18 Aug 2023 06:05:59 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id E04F4C433C9; Fri, 18 Aug 2023 06:05:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1692338759; bh=uh54hFbXQ/BfwpWzs/O+bKFUYp44N50ejYnxz4It+b0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=fnqnrGAnVQyXR1SS/0NXCLMP1X7tRNAp9dB+8XKfYgRvzDsbTaFsi/rxhGGW7IuU6 +e+pSg5knwNBoIguA8cF0CMjDF1mPQDAkkk9o5tHAQ1OIq15vvfagkUnN3UFVye4IA y7lSunNnzFdJ/gUaPDMcBUoVZv+xg5EquAfE4ZPclYglXa8Za+JGEctXzdz7xeMloE 7mipOXKSkwoNk+FJr0D+wIuuVlS5ESh4VTmOWRr5QBhsAx/fkt4lEZ6pdYaQ4ks/gU lPmxLd+NP4xvTdrGiwzYT6oBBvS6WT61fjeX0zl7HnBKfWhszwBaWETEUil8nFwrdT +JCr7unUVIkXg== From: Chris Li Date: Thu, 17 Aug 2023 23:05:23 -0700 Subject: [PATCH RFC 1/2] mm/page_alloc: safeguard free_pcppages_bulk MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20230817-free_pcppages_bulk-v1-1-c14574a9f80c@kernel.org> References: <20230817-free_pcppages_bulk-v1-0-c14574a9f80c@kernel.org> In-Reply-To: <20230817-free_pcppages_bulk-v1-0-c14574a9f80c@kernel.org> To: Andrew Morton , Kemeng Shi Cc: akpm@linux-foundation.org, baolin.wang@linux.alibaba.com, mgorman@techsingularity.net, Michal Hocko , david@redhat.com, willy@infradead.org, linux-mm@kvack.org, Namhyung Kim , Greg Thelen , linux-kernel@vger.kernel.org, Chris Li , John Sperbeck X-Mailer: b4 0.12.2 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current free_pcppages_bulk() can panic when pcp->count is changed outside of this function by the BPF program injected in ftrace function entry. Commit c66a36af7ba3a628 was to fix on the BPF program side to not allocate memory inside the spinlock. But the kernel can still panic loading similar BPF without the fix. Here is the step to reproduce it: $ git checkout 19030564ab116757e32 $ cd tools/perf $ make perf $ ./perf lock con -ab -- ./perf bench sched messaging You should be able to see the kernel panic within 20 seconds. Here is what happened in the panic: count =3D min(pcp->count, count); free_pcppages_bulk() assumes count and pcp->count are in sync. There are no pcp->count changes outside of this function. That assumption gets broken when BPF lock contention code allocates memory inside spinlock. pcp->count is one less than "count". The loop only checks against "count" and runs into a deadloop because pcp->count drops to zero and all lists are empty. In a deadloop pindex_min can grow bigger than pindex_max and pindex_max can lower to negative. The kernel panic is happening on the pindex trying to access outside of pcp->lists ranges. Notice that this is just one of the (buggy) BPF programs that can break it. Other than the spin lock, there are other function tracepoints under this function can be hooked up to the BPF program which can allocate memory and change the pcp->count. One argument is that BPF should not allocate memory under the spinlock. On the other hand, the kernel can just check pcp->count inside the loop to avoid the kernel panic. Signed-off-by: Chris Li Reported-by: John Sperbeck --- mm/page_alloc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 1eb3864e1dbc7..347cb93081a02 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1215,12 +1215,6 @@ static void free_pcppages_bulk(struct zone *zone, in= t count, bool isolated_pageblocks; struct page *page; =20 - /* - * Ensure proper count is passed which otherwise would stuck in the - * below while (list_empty(list)) loop. - */ - count =3D min(pcp->count, count); - /* Ensure requested pindex is drained first. */ pindex =3D pindex - 1; =20 @@ -1266,7 +1260,7 @@ static void free_pcppages_bulk(struct zone *zone, int= count, =20 __free_one_page(page, page_to_pfn(page), zone, order, mt, FPI_NONE); trace_mm_page_pcpu_drain(page, order, mt); - } while (count > 0 && !list_empty(list)); + } while (count > 0 && pcp->count > 0 && !list_empty(list)); } =20 spin_unlock_irqrestore(&zone->lock, flags); --=20 2.42.0.rc1.204.g551eb34607-goog From nobody Wed Dec 17 16:02:48 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 88D99C7113B for ; Fri, 18 Aug 2023 06:07:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1358006AbjHRGGo (ORCPT ); Fri, 18 Aug 2023 02:06:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1358009AbjHRGGM (ORCPT ); Fri, 18 Aug 2023 02:06:12 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ACC3D3A9C for ; Thu, 17 Aug 2023 23:06:00 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 4326463E81 for ; Fri, 18 Aug 2023 06:06:00 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6090DC433CC; Fri, 18 Aug 2023 06:05:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1692338759; bh=PTFvK66aSpc/wWYXL1tG3ENdFiVUZlkQu/DReJnqKDo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=bbOTWJ6hSKJFcss5lL+TZpqq6+IGVcsiAeVbsSyFwYW+JEYg7RhWRlkI7cxWfBWZf 76/MXNfx+Co4g9cC8KsCqjeTj1uY1hjSffEqPmKzAaZ5HYLN7P8dYTYPk96SyMaT6p 3mDVpiYFix5Vwe3HjrP2w6PxKfW7tCrrw2a9HZalQ8399I/IMvWZ5vndleGZb8Lu4w jVMnbDZaGygfjf7W++mxpohOYkARhyjCsOUIcfwXM2rRQcTouyZUrWIt0dJNFHh0Md Nx8cfMGpk0/gIXyEjho2O2qu9ljHiGQWxobEmRC40zT6fPvPn6x4Jcq25ZwqVdmr2r x9InBHdTcsCKA== From: Chris Li Date: Thu, 17 Aug 2023 23:05:24 -0700 Subject: [PATCH RFC 2/2] mm/page_alloc: free_pcppages_bulk clean up MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20230817-free_pcppages_bulk-v1-2-c14574a9f80c@kernel.org> References: <20230817-free_pcppages_bulk-v1-0-c14574a9f80c@kernel.org> In-Reply-To: <20230817-free_pcppages_bulk-v1-0-c14574a9f80c@kernel.org> To: Andrew Morton , Kemeng Shi Cc: akpm@linux-foundation.org, baolin.wang@linux.alibaba.com, mgorman@techsingularity.net, Michal Hocko , david@redhat.com, willy@infradead.org, linux-mm@kvack.org, Namhyung Kim , Greg Thelen , linux-kernel@vger.kernel.org, Chris Li X-Mailer: b4 0.12.2 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch does not have functional change. Just pure clean up. It removes the pindex_max and pindex_min and replaces it with a simpler loop. It uses for_each_entry_safe_reverse() to replace the loop over list_last_entry(). It produces slightly=C2=A0better machine code. Signed-off-by: Chris Li --- mm/page_alloc.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 347cb93081a02..d64d0f5ec70b4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1209,11 +1209,9 @@ static void free_pcppages_bulk(struct zone *zone, in= t count, int pindex) { unsigned long flags; - int min_pindex =3D 0; - int max_pindex =3D NR_PCP_LISTS - 1; unsigned int order; bool isolated_pageblocks; - struct page *page; + int i; =20 /* Ensure requested pindex is drained first. */ pindex =3D pindex - 1; @@ -1221,31 +1219,18 @@ static void free_pcppages_bulk(struct zone *zone, i= nt count, spin_lock_irqsave(&zone->lock, flags); isolated_pageblocks =3D has_isolate_pageblock(zone); =20 - while (count > 0) { + for (i =3D 0; i < NR_PCP_LISTS; i++, pindex++) { struct list_head *list; int nr_pages; + struct page *page, *next; =20 - /* Remove pages from lists in a round-robin fashion. */ - do { - if (++pindex > max_pindex) - pindex =3D min_pindex; - list =3D &pcp->lists[pindex]; - if (!list_empty(list)) - break; - - if (pindex =3D=3D max_pindex) - max_pindex--; - if (pindex =3D=3D min_pindex) - min_pindex++; - } while (1); - + if (pindex =3D=3D NR_PCP_LISTS) + pindex =3D 0; + list =3D pcp->lists + pindex; order =3D pindex_to_order(pindex); nr_pages =3D 1 << order; - do { - int mt; - - page =3D list_last_entry(list, struct page, pcp_list); - mt =3D get_pcppage_migratetype(page); + list_for_each_entry_safe_reverse(page, next, list, lru) { + int mt =3D get_pcppage_migratetype(page); =20 /* must delete to avoid corrupting pcp list */ list_del(&page->pcp_list); @@ -1260,9 +1245,12 @@ static void free_pcppages_bulk(struct zone *zone, in= t count, =20 __free_one_page(page, page_to_pfn(page), zone, order, mt, FPI_NONE); trace_mm_page_pcpu_drain(page, order, mt); - } while (count > 0 && pcp->count > 0 && !list_empty(list)); - } =20 + if (count <=3D 0 || pcp->count <=3D 0) + goto out; + } + } +out: spin_unlock_irqrestore(&zone->lock, flags); } =20 --=20 2.42.0.rc1.204.g551eb34607-goog