* [PATCH v4 1/8] mm: Add arch_get_mmap_base_topdown macro
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
@ 2021-04-30 20:28 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 2/8] hugetlbfs: Use arch_get_mmap_* macros Amanieu d'Antras
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:28 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
This allows architectures to customize the mmap base to use depending on
the direction of allocation.
The base argument is also removed from arch_get_mmap_base[_topdown] in
prepartion for future changes.
arm64 is currently the only user of the arch_get_mmap_* macros and is
adjusted accordingly. Specifically it only needs to limit the upper
bound of VM allocations and therefore only needs to customize
arch_get_mmap_base_topdown but not arch_get_mmap_base.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
arch/arm64/include/asm/processor.h | 7 ++++---
mm/mmap.c | 14 +++++++++-----
2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index efc10e9041a0..f47528aae321 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -88,9 +88,10 @@
#define arch_get_mmap_end(addr) ((addr > DEFAULT_MAP_WINDOW) ? TASK_SIZE :\
DEFAULT_MAP_WINDOW)
-#define arch_get_mmap_base(addr, base) ((addr > DEFAULT_MAP_WINDOW) ? \
- base + TASK_SIZE - DEFAULT_MAP_WINDOW :\
- base)
+#define arch_get_mmap_base_topdown(addr) \
+ ((addr > DEFAULT_MAP_WINDOW) ? \
+ current->mm->mmap_base + TASK_SIZE - DEFAULT_MAP_WINDOW :\
+ current->mm->mmap_base)
#endif /* CONFIG_ARM64_FORCE_52BIT */
extern phys_addr_t arm64_dma_phys_limit;
diff --git a/mm/mmap.c b/mm/mmap.c
index 3f287599a7a3..4937b34085cb 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2139,11 +2139,15 @@ unsigned long vm_unmapped_area(struct vm_unmapped_area_info *info)
}
#ifndef arch_get_mmap_end
-#define arch_get_mmap_end(addr) (TASK_SIZE)
+#define arch_get_mmap_end(addr) (TASK_SIZE)
#endif
#ifndef arch_get_mmap_base
-#define arch_get_mmap_base(addr, base) (base)
+#define arch_get_mmap_base(addr) (current->mm->mmap_base)
+#endif
+
+#ifndef arch_get_mmap_base_topdown
+#define arch_get_mmap_base_topdown(addr) (current->mm->mmap_base)
#endif
/* Get an address range which is currently unmapped.
@@ -2184,7 +2188,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
info.flags = 0;
info.length = len;
- info.low_limit = mm->mmap_base;
+ info.low_limit = arch_get_mmap_base(addr);
info.high_limit = mmap_end;
info.align_mask = 0;
info.align_offset = 0;
@@ -2227,7 +2231,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
info.length = len;
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
- info.high_limit = arch_get_mmap_base(addr, mm->mmap_base);
+ info.high_limit = arch_get_mmap_base_topdown(addr);
info.align_mask = 0;
info.align_offset = 0;
addr = vm_unmapped_area(&info);
@@ -2241,7 +2245,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
if (offset_in_page(addr)) {
VM_BUG_ON(addr != -ENOMEM);
info.flags = 0;
- info.low_limit = TASK_UNMAPPED_BASE;
+ info.low_limit = arch_get_mmap_base(addr);
info.high_limit = mmap_end;
addr = vm_unmapped_area(&info);
}
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/8] hugetlbfs: Use arch_get_mmap_* macros
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
2021-04-30 20:28 ` [PATCH v4 1/8] mm: Add arch_get_mmap_base_topdown macro Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 3/8] mm: Support mmap_compat_base with the generic layout Amanieu d'Antras
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
hugetlb_get_unmapped_area should obey the same arch-specific constraints
as mmap when selecting an address.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
fs/hugetlbfs/inode.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 701c82c36138..526ccb524329 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -191,6 +191,18 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
*/
#ifndef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#ifndef arch_get_mmap_end
+#define arch_get_mmap_end(addr) (TASK_SIZE)
+#endif
+
+#ifndef arch_get_mmap_base
+#define arch_get_mmap_base(addr) (current->mm->mmap_base)
+#endif
+
+#ifndef arch_get_mmap_base_topdown
+#define arch_get_mmap_base_topdown(addr) (current->mm->mmap_base)
+#endif
+
static unsigned long
hugetlb_get_unmapped_area_bottomup(struct file *file, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -200,8 +212,8 @@ hugetlb_get_unmapped_area_bottomup(struct file *file, unsigned long addr,
info.flags = 0;
info.length = len;
- info.low_limit = current->mm->mmap_base;
- info.high_limit = TASK_SIZE;
+ info.low_limit = arch_get_mmap_base(addr);
+ info.high_limit = arch_get_mmap_end(addr);
info.align_mask = PAGE_MASK & ~huge_page_mask(h);
info.align_offset = 0;
return vm_unmapped_area(&info);
@@ -217,7 +229,7 @@ hugetlb_get_unmapped_area_topdown(struct file *file, unsigned long addr,
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
info.length = len;
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
- info.high_limit = current->mm->mmap_base;
+ info.high_limit = arch_get_mmap_base_topdown(addr);
info.align_mask = PAGE_MASK & ~huge_page_mask(h);
info.align_offset = 0;
addr = vm_unmapped_area(&info);
@@ -231,8 +243,8 @@ hugetlb_get_unmapped_area_topdown(struct file *file, unsigned long addr,
if (unlikely(offset_in_page(addr))) {
VM_BUG_ON(addr != -ENOMEM);
info.flags = 0;
- info.low_limit = current->mm->mmap_base;
- info.high_limit = TASK_SIZE;
+ info.low_limit = arch_get_mmap_base(addr);
+ info.high_limit = arch_get_mmap_end(addr);
addr = vm_unmapped_area(&info);
}
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 3/8] mm: Support mmap_compat_base with the generic layout
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
2021-04-30 20:28 ` [PATCH v4 1/8] mm: Add arch_get_mmap_base_topdown macro Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 2/8] hugetlbfs: Use arch_get_mmap_* macros Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 4/8] arm64: Separate in_compat_syscall from is_compat_task Amanieu d'Antras
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
This enables architectures using the generic mmap layout to support
32-bit mmap calls from 64-bit processes and vice-versa.
Architectures using this must define separate 32-bit and 64-bit versions
of STACK_TOP, TASK_UNMAPPED_BASE and STACK_RND_MASK.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
mm/util.c | 46 ++++++++++++++++++++++++++++++++++++++--------
1 file changed, 38 insertions(+), 8 deletions(-)
diff --git a/mm/util.c b/mm/util.c
index 54870226cea6..37bd764174b5 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -353,12 +353,12 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
return randomize_page(mm->brk, SZ_1G);
}
-unsigned long arch_mmap_rnd(void)
+static unsigned long mmap_rnd(bool compat)
{
unsigned long rnd;
#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS
- if (is_compat_task())
+ if (compat)
rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
else
#endif /* CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS */
@@ -367,6 +367,11 @@ unsigned long arch_mmap_rnd(void)
return rnd << PAGE_SHIFT;
}
+unsigned long arch_mmap_rnd(void)
+{
+ return mmap_rnd(is_compat_task());
+}
+
static int mmap_is_legacy(struct rlimit *rlim_stack)
{
if (current->personality & ADDR_COMPAT_LAYOUT)
@@ -383,16 +388,17 @@ static int mmap_is_legacy(struct rlimit *rlim_stack)
* the face of randomisation.
*/
#define MIN_GAP (SZ_128M)
-#define MAX_GAP (STACK_TOP / 6 * 5)
+#define MAX_GAP (stack_top / 6 * 5)
-static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
+static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack,
+ unsigned long stack_top, unsigned long stack_rnd_mask)
{
unsigned long gap = rlim_stack->rlim_cur;
unsigned long pad = stack_guard_gap;
/* Account for stack randomization if necessary */
if (current->flags & PF_RANDOMIZE)
- pad += (STACK_RND_MASK << PAGE_SHIFT);
+ pad += (stack_rnd_mask << PAGE_SHIFT);
/* Values close to RLIM_INFINITY can overflow. */
if (gap + pad > gap)
@@ -403,21 +409,45 @@ static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack)
else if (gap > MAX_GAP)
gap = MAX_GAP;
- return PAGE_ALIGN(STACK_TOP - gap - rnd);
+ return PAGE_ALIGN(stack_top - gap - rnd);
}
void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
{
unsigned long random_factor = 0UL;
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+ unsigned long compat_random_factor = 0UL;
+#endif
- if (current->flags & PF_RANDOMIZE)
+ if (current->flags & PF_RANDOMIZE) {
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+ random_factor = mmap_rnd(false);
+ compat_random_factor = mmap_rnd(true);
+#else
random_factor = arch_mmap_rnd();
+#endif
+ }
if (mmap_is_legacy(rlim_stack)) {
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+ mm->mmap_base = TASK_UNMAPPED_BASE_64 + random_factor;
+ mm->mmap_compat_base =
+ TASK_UNMAPPED_BASE_32 + compat_random_factor;
+#else
mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
+#endif
mm->get_unmapped_area = arch_get_unmapped_area;
} else {
- mm->mmap_base = mmap_base(random_factor, rlim_stack);
+#ifdef CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES
+ mm->mmap_base = mmap_base(random_factor, rlim_stack,
+ STACK_TOP_64, STACK_RND_MASK_64);
+ mm->mmap_compat_base = mmap_base(compat_random_factor,
+ rlim_stack, STACK_TOP_32,
+ STACK_RND_MASK_32);
+#else
+ mm->mmap_base = mmap_base(random_factor, rlim_stack, STACK_TOP,
+ STACK_RND_MASK);
+#endif
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
}
}
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 4/8] arm64: Separate in_compat_syscall from is_compat_task
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
` (2 preceding siblings ...)
2021-04-30 20:37 ` [PATCH v4 3/8] mm: Support mmap_compat_base with the generic layout Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 5/8] arm64: mm: Use HAVE_ARCH_COMPAT_MMAP_BASES Amanieu d'Antras
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
This is preliminary work for allowing 64-bit processes to invoke compat
syscalls.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
arch/arm64/include/asm/compat.h | 24 ++++++++++++++++++++----
arch/arm64/include/asm/ftrace.h | 2 +-
arch/arm64/include/asm/syscall.h | 6 +++---
arch/arm64/kernel/ptrace.c | 2 +-
arch/arm64/kernel/syscall.c | 2 +-
5 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 23a9fb73c04f..a2f5001f7793 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -178,21 +178,37 @@ struct compat_shmid64_ds {
compat_ulong_t __unused5;
};
-static inline int is_compat_task(void)
+static inline bool is_compat_task(void)
{
return test_thread_flag(TIF_32BIT);
}
-static inline int is_compat_thread(struct thread_info *thread)
+static inline bool is_compat_thread(struct thread_info *thread)
{
return test_ti_thread_flag(thread, TIF_32BIT);
}
+static inline bool in_compat_syscall(void)
+{
+ return is_compat_task();
+}
+#define in_compat_syscall in_compat_syscall /* override the generic impl */
+
+static inline bool thread_in_compat_syscall(struct thread_info *thread)
+{
+ return is_compat_thread(thread);
+}
+
#else /* !CONFIG_COMPAT */
-static inline int is_compat_thread(struct thread_info *thread)
+static inline bool is_compat_thread(struct thread_info *thread)
+{
+ return false;
+}
+
+static inline bool thread_in_compat_syscall(struct thread_info *thread)
{
- return 0;
+ return false;
}
#endif /* CONFIG_COMPAT */
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index 91fa4baa1a93..f41aad92c67a 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -88,7 +88,7 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
{
- return is_compat_task();
+ return in_compat_syscall();
}
#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index cfc0672013f6..0dfc01ea386c 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h
@@ -35,7 +35,7 @@ static inline long syscall_get_error(struct task_struct *task,
{
unsigned long error = regs->regs[0];
- if (is_compat_thread(task_thread_info(task)))
+ if (thread_in_compat_syscall(task_thread_info(task)))
error = sign_extend64(error, 31);
return IS_ERR_VALUE(error) ? error : 0;
@@ -54,7 +54,7 @@ static inline void syscall_set_return_value(struct task_struct *task,
if (error)
val = error;
- if (is_compat_thread(task_thread_info(task)))
+ if (thread_in_compat_syscall(task_thread_info(task)))
val = lower_32_bits(val);
regs->regs[0] = val;
@@ -88,7 +88,7 @@ static inline void syscall_set_arguments(struct task_struct *task,
*/
static inline int syscall_get_arch(struct task_struct *task)
{
- if (is_compat_thread(task_thread_info(task)))
+ if (thread_in_compat_syscall(task_thread_info(task)))
return AUDIT_ARCH_ARM;
return AUDIT_ARCH_AARCH64;
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 170f42fd6101..017a82b24f49 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -1721,7 +1721,7 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
* 32-bit children use an extended user_aarch32_ptrace_view to allow
* access to the TLS register.
*/
- if (is_compat_task())
+ if (in_compat_syscall())
return &user_aarch32_view;
else if (is_compat_thread(task_thread_info(task)))
return &user_aarch32_ptrace_view;
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index b9cf12b271d7..e0e9d54de0a2 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -51,7 +51,7 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
ret = do_ni_syscall(regs, scno);
}
- if (is_compat_task())
+ if (in_compat_syscall())
ret = lower_32_bits(ret);
regs->regs[0] = ret;
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 5/8] arm64: mm: Use HAVE_ARCH_COMPAT_MMAP_BASES
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
` (3 preceding siblings ...)
2021-04-30 20:37 ` [PATCH v4 4/8] arm64: Separate in_compat_syscall from is_compat_task Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 6/8] arm64: Add a compat syscall flag to thread_info Amanieu d'Antras
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
This patch switches arm64 to use separate mmap_base for 32-bit and
64-bit mmaps. This is needed to ensure that compat syscalls
invoked by 64-bit tasks perform VM allocations in the low 4G of the
address space.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/elf.h | 8 +++++---
arch/arm64/include/asm/processor.h | 33 ++++++++++++++++++------------
arch/arm64/mm/mmap.c | 33 ++++++++++++++++++++++++++++++
4 files changed, 59 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index dfdc3e0af5e1..d57b7bcbd758 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -133,6 +133,7 @@ config ARM64
select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_BITREVERSE
+ select HAVE_ARCH_COMPAT_MMAP_BASES if COMPAT
select HAVE_ARCH_COMPILER_H
select HAVE_ARCH_HUGE_VMAP
select HAVE_ARCH_JUMP_LABEL
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 8d1c8dcb87fd..e21964898d06 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -187,12 +187,14 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp);
/* 1GB of VA */
+#define STACK_RND_MASK_64 (0x3ffff >> (PAGE_SHIFT - 12))
#ifdef CONFIG_COMPAT
+#define STACK_RND_MASK_32 (0x7ff >> (PAGE_SHIFT - 12))
#define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \
- 0x7ff >> (PAGE_SHIFT - 12) : \
- 0x3ffff >> (PAGE_SHIFT - 12))
+ STACK_RND_MASK_32 : \
+ STACK_RND_MASK_64)
#else
-#define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12))
+#define STACK_RND_MASK STACK_RND_MASK_64
#endif
#ifdef __AARCH64EB__
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index f47528aae321..f8309f8d0ece 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -70,29 +70,36 @@
#ifdef CONFIG_ARM64_FORCE_52BIT
#define STACK_TOP_MAX TASK_SIZE_64
-#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
+#define TASK_UNMAPPED_BASE_64 (PAGE_ALIGN(TASK_SIZE_64 / 4))
#else
#define STACK_TOP_MAX DEFAULT_MAP_WINDOW_64
-#define TASK_UNMAPPED_BASE (PAGE_ALIGN(DEFAULT_MAP_WINDOW / 4))
+#define TASK_UNMAPPED_BASE_64 (PAGE_ALIGN(DEFAULT_MAP_WINDOW_64 / 4))
#endif /* CONFIG_ARM64_FORCE_52BIT */
+#ifdef CONFIG_COMPAT
+#define TASK_UNMAPPED_BASE_32 (PAGE_ALIGN(TASK_SIZE_32 / 4))
+#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \
+ TASK_UNMAPPED_BASE_32 : TASK_UNMAPPED_BASE_64)
+#else
+#define TASK_UNMAPPED_BASE TASK_UNMAPPED_BASE_64
+#endif /* CONFIG_COMPAT */
+
+#define STACK_TOP_64 STACK_TOP_MAX
#ifdef CONFIG_COMPAT
#define AARCH32_VECTORS_BASE 0xffff0000
+#define STACK_TOP_32 AARCH32_VECTORS_BASE
#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
- AARCH32_VECTORS_BASE : STACK_TOP_MAX)
+ STACK_TOP_32 : STACK_TOP_64)
#else
-#define STACK_TOP STACK_TOP_MAX
+#define STACK_TOP STACK_TOP_64
#endif /* CONFIG_COMPAT */
-#ifndef CONFIG_ARM64_FORCE_52BIT
-#define arch_get_mmap_end(addr) ((addr > DEFAULT_MAP_WINDOW) ? TASK_SIZE :\
- DEFAULT_MAP_WINDOW)
-
-#define arch_get_mmap_base_topdown(addr) \
- ((addr > DEFAULT_MAP_WINDOW) ? \
- current->mm->mmap_base + TASK_SIZE - DEFAULT_MAP_WINDOW :\
- current->mm->mmap_base)
-#endif /* CONFIG_ARM64_FORCE_52BIT */
+#define arch_get_mmap_end arch_get_mmap_end
+#define arch_get_mmap_base arch_get_mmap_base
+#define arch_get_mmap_base_topdown arch_get_mmap_base_topdown
+unsigned long arch_get_mmap_end(unsigned long addr);
+unsigned long arch_get_mmap_base(unsigned long addr);
+unsigned long arch_get_mmap_base_topdown(unsigned long addr);
extern phys_addr_t arm64_dma_phys_limit;
#define ARCH_LOW_ADDRESS_LIMIT (arm64_dma_phys_limit - 1)
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index a38f54cd638c..956cab3ade11 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -38,3 +38,36 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{
return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
}
+
+unsigned long arch_get_mmap_end(unsigned long addr)
+{
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall())
+ return TASK_SIZE_32;
+#endif /* CONFIG_COMPAT */
+#ifndef CONFIG_ARM64_FORCE_52BIT
+ if (addr > DEFAULT_MAP_WINDOW_64)
+ return TASK_SIZE_64;
+#endif /* CONFIG_ARM64_FORCE_52BIT */
+ return DEFAULT_MAP_WINDOW_64;
+}
+unsigned long arch_get_mmap_base(unsigned long addr)
+{
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall())
+ return current->mm->mmap_compat_base;
+#endif /* CONFIG_COMPAT */
+ return current->mm->mmap_base;
+}
+unsigned long arch_get_mmap_base_topdown(unsigned long addr)
+{
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall())
+ return current->mm->mmap_compat_base;
+#endif /* CONFIG_COMPAT */
+#ifndef CONFIG_ARM64_FORCE_52BIT
+ if (addr > DEFAULT_MAP_WINDOW_64)
+ return current->mm->mmap_base + TASK_SIZE - DEFAULT_MAP_WINDOW_64;
+#endif /* CONFIG_ARM64_FORCE_52BIT */
+ return current->mm->mmap_base;
+}
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 6/8] arm64: Add a compat syscall flag to thread_info
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
` (4 preceding siblings ...)
2021-04-30 20:37 ` [PATCH v4 5/8] arm64: mm: Use HAVE_ARCH_COMPAT_MMAP_BASES Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 7/8] arm64: Forbid calling compat sigreturn from 64-bit tasks Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 8/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
This flag is used by in_compat_syscall to handle compat syscalls coming
from 64-bit tasks.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
arch/arm64/include/asm/compat.h | 4 ++--
arch/arm64/include/asm/elf.h | 13 ++++++++++++-
arch/arm64/include/asm/thread_info.h | 6 ++++++
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index a2f5001f7793..124f4487dfee 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -190,13 +190,13 @@ static inline bool is_compat_thread(struct thread_info *thread)
static inline bool in_compat_syscall(void)
{
- return is_compat_task();
+ return current_thread_info()->use_compat_syscall;
}
#define in_compat_syscall in_compat_syscall /* override the generic impl */
static inline bool thread_in_compat_syscall(struct thread_info *thread)
{
- return is_compat_thread(thread);
+ return thread->use_compat_syscall;
}
#else /* !CONFIG_COMPAT */
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index e21964898d06..49a9a9db612c 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -158,10 +158,20 @@ typedef struct user_fpsimd_state elf_fpregset_t;
*/
#define ELF_PLAT_INIT(_r, load_addr) (_r)->regs[0] = 0
+#ifdef CONFIG_COMPAT
+#define CLEAR_COMPAT_SYSCALL() \
+({ \
+ current_thread_info()->use_compat_syscall = false; \
+})
+#else
+#define CLEAR_COMPAT_SYSCALL() ((void)0)
+#endif
+
#define SET_PERSONALITY(ex) \
({ \
clear_thread_flag(TIF_32BIT); \
current->personality &= ~READ_IMPLIES_EXEC; \
+ CLEAR_COMPAT_SYSCALL(); \
})
/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */
@@ -228,7 +238,8 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
#define COMPAT_SET_PERSONALITY(ex) \
({ \
set_thread_flag(TIF_32BIT); \
- })
+ current_thread_info()->use_compat_syscall = true; \
+})
#ifdef CONFIG_COMPAT_VDSO
#define COMPAT_ARCH_DLINFO \
do { \
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 6623c99f0984..02310b45900d 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -42,6 +42,12 @@ struct thread_info {
void *scs_base;
void *scs_sp;
#endif
+#ifdef CONFIG_COMPAT
+ /*
+ * compat task or inside a compat syscall from a 64-bit task
+ */
+ bool use_compat_syscall;
+#endif
};
#define thread_saved_pc(tsk) \
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 7/8] arm64: Forbid calling compat sigreturn from 64-bit tasks
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
` (5 preceding siblings ...)
2021-04-30 20:37 ` [PATCH v4 6/8] arm64: Add a compat syscall flag to thread_info Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
2021-04-30 20:37 ` [PATCH v4 8/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
It's impossible for this syscall to do anything sensible in this
context.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
arch/arm64/kernel/signal32.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 2f507f565c48..e2bdd1eaefd8 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -237,6 +237,10 @@ COMPAT_SYSCALL_DEFINE0(sigreturn)
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
+ /* Reject attempts to call this from a 64-bit process. */
+ if (!is_compat_task())
+ goto badframe;
+
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
@@ -268,6 +272,10 @@ COMPAT_SYSCALL_DEFINE0(rt_sigreturn)
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
+ /* Reject attempts to call this from a 64-bit process. */
+ if (!is_compat_task())
+ goto badframe;
+
/*
* Since we stacked the signal on a 64-bit boundary,
* then 'sp' should be word aligned here. If it's
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 8/8] arm64: Allow 64-bit tasks to invoke compat syscalls
2021-04-30 20:28 [PATCH v4 0/8] arm64: Allow 64-bit tasks to invoke compat syscalls Amanieu d'Antras
` (6 preceding siblings ...)
2021-04-30 20:37 ` [PATCH v4 7/8] arm64: Forbid calling compat sigreturn from 64-bit tasks Amanieu d'Antras
@ 2021-04-30 20:37 ` Amanieu d'Antras
7 siblings, 0 replies; 9+ messages in thread
From: Amanieu d'Antras @ 2021-04-30 20:37 UTC (permalink / raw)
Cc: Amanieu d'Antras, Ryan Houdek, Catalin Marinas, Will Deacon,
Mark Rutland, Steven Price, Arnd Bergmann, David Laight,
Mark Brown, linux-arm-kernel, linux-kernel
Setting bit 31 in x8 when performing a syscall will do the following:
- The remainder of x8 is treated as a compat syscall number and is used
to index the compat syscall table.
- in_compat_syscall will return true for the duration of the syscall.
- VM allocations performed by the syscall will be located in the lower
4G of the address space.
- Interrupted syscalls are properly restarted as compat syscalls.
- Seccomp will treats the syscall as having AUDIT_ARCH_ARM instead of
AUDIT_ARCH_AARCH64. This affects the arch value seen by seccomp
filters and reported by SIGSYS.
- PTRACE_GET_SYSCALL_INFO also treats the syscall as having
AUDIT_ARCH_ARM. Recent versions of strace will correctly report the
system call name and parameters when an AArch64 task mixes 32-bit and
64-bit syscalls.
Previously, setting bit 31 of the syscall number would always cause the
sygscall to return ENOSYS. This allows user programs to reliably detect
kernel support for compat syscall by trying a simple syscall such as
getpid.
The AArch32-private compat syscalls (__ARM_NR_compat_*) are not exposed
through this interface. These syscalls do not make sense in the context
of an AArch64 task.
Signed-off-by: Amanieu d'Antras <amanieu@gmail.com>
Co-developed-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
Signed-off-by: Ryan Houdek <Houdek.Ryan@fex-emu.org>
---
arch/arm64/include/uapi/asm/unistd.h | 2 ++
arch/arm64/kernel/signal.c | 5 +++++
arch/arm64/kernel/syscall.c | 21 ++++++++++++++++++++-
3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/uapi/asm/unistd.h b/arch/arm64/include/uapi/asm/unistd.h
index f83a70e07df8..5574bc6ab0a3 100644
--- a/arch/arm64/include/uapi/asm/unistd.h
+++ b/arch/arm64/include/uapi/asm/unistd.h
@@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define __ARM64_COMPAT_SYSCALL_BIT 0x80000000
+
#define __ARCH_WANT_RENAMEAT
#define __ARCH_WANT_NEW_STAT
#define __ARCH_WANT_SET_GET_RLIMIT
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 6237486ff6bb..463c8a82050e 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -795,6 +795,11 @@ static void setup_restart_syscall(struct pt_regs *regs)
{
if (is_compat_task())
compat_setup_restart_syscall(regs);
+#ifdef COMPAT
+ else if (in_compat_syscall())
+ regs->regs[8] = __ARM64_COMPAT_SYSCALL_BIT |
+ __NR_compat_restart_syscall;
+#endif
else
regs->regs[8] = __NR_restart_syscall;
}
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index e0e9d54de0a2..83747cf4b5b7 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -118,6 +118,11 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
* user-issued syscall(-1). However, requesting a skip and not
* setting the return value is unlikely to do anything sensible
* anyway.
+ *
+ * This edge case goes away with CONFIG_COMPAT since a
+ * user-issued syscall(-1) is interpreted as a
+ * compat_syscall(0x7fffffff) which still ends up returning
+ * -ENOSYS in x0.
*/
if (scno == NO_SYSCALL)
regs->regs[0] = -ENOSYS;
@@ -165,7 +170,21 @@ static inline void sve_user_discard(void)
void do_el0_svc(struct pt_regs *regs)
{
sve_user_discard();
- el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
+
+#ifdef CONFIG_COMPAT
+ /*
+ * Setting bit 31 of x8 allows a 64-bit processe to perform compat
+ * syscalls.
+ */
+ if (regs->regs[8] & __ARM64_COMPAT_SYSCALL_BIT) {
+ current_thread_info()->use_compat_syscall = true;
+ el0_svc_common(regs,
+ regs->regs[8] & ~__ARM64_COMPAT_SYSCALL_BIT,
+ __NR_compat_syscalls, compat_sys_call_table);
+ current_thread_info()->use_compat_syscall = false;
+ } else
+#endif
+ el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
}
#ifdef CONFIG_COMPAT
--
2.31.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related [flat|nested] 9+ messages in thread