All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rick Edgecombe <rick.p.edgecombe@intel.com>
To: Liam.Howlett@oracle.com, akpm@linux-foundation.org,
	debug@rivosinc.com, broonie@kernel.org,
	kirill.shutemov@linux.intel.com, keescook@chromium.org,
	tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
	dave.hansen@linux.intel.com, x86@kernel.org, luto@kernel.org,
	peterz@infradead.org, hpa@zytor.com, linux-mm@kvack.org,
	linux-kernel@vger.kernel.org
Cc: rick.p.edgecombe@intel.com
Subject: [RFC PATCH 5/8] mm: Take placement mappings gap into account
Date: Thu, 15 Feb 2024 15:13:29 -0800	[thread overview]
Message-ID: <20240215231332.1556787-6-rick.p.edgecombe@intel.com> (raw)
In-Reply-To: <20240215231332.1556787-1-rick.p.edgecombe@intel.com>

When memory is being placed, mmap() will take care to respect the guard
gaps of certain types of memory (VM_SHADOWSTACK, VM_GROWSUP and
VM_GROWSDOWN). In order to ensure guard gaps between mappings, mmap()
needs to consider two things:
 1. That the new mapping isn’t placed in an any existing mappings guard
    gaps.
 2. That the new mapping isn’t placed such that any existing mappings
    are not in *its* guard gaps.

The long standing behavior of mmap() is to ensure 1, but not take any care
around 2. So for example, if there is a PAGE_SIZE free area, and a
mmap() with a PAGE_SIZE size, and a type that has a guard gap is being
placed, mmap() may place the shadow stack in the PAGE_SIZE free area. Then
the mapping that is supposed to have a guard gap will not have a gap to
the adjacent VMA.

For MAP_GROWSDOWN/VM_GROWSDOWN and MAP_GROWSUP/VM_GROWSUP this has not
been a problem in practice because applications place these kinds of
mappings very early, when there is not many mappings to find a space
between. But for shadow stacks, they may be placed throughout the lifetime
of the application.

So define a VM_UNMAPPED_START_GAP_SET flag to specify that a start_gap
field has been set, as most vm_unmapped_area_info structs are not zeroed,
so the added field will often contain garbage. Use
VM_UNMAPPED_START_GAP_SET in unmapped_area/_topdown() to find a space that
includes the guard gap for the new mapping. Take care to not interfere
with the alignment.

Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
 include/linux/mm.h |  2 ++
 mm/mmap.c          | 21 ++++++++++++++-------
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9addf16dbf18..160bb6db7a16 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3393,12 +3393,14 @@ extern unsigned long __must_check vm_mmap(struct file *, unsigned long,
 
 struct vm_unmapped_area_info {
 #define VM_UNMAPPED_AREA_TOPDOWN 1
+#define VM_UNMAPPED_START_GAP_SET 2
 	unsigned long flags;
 	unsigned long length;
 	unsigned long low_limit;
 	unsigned long high_limit;
 	unsigned long align_mask;
 	unsigned long align_offset;
+	unsigned long start_gap;
 };
 
 extern unsigned long vm_unmapped_area(struct vm_unmapped_area_info *info);
diff --git a/mm/mmap.c b/mm/mmap.c
index 936d728ba1ca..1b6c333656f9 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1567,14 +1567,17 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
  */
 static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
 {
-	unsigned long length, gap;
+	unsigned long length, gap, start_gap = 0;
 	unsigned long low_limit, high_limit;
 	struct vm_area_struct *tmp;
 
 	MA_STATE(mas, &current->mm->mm_mt, 0, 0);
 
+	if (info->flags & VM_UNMAPPED_START_GAP_SET)
+		start_gap = info->start_gap;
+
 	/* Adjust search length to account for worst case alignment overhead */
-	length = info->length + info->align_mask;
+	length = info->length + info->align_mask + start_gap;
 	if (length < info->length)
 		return -ENOMEM;
 
@@ -1586,7 +1589,7 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
 	if (mas_empty_area(&mas, low_limit, high_limit - 1, length))
 		return -ENOMEM;
 
-	gap = mas.index;
+	gap = mas.index + start_gap;
 	gap += (info->align_offset - gap) & info->align_mask;
 	tmp = mas_next(&mas, ULONG_MAX);
 	if (tmp && (tmp->vm_flags & VM_STARTGAP_FLAGS)) { /* Avoid prev check if possible */
@@ -1619,13 +1622,17 @@ static unsigned long unmapped_area(struct vm_unmapped_area_info *info)
  */
 static unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info)
 {
-	unsigned long length, gap, gap_end;
+	unsigned long length, gap, gap_end, start_gap = 0;
 	unsigned long low_limit, high_limit;
 	struct vm_area_struct *tmp;
 
 	MA_STATE(mas, &current->mm->mm_mt, 0, 0);
+
+	if (info->flags & VM_UNMAPPED_START_GAP_SET)
+		start_gap = info->start_gap;
+
 	/* Adjust search length to account for worst case alignment overhead */
-	length = info->length + info->align_mask;
+	length = info->length + info->align_mask + start_gap;
 	if (length < info->length)
 		return -ENOMEM;
 
@@ -1832,7 +1839,7 @@ unsigned long mm_get_unmapped_area_vmflags(struct mm_struct *mm, struct file *fi
 
 unsigned long
 __get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
-		unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags)
+		    unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags)
 {
 	unsigned long (*get_area)(struct file *, unsigned long,
 				  unsigned long, unsigned long, unsigned long)
@@ -1883,7 +1890,7 @@ __get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
 
 unsigned long
 get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
-		unsigned long pgoff, unsigned long flags)
+		  unsigned long pgoff, unsigned long flags)
 {
 	return __get_unmapped_area(file, addr, len, pgoff, flags, 0);
 }
-- 
2.34.1


  parent reply	other threads:[~2024-02-15 23:14 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-15 23:13 [RFC PATCH 0/8] Cover a guard gap corner case Rick Edgecombe
2024-02-15 23:13 ` [RFC PATCH 1/8] mm: Switch mm->get_unmapped_area() to a flag Rick Edgecombe
2024-02-16  0:30   ` Dave Hansen
2024-02-16  2:15     ` Liam R. Howlett
2024-02-16 12:30   ` Kirill A. Shutemov
2024-02-16 21:42     ` Edgecombe, Rick P
2024-02-21  7:10   ` Mike Rapoport
2024-02-21 16:59     ` Edgecombe, Rick P
2024-02-15 23:13 ` [RFC PATCH 2/8] mm: Introduce arch_get_unmapped_area_vmflags() Rick Edgecombe
2024-02-15 23:13 ` [RFC PATCH 3/8] mm: Use get_unmapped_area_vmflags() Rick Edgecombe
2024-02-16 12:56   ` Kirill A. Shutemov
2024-02-16 22:15     ` Edgecombe, Rick P
2024-02-17 12:35       ` kirill.shutemov
2024-02-15 23:13 ` [RFC PATCH 4/8] thp: Add thp_get_unmapped_area_vmflags() Rick Edgecombe
2024-02-16 12:59   ` Kirill A. Shutemov
2024-02-16 22:21     ` Edgecombe, Rick P
2024-02-17 12:57       ` kirill.shutemov
2024-02-15 23:13 ` Rick Edgecombe [this message]
2024-02-16 13:12   ` [RFC PATCH 5/8] mm: Take placement mappings gap into account Kirill A. Shutemov
2024-02-17  1:11     ` Edgecombe, Rick P
2024-02-20 16:48       ` Edgecombe, Rick P
2024-02-15 23:13 ` [RFC PATCH 6/8] x86/mm: Implement HAVE_ARCH_UNMAPPED_AREA_VMFLAGS Rick Edgecombe
2024-02-15 23:13 ` [RFC PATCH 7/8] x86/mm: Care about shadow stack guard gap during placement Rick Edgecombe
2024-02-15 23:13 ` [RFC PATCH 8/8] selftests/x86: Add placement guard gap test for shstk Rick Edgecombe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240215231332.1556787-6-rick.p.edgecombe@intel.com \
    --to=rick.p.edgecombe@intel.com \
    --cc=Liam.Howlett@oracle.com \
    --cc=akpm@linux-foundation.org \
    --cc=bp@alien8.de \
    --cc=broonie@kernel.org \
    --cc=dave.hansen@linux.intel.com \
    --cc=debug@rivosinc.com \
    --cc=hpa@zytor.com \
    --cc=keescook@chromium.org \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=luto@kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.