From nobody Sun Feb 8 00:12:20 2026 Received: from mail-qv1-f67.google.com (mail-qv1-f67.google.com [209.85.219.67]) (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 6252A2D9ED1 for ; Mon, 19 Jan 2026 07:10:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.67 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768806649; cv=none; b=cehhhM007XxtJfmVqtQorHClEzYMYUH/uLz150R8ihEDU1UcaJDvc6oacNkIuXHP8RcBN7g2Y9Hfn+Z1yQ8bS8u5fBnCXyZLA7m0cl2FEOuhuwTootZ2jqd6ZdTH6h5lpsslwRH9/HnH2ELeLUmEs95pOjHA5NO+sed1d6f5SwE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1768806649; c=relaxed/simple; bh=S3Y98FFWgoY8a3pcnPVFBrL19HFaL0F70zFtuxAOCe0=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=b50ZYRw7lC9Bw76sWXfdkPTspmCXOUgYZFxksnoO0JNUATBRvdpoZiMaZOaQjIRb0kDQ1xk8R6G+5d/sCtSwKXjbMeQFrmcFZCQ4dboE/B2VhZ5UdhqrN+cJ7yme3fwjzGfeW9185QJFsdu2T3jdera0KsoSI8itm8qbBczA9EI= 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=M7sgr0tg; arc=none smtp.client-ip=209.85.219.67 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="M7sgr0tg" Received: by mail-qv1-f67.google.com with SMTP id 6a1803df08f44-88a2e3bd3cdso40589556d6.0 for ; Sun, 18 Jan 2026 23:10:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1768806647; x=1769411447; 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=gKM15vI5ObaHuQbAnvaLHXhQIMY9SS6X3bJEvEg+p4E=; b=M7sgr0tgEqxU85NZwJXA0fJ7ksaOXe6UK4eRTS1rsoNH5NYiD/ICYEV2fV4Z2JLz6l Zk4FHXMO3n7O612o9SENbGsWzYCqdU6ol8hUShUZB1aNN3m3oviyUIPufkPTTwJ13121 RNHk7ACCZ2/tZrhcbqAH0QRRqpwYZCjjRMkWLwymPK3K2jfIw5uyGLj09Gq869sDSR8/ 8M81UMFqjq0CaeHK6jvN0h8hMq1wIq9LTga5offRTuTcCWgFwmjM/+vsGKHOO/Z23EnB +3N+TZO/YzgbAgsiQ+gTZDggeHAy4xD3kRgVlUK6/mIyLbQHJfivjL+BosbRvxibvVfs Y6Pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768806647; x=1769411447; 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=gKM15vI5ObaHuQbAnvaLHXhQIMY9SS6X3bJEvEg+p4E=; b=j3LVBcX35QQqmpjTQ3GTJacGpyvGhDb2yBP+co0QyoYqMGXKMehuUqk/83xRyOi7Vi lsxU6GI8Gfs0f2M6sTFJBFlO8u4opVMaKU9aFZOk1rTMle3EFGYc01f3m7WYb3QwLLWd 11bh4yBSdki/XErJu5EhxCI+kPk0Zpv59bGarSlPqVQ9t2f8istMcwyvhS9IGAlYpShR zl5jjRa1ckOK8k/NXgA2+ecUex9pgxe+khEPouGi2oU/5QHUSp4RJ4Bj5Ekrma703nkJ Vy6Z/XpQgNGw3LfOfLwnixMmYgsZqQ8Z3jaMsYB+1BhWEYwCH/NlN/R8AaVTX/KUfjcv NAag== X-Forwarded-Encrypted: i=1; AJvYcCUQ4Oh2YaNSrwxHlm6vGo8cA2BFKtrwUUIf0lxrpNNXfzLYrQMSWno4Qpmou1Hv9UvH98znzinI49PwAGA=@vger.kernel.org X-Gm-Message-State: AOJu0YwScpIWn8hTUA5+Q1U3TODFFAcnApbqhbQrmoeeVNlZhQy28yyq SeCF0+LpOjYs5tfw8/1Tyrj+ESRJ4ikYcM6BE6XjLysHs5sl+Cyt9Ryg X-Gm-Gg: AY/fxX4m+9cwoKyslRhCDi7YKYWfDkIsW2jm9R7NY+pnIH0Nj9KQe4O0nrASie3Ns3A QU0ugVF6Yfj2lnr7F5NyjDsrHPdMeD9lGjVlwN/HuLg3fCtP7VPwwQpuhmdW71Ix/50ciMQYxJR Emcj6SggQU/L0xOZbNw5eWp7VtaAS56+yvkIi2qbuFUeTSPnDyYW3a0yGJ2CGz6XJAl5P2PI/bK mAvcNfQgkJpHu3tgzoEspreaMVv1LKR7C5DQv7BSlClE1a1bDoW1BewrHG059U6Q7dlq4aAWqfO sgFl/T0hLt7X53cUjunVW8zhBxfIUxJMaZNrV5hnEmkeFYikxmdVeGo9vS/8ZH3I8JbSpaq0oWz uGlKPKUbL2RABK7puNMZ6/FTSpdxQiPbzB2ZFMl4RAMrASH0DKu8AdzvvdwpZqii0rkG2rw0zvL VuofnFV2tayzT65hmyArQ3JaudAkQTsz51qF9yR3xaDhRJonjpE+ErRsKO0cdRiNNjgnFj67ZNX gZwNMk7E6ZjQMIiOXX/2feb7A== X-Received: by 2002:a05:6214:21ef:b0:87c:19af:4b76 with SMTP id 6a1803df08f44-89398144853mr211893076d6.17.1768806647373; Sun, 18 Jan 2026 23:10:47 -0800 (PST) Received: from abc-virtual-machine.localdomain (c-76-150-86-52.hsd1.il.comcast.net. [76.150.86.52]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-8942e6043a6sm79024586d6.18.2026.01.18.23.10.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 18 Jan 2026 23:10:46 -0800 (PST) From: Yuhao Jiang To: Jens Axboe , Pavel Begunkov Cc: io-uring@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Yuhao Jiang Subject: [PATCH v2] io_uring/rsrc: fix RLIMIT_MEMLOCK bypass by removing cross-buffer accounting Date: Mon, 19 Jan 2026 01:10:39 -0600 Message-Id: <20260119071039.2113739-1-danisjiang@gmail.com> X-Mailer: git-send-email 2.34.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" When multiple registered buffers share the same compound page, only the first buffer accounts for the memory via io_buffer_account_pin(). The subsequent buffers skip accounting since headpage_already_acct() returns true. When the first buffer is unregistered, the accounting is decremented, but the compound page remains pinned by the remaining buffers. This creates a state where pinned memory is not properly accounted against RLIMIT_MEMLOCK. On systems with HugeTLB pages pre-allocated, an unprivileged user can exploit this to pin memory beyond RLIMIT_MEMLOCK by cycling buffer registrations. The bypass amount is proportional to the number of available huge pages, potentially allowing gigabytes of memory to be pinned while the kernel accounting shows near-zero. Fix this by removing the cross-buffer accounting optimization entirely. Each buffer now independently accounts for its pinned pages, even if the same compound pages are referenced by other buffers. This prevents accounting underflow when buffers are unregistered in arbitrary order. The trade-off is that memory accounting may be overestimated when multiple buffers share compound pages, but this is safe and prevents the security issue. Reported-by: Yuhao Jiang Suggested-by: Pavel Begunkov Fixes: de2939388be5 ("io_uring: improve registered buffer accounting for hu= ge pages") Cc: stable@vger.kernel.org Signed-off-by: Yuhao Jiang --- Changes in v2: - Remove cross-buffer accounting logic entirely - Link to v1: https://lore.kernel.org/all/20251218025947.36115-1-danisjia= ng@gmail.com/ io_uring/rsrc.c | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c index 41c89f5c616d..f35652f36c57 100644 --- a/io_uring/rsrc.c +++ b/io_uring/rsrc.c @@ -619,47 +619,6 @@ int io_sqe_buffers_unregister(struct io_ring_ctx *ctx) return 0; } =20 -/* - * Not super efficient, but this is just a registration time. And we do ca= che - * the last compound head, so generally we'll only do a full search if we = don't - * match that one. - * - * We check if the given compound head page has already been accounted, to - * avoid double accounting it. This allows us to account the full size of = the - * page, not just the constituent pages of a huge page. - */ -static bool headpage_already_acct(struct io_ring_ctx *ctx, struct page **p= ages, - int nr_pages, struct page *hpage) -{ - int i, j; - - /* check current page array */ - for (i =3D 0; i < nr_pages; i++) { - if (!PageCompound(pages[i])) - continue; - if (compound_head(pages[i]) =3D=3D hpage) - return true; - } - - /* check previously registered pages */ - for (i =3D 0; i < ctx->buf_table.nr; i++) { - struct io_rsrc_node *node =3D ctx->buf_table.nodes[i]; - struct io_mapped_ubuf *imu; - - if (!node) - continue; - imu =3D node->buf; - for (j =3D 0; j < imu->nr_bvecs; j++) { - if (!PageCompound(imu->bvec[j].bv_page)) - continue; - if (compound_head(imu->bvec[j].bv_page) =3D=3D hpage) - return true; - } - } - - return false; -} - static int io_buffer_account_pin(struct io_ring_ctx *ctx, struct page **pa= ges, int nr_pages, struct io_mapped_ubuf *imu, struct page **last_hpage) @@ -677,8 +636,6 @@ static int io_buffer_account_pin(struct io_ring_ctx *ct= x, struct page **pages, if (hpage =3D=3D *last_hpage) continue; *last_hpage =3D hpage; - if (headpage_already_acct(ctx, pages, i, hpage)) - continue; imu->acct_pages +=3D page_size(hpage) >> PAGE_SHIFT; } } --=20 2.34.1