lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0e7d82b8e8f4ac58d51c18fc059ea2ca235df47c.1747686021.git.lorenzo.stoakes@oracle.com>
Date: Mon, 19 May 2025 21:52:40 +0100
From: Lorenzo Stoakes <lorenzo.stoakes@...cle.com>
To: Andrew Morton <akpm@...ux-foundation.org>
Cc: "Liam R . Howlett" <Liam.Howlett@...cle.com>,
        David Hildenbrand <david@...hat.com>, Vlastimil Babka <vbabka@...e.cz>,
        Jann Horn <jannh@...gle.com>, Arnd Bergmann <arnd@...db.de>,
        Christian Brauner <brauner@...nel.org>, linux-mm@...ck.org,
        linux-arch@...r.kernel.org, linux-kernel@...r.kernel.org,
        SeongJae Park <sj@...nel.org>, Usama Arif <usamaarif642@...il.com>
Subject: [RFC PATCH 3/5] mm/madvise: add PMADV_NO_ERROR_ON_UNMAPPED process_madvise() flag

madvise() has the peculiar behaviour of, should unmapped memory be
encountered in a specified range, carrying on regardless, but returning an
-ENOMEM error at the end of the operation.

This is problematic as one cannot tell if this error arose from there being
unmapped memory or some other cause. It's also rather odd behaviour.

However, we must maintain madvise() behaviour as-is for uAPI reasons.

When it comes to process_madvise(), things are a little different (and a
little more strange). Should ANY entry in the supplied iovec encounter no
errors whatsoever, then all errors encountered are swallowed and we instead
report the number of iovec ranges which succeeded.

However, if no entries succeeded, we simply report the error.

This is problematic in the case of gaps - as the -ENOMEM return value is
treated like an error and causes the entire operation to halt.

A user may very well not desire this behaviour, so we provide the
PMADV_NO_ERROR_ON_UNMAPPED option to cause this to not be treated as an
error at all.

Note that due to the way it is implemented, PMADV_SKIP_ERRORS implies
PMADV_NO_ERROR_ON_UNMAPPED.

Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@...cle.com>
---
 include/uapi/asm-generic/mman-common.h |  3 ++-
 mm/madvise.c                           | 15 ++++++++-------
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h
index a5e4e2f3e82d..58c8a3fadf99 100644
--- a/include/uapi/asm-generic/mman-common.h
+++ b/include/uapi/asm-generic/mman-common.h
@@ -92,6 +92,7 @@
 				 PKEY_DISABLE_WRITE)
 
 /* process_madvise() flags */
-#define PMADV_SKIP_ERRORS (1U << 0) /* Skip VMAs on errors, but carry on. */
+#define PMADV_SKIP_ERRORS (1U << 0) /* Skip VMAs on errors, but carry on. Implies no error on unmapped. */
+#define PMADV_NO_ERROR_ON_UNMAPPED (1U << 1) /* Never report an error on unmapped ranges. */
 
 #endif /* __ASM_GENERIC_MMAN_COMMON_H */
diff --git a/mm/madvise.c b/mm/madvise.c
index 37ef1d6f4190..fd94ef27f909 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1530,7 +1530,7 @@ static bool process_madvise_remote_valid(int behavior)
  */
 static
 int madvise_walk_vmas(struct mm_struct *mm, unsigned long start,
-		      unsigned long end, void *arg,
+		      unsigned long end, bool err_on_unmapped, void *arg,
 		      int (*visit)(struct vm_area_struct *vma,
 				   struct vm_area_struct **prev, unsigned long start,
 				   unsigned long end, void *arg))
@@ -1584,7 +1584,7 @@ int madvise_walk_vmas(struct mm_struct *mm, unsigned long start,
 			vma = find_vma(mm, start);
 	}
 
-	return unmapped_error;
+	return err_on_unmapped ? unmapped_error : 0;
 }
 
 #ifdef CONFIG_ANON_VMA_NAME
@@ -1632,8 +1632,8 @@ int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
 	if (end == start)
 		return 0;
 
-	return madvise_walk_vmas(mm, start, end, anon_name,
-				 madvise_vma_anon_name);
+	return madvise_walk_vmas(mm, start, end, /* err_on_unmapped= */true,
+				 anon_name, madvise_vma_anon_name);
 }
 #endif /* CONFIG_ANON_VMA_NAME */
 
@@ -1752,6 +1752,7 @@ static int madvise_do_behavior(struct mm_struct *mm,
 	struct blk_plug plug;
 	unsigned long end;
 	int error;
+	bool err_on_unmapped = !(madv_behavior->flags & PMADV_NO_ERROR_ON_UNMAPPED);
 
 	if (is_memory_failure(behavior))
 		return madvise_inject_error(madv_behavior, start,
@@ -1763,8 +1764,8 @@ static int madvise_do_behavior(struct mm_struct *mm,
 	if (is_madvise_populate(behavior))
 		error = madvise_populate(mm, start, end, madv_behavior);
 	else
-		error = madvise_walk_vmas(mm, start, end, madv_behavior,
-					  madvise_vma_behavior);
+		error = madvise_walk_vmas(mm, start, end, err_on_unmapped,
+					  madv_behavior, madvise_vma_behavior);
 	blk_finish_plug(&plug);
 	return error;
 }
@@ -1950,7 +1951,7 @@ static ssize_t vector_madvise(struct mm_struct *mm, struct iov_iter *iter,
 
 static bool check_process_madvise_flags(unsigned int flags)
 {
-	unsigned int mask = PMADV_SKIP_ERRORS;
+	unsigned int mask = PMADV_SKIP_ERRORS | PMADV_NO_ERROR_ON_UNMAPPED;
 
 	if (flags & ~mask)
 		return false;
-- 
2.49.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ