From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (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 37167395D9F for ; Thu, 13 Aug 2026 22:53:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786661625; cv=none; b=PBH0bkhgzEk4Q2pf/yoXt4B9CYTbwui/ejV+UhWCs357wHHuByQDLbpgRxoCcAO6IsUwbgNoCGWJvLDLMuLvpR5qEFbLqqmLLWd8dybiKSM4IjoThqWNVXWxOtoGI1138qwTlsSYPUdkH3qerWg4/rOVRuPFF9yruX0fbvu0pPs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786661625; c=relaxed/simple; bh=TEkdEtWWelkeGOFWgyUwKKWPnFifo34zhVuv5pR/4NM=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=N7dsgTfQAq7JZcjT+aCC6wz4cRJHUjV7DWmPOz/0cavWwi9jVkouocvpCo62YrRZwsVub/IXGbNulv9ytl3Wf3B0wq54hJT2/g/HkWUi8nD+/izSNRcAcZqYe2Sy+Mxrj8y3OmfcB0bmQBzmN5NRTWpcrjgsw62+8rBj2BSMWpk= 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=sJ/WxpvL; arc=none smtp.client-ip=209.85.214.174 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="sJ/WxpvL" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2cfbbdfa60bso4705015ad.3 for ; Thu, 13 Aug 2026 15:53:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786661622; x=1787266422; 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:content-type; bh=QcZaXKSZ+vl5BQB5E9TRFwg6GdaSdB6v8ybUxPjYbic=; b=sJ/WxpvLmc7xDihGq+PUE94XPAnTVynvzMI7HxmU6x2lEzm7ChTCVlFYrm9h5y1wuj uiJseoJHx5mdDwb5GqFUP+iK86P7zyatrNYuFO0hLG4bWRZATxESi2YGeCiuvST2Ft6h CcbfpbLMdjx+0I/TCFA0oy8hm9h+wbV3Xqmy1V5a1XxaktszTJAtH+DC/2hw1Ithx9fE eu5xnLOzUfaxoTd6/IdSH+fjVxSPzIcMyLxNcRuiX/smEFE++iqnZ0H/1kqBO9XcAFRE OsZv8J2MxzoDCyLg+42oBdmvE5Z9BF5mHu2oupLSanvH15aAfMjohFtqzbXGkhXmRB3z oJ2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786661622; x=1787266422; 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:content-type; bh=QcZaXKSZ+vl5BQB5E9TRFwg6GdaSdB6v8ybUxPjYbic=; b=kPmzthOEIr1XaJ4XPJHEV5MZkzsnv/S5tDo0+xeZRB+c2wX0iMmFIoPe2/mPer7RQ2 /ocB5lOWe6AcVvOHXTz5B7K8F/gG1id/mNI+HrvTbi1D7DH7QtmiQj8T1nrGnDB/jo+Q mnDkLRCAQcdnph6X1zRq0YdT3Ipp1ZJkpQg4g44Bza//GMNQVZcDCpNp2hKr7R/SnnSR XQl2FJc48ApANGjlFIMSApyBcMKZiZZxDbEP9MRiynvIU+y0DZmYllwiHf+Fy77lc8HA rXteI1WPgINtIIbUiXCCv/EvBVVS1SyP71gR4eaPSMXsZ0qxxhzjmdWznJVKeT+fR2wl GtTw== X-Forwarded-Encrypted: i=1; AHgh+RpKHIAQs63EoEUl1RRPDFd1cphwHNH4hehvvcucWwgcOlP1VBovxnPsbsVG70Zn/EF8pV6X5/gOsWxAxPc=@vger.kernel.org X-Gm-Message-State: AOJu0YxpKSMuooSmn/IEnqmz/NDMf0lZCWqv4CP5lY8TJ0G1CZ6tSjQ4 ToBFd4peMmYC00lLKoGDns1MYh06SyrOE73kPGzn2j9jiGKzHMg++CmK X-Gm-Gg: AR+sD10UoBkOGSUs9T1ZL0a+GqUn8Cre9ZhxzgGAzq7XX7v4dQ9LivvpbJJQhxpVXy1 jU2S2edaF+S7Ws+DCmOoYqnPhe2qR26Bn0wt0X9ogYwPhpFuPDhlgghuM8g7R5aQ5sCmeEFrmtF Xs7jxEDSn14MKoXxoeR1Qcxb7Mwjq+6ZpctyCryRKpUG3ABK+T8PcsY97THfPRbExhCmjwoTi65 0mcYFrci5oMpTO+hRdu15rD2XwkMh3ls8vT1E03n2ZyHYwmA8hyWTxkNBTvTHc7bkIK8TOyYL8Q ASnjkf+H9BPgX1Aw6QY215fpIwsRGKwyz8UwZ3BlRGQ/CZvmy/mCexXO9SGM1mt8mnMc/nmvbn3 O9bEwDjjHR5x+soHlIZFj2YMv5TXB0+4d+as/+lkRSTEzcY+LKbHdbWih4ptnjcsVJ4v1wvInVy Csm6NaWbu2WJofM9krm/pUoe+5Vjpjh6FohBUQm05CdyfoYFxfGByW9dngAGyleNo0BVQWqIwT X-Received: by 2002:a17:903:9cf:b0:2bf:27b2:4b80 with SMTP id d9443c01a7336-2d3b0d1302amr15512025ad.14.1786661622331; Thu, 13 Aug 2026 15:53:42 -0700 (PDT) Received: from ancienth-X870E-Nova-WiFi ([125.186.72.2]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d3ae804b32sm2657265ad.35.2026.08.13.15.53.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 15:53:40 -0700 (PDT) From: Daehyeon Ko <4ncienth@gmail.com> To: Andrew Morton , Mike Rapoport , linux-mm@kvack.org Cc: David Hildenbrand , Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Suren Baghdasaryan , Michal Hocko , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Daehyeon Ko <4ncienth@gmail.com> Subject: [PATCH] mm/secretmem: prevent uncharged mremap expansion after fork Date: Fri, 14 Aug 2026 07:53:28 +0900 Message-ID: <20260813225328.2010303-1-4ncienth@gmail.com> X-Mailer: git-send-email 2.54.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Secretmem mappings are charged against RLIMIT_MEMLOCK and marked VM_LOCKED because their pages are unevictable and removed from the direct map. dup_mmap() clears VM_LOCKED on the child copy, but mremap() uses that flag to decide whether an expansion needs a memlock limit check and accounting. An unprivileged child can therefore expand an inherited secretmem VMA past its limit and populate the added range. Add a VMA open callback that marks secretmem copies without VM_LOCKED as VM_DONTEXPAND. dup_mmap() invokes the callback after clearing VM_LOCKED, while the original charged mapping retains its existing ability to grow within the limit. Add a selftest that verifies expansion of an inherited secretmem VMA is rejected. Fixes: 1507f51255c9 ("mm: introduce memfd_secret system call to create "secret" memory areas") Cc: stable@vger.kernel.org Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> --- mm/secretmem.c | 11 +++++ tools/testing/selftests/mm/memfd_secret.c | 58 ++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/mm/secretmem.c b/mm/secretmem.c index 4877c262cb1f6f..e5878ce91c768c 100644 --- a/mm/secretmem.c +++ b/mm/secretmem.c @@ -108,7 +108,18 @@ static vm_fault_t secretmem_fault(struct vm_fault *vmf) return ret; } +static void secretmem_open(struct vm_area_struct *vma) +{ + /* + * dup_mmap() clears VM_LOCKED before calling ->open(). Prevent an + * inherited, uncharged mapping from being expanded by mremap(). + */ + if (!vma_test(vma, VMA_LOCKED_BIT)) + vma_set_flags(vma, VMA_DONTEXPAND_BIT); +} + static const struct vm_operations_struct secretmem_vm_ops = { + .open = secretmem_open, .fault = secretmem_fault, }; diff --git a/tools/testing/selftests/mm/memfd_secret.c b/tools/testing/selftests/mm/memfd_secret.c index aac4f795c327bd..3d33487eaaccf3 100644 --- a/tools/testing/selftests/mm/memfd_secret.c +++ b/tools/testing/selftests/mm/memfd_secret.c @@ -84,6 +84,61 @@ static void test_mlock_limit(int fd) pass("mlock limit is respected\n"); } +static void test_mremap_after_fork(void) +{ + void *mem, *remapped; + pid_t pid, waited; + int fd, status; + + fd = memfd_secret(0); + if (fd < 0) { + fail("memfd_secret failed: %s\n", strerror(errno)); + return; + } + + if (ftruncate(fd, page_size * 2)) { + fail("ftruncate failed: %s\n", strerror(errno)); + goto close_fd; + } + + mem = mmap(NULL, page_size, prot, mode, fd, 0); + if (mem == MAP_FAILED) { + fail("unable to mmap secret memory: %s\n", strerror(errno)); + goto close_fd; + } + + pid = fork(); + if (pid < 0) { + fail("fork failed: %s\n", strerror(errno)); + goto unmap; + } + + if (pid == 0) { + remapped = mremap(mem, page_size, page_size * 2, + MREMAP_MAYMOVE); + if (remapped != MAP_FAILED) { + munmap(remapped, page_size * 2); + _exit(KSFT_FAIL); + } + _exit(errno == EFAULT ? KSFT_PASS : KSFT_FAIL); + } + + do { + waited = waitpid(pid, &status, 0); + } while (waited < 0 && errno == EINTR); + + if (waited == pid && WIFEXITED(status) && + WEXITSTATUS(status) == KSFT_PASS) + pass("mremap expansion after fork is blocked\n"); + else + fail("mremap expansion after fork was not blocked\n"); + +unmap: + munmap(mem, page_size); +close_fd: + close(fd); +} + static void test_vmsplice(int fd, const char *desc) { ssize_t transferred; @@ -297,7 +352,7 @@ static void prepare(void) strerror(errno)); } -#define NUM_TESTS 6 +#define NUM_TESTS 7 int main(int argc, char *argv[]) { @@ -320,6 +375,7 @@ int main(int argc, char *argv[]) ksft_exit_fail_msg("ftruncate failed: %s\n", strerror(errno)); test_mlock_limit(fd); + test_mremap_after_fork(); test_file_apis(fd); /* * We have to run the first vmsplice test before any secretmem page was -- 2.54.0