From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) (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 48ECC3F1AC5 for ; Tue, 21 Jul 2026 00:56:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.71 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784595415; cv=none; b=bGKH1eTQinRzoZSfzpEbsPqVwboUkR82RL50G9cwvuLKm3a4Qabn+qLnRXZIJColviN/ZVkWPO9xA+pfzBqJoPBmrVFU9X2PtdLQdsUgk/wzyComEUK9K6SIKMCTz5VNaY9Fe3RWKdKi/eYq2lr6ig1uDyiukHPMgQWShzv3v9k= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784595415; c=relaxed/simple; bh=Jf1Z3wiUSnHmBFlRFZCz2LuluHz3SAmuUlW9niHQURk=; h=Date:Mime-Version:Message-ID:Subject:From:To:Cc:Content-Type; b=jZCXrW++FQTeQZvN3BTgPgr9Ea0N9HVAdiHqSOUwguUN2vRyPbe7qtK2JUlZazzaHbc8qkigCdIrnITtRnfBWSQtwI/LoOiOdzUo7LNY6f2B6sVDuR23rfwvD4F8a+Hyk415MPKo4p/mbRW0tntrH0IvpUhRISNWm2l/vPC9wwQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--linkl.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=uWkvLRDu; arc=none smtp.client-ip=209.85.216.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--linkl.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="uWkvLRDu" Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-38e11baa66eso7854453a91.2 for ; Mon, 20 Jul 2026 17:56:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1784595413; x=1785200213; darn=vger.kernel.org; h=content-transfer-encoding:content-type:cc:to:from:subject :message-id:mime-version:date:from:to:cc:subject:date:message-id :reply-to:content-type; bh=dVZeqaiAWbMoulLNM+KQI45sBsT7cMtZAQ/ZsFxQyUg=; b=uWkvLRDuIH5GwwcXgN/lksml84qS2O99TXiJ+F4TJhOWNF73jvkjjXYjw4+apg1jkw rQqEfZtacBZBlsfRkRDgEXdJPCrlZUYwIkm2U2Cs+E2dI3PNnePfs6y5wbjTkUe6/6/e mTK0gp2FxewKOYgZ33sYnifs1tiXd/TweUx6u4aw/yHfsf1zRMpZa9GWM9DzMtWJshbY 6zl6YKhqt2wGdz0Lwdg1LK+XFU+HBoOoHXpzzJCNdKT181uzQ444wSaQKC4J1qPUQwPL QWluCytdz44cFDP/R5yY4tlVj1x4J5NvqnL83AcuTty5Wlh8OlVmELJnHNybOjR0SRTq mxNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784595413; x=1785200213; h=content-transfer-encoding:content-type:cc:to:from:subject :message-id:mime-version:date:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to:content-type; bh=dVZeqaiAWbMoulLNM+KQI45sBsT7cMtZAQ/ZsFxQyUg=; b=sAV7mA0/1356kgq62AAiXvTie+CaKenDA8BQxWLjbio11XRFV5Y4Flk96y7aSpXO1e u3ata+3/jCdARF8Xf5OikURhqDMiZ2bm5YC6jIyJoLwNg0V+dz6S/W71N1m35z4Gk7yf 7kjQ3cf0W+UBGsDf1HWN0mLmzY4DvR+aHzj+enHPLklDtoJjhZNpXQ8BWQ5iUIujLeiT +Jk0RYovRvKxERo2NijU+DKQ7f5wr9GmlJIQDqJo8HCIh5vUVEucrARAyrb7lCUJl4kV rnF/NbQCv+mprL/3YOIDaARS2+UguQDRyWBG38J6cKWR3dxhxE2AcC5RTy0HKYsgjEC0 Uo3A== X-Forwarded-Encrypted: i=1; AHgh+RoF7K29r/Sg0B/S4Z3O8uX+RH9Nfl5ksaaOJEwy4hDwqHdWHbENcEw6waKbePPkmO9pl2SotH2pr6sIRJE=@vger.kernel.org X-Gm-Message-State: AOJu0YypynSN9pFYJUDnSoTcMPTxWSaVmIhz+hUD/3KmrMpM6H+UrdPl 6FSU0Tvom7iANH5ePubqvOv5s4MRRD6g7Docd/R71AxyGooFZVU7kY/1hw7Co+YXOvzEu0wqOyj 0Eg== X-Received: from pjbng10.prod.google.com ([2002:a17:90b:1a8a:b0:38e:7f2c:2c4b]) (user=linkl job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:3886:b0:36b:944b:fd81 with SMTP id 98e67ed59e1d1-38e4b3d27c3mr16883838a91.4.1784595413290; Mon, 20 Jul 2026 17:56:53 -0700 (PDT) Date: Tue, 21 Jul 2026 00:55:33 +0000 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 X-Mailer: git-send-email 2.55.0.229.g6434b31f56-goog Message-ID: <20260721005603.1710551-1-linkl@google.com> Subject: [PATCH v3] mm/page_reporting: use system_freezable_wq to fix UAF during suspend From: Link Lin To: Andrew Morton , Vlastimil Babka , "Michael S . Tsirkin" , David Hildenbrand Cc: virtualization@lists.linux.dev, linux-mm@kvack.org, linux-kernel@vger.kernel.org, prasin@google.com, rientjes@google.com, duenwen@google.com, jasowang@redhat.com, xuanzhuo@linux.alibaba.com, Ammar Faizi , jiaqiyan@google.com, ahwilkins@google.com, Greg Thelen , Alexander Duyck , jthoughton@google.com, stable@vger.kernel.org, Link Lin Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable During PM freeze (e.g. S3 suspend or S4 hibernation), device drivers like virtio_balloon reset their underlying virtio devices and delete their virtqueues via vdev->config->del_vqs(). However, page reporting work (page_reporting_process) was scheduled on the global system_wq. Because system_wq lacks the WQ_FREEZABLE flag, the PM freezer skips it, leaving page_reporting_process active during suspend. If pages are freed into the buddy allocator while suspending (for example, when core MM invokes the balloon shrinker during S4 hibernation image saving), page reporting triggers virtballoon_free_page_report() on deleted virtqueues, resulting in a Use-After-Free / General Protection Fault: [ 196.795226] general protection fault, probably for non-canonical add= ress 0xaa1436fe70dae6df: 0000 [#1] SMP NOPTI [ 196.825967] Workqueue: events page_reporting_process [ 196.831038] RIP: 0010:virtqueue_add_split+0x233/0x4c0 [virtio_ring] [ 196.927073] virtballoon_free_page_report+0x3a/0xe0 [virtio_balloon] [ 196.946943] page_reporting_process+0x370/0x4f0 Fix this by switching page reporting work to system_freezable_wq. This ensures that the PM freezer pauses page_reporting_process before device drivers destroy their reporting virtqueues. Because the reporting worker is frozen, memory reclamation/freeing (e.g. via shrinker execution) can safely return pages to MM during freeze without triggering unfrozen reporting work on deleted virtqueues. This aligns with the driver's existing design. The comment in virtballoon_freeze() states: /* * The workqueue is already frozen by the PM core before this * function is called. */ Testing: I have verified these fixes using Google=E2=80=99s virtualization infrastru= cture by running continuous suspend/resume iterations (40+ cycles) while churning memory using stress-ng (`stress-ng --vm 4 --vm-bytes 60% --timeout 1`) to constantly create free pages for the buddy allocator. We also set the `page_reporting_order` parameter to 0 to make the page reporting worker highly sensitive, forcing it to pick up any 4K free pages. This confirmed that the UAF crashes are no longer reproducible. Fixes: 924a663f75e2 ("virtio-balloon: Reporting free page reservations") Cc: stable@vger.kernel.org Suggested-by: David Hildenbrand (Arm) Suggested-by: Michael S. Tsirkin Acked-by: David Rientjes Acked-by: David Hildenbrand (Arm) Acked-by: Michael S. Tsirkin Signed-off-by: Link Lin --- v3: - Dropped Patch 2/2 (virtio_balloon shrinker flag). Freeing pages via the shrinker only returns pages to MM; with page reporting work now properly serialized on system_freezable_wq, shrinker execution during freeze is harmless and requires no additional locking/flags in virtio_balloon. - Link to v2: https://lore.kernel.org/all/20260717002311.681748-1-linkl@g= oogle.com/ v2: - Split into a 2-patch series including explicit shrinker fencing. - Link to RFC: https://lore.kernel.org/all/20260709224330.946683-1-linkl@= google.com/ mm/page_reporting.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/page_reporting.c b/mm/page_reporting.c index 7418f2e500..4dc6f4b852 100644 --- a/mm/page_reporting.c +++ b/mm/page_reporting.c @@ -80,7 +80,8 @@ __page_reporting_request(struct page_reporting_dev_info *= prdev) * now we are limiting this to running no more than once every * couple of seconds. */ - schedule_delayed_work(&prdev->work, PAGE_REPORTING_DELAY); + queue_delayed_work(system_freezable_wq, &prdev->work, + PAGE_REPORTING_DELAY); } =20 /* notify prdev of free page reporting request */ @@ -343,7 +344,8 @@ static void page_reporting_process(struct work_struct *= work) */ state =3D atomic_cmpxchg(&prdev->state, state, PAGE_REPORTING_IDLE); if (state =3D=3D PAGE_REPORTING_REQUESTED) - schedule_delayed_work(&prdev->work, PAGE_REPORTING_DELAY); + queue_delayed_work(system_freezable_wq, &prdev->work, + PAGE_REPORTING_DELAY); } =20 static DEFINE_MUTEX(page_reporting_mutex); --=20 2.55.0