diff mbox

[v5,2/2] arm64: signal: Report signal frame size to userspace via auxv

Message ID 1527261428-6662-3-git-send-email-Dave.Martin@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Martin May 25, 2018, 3:17 p.m. UTC
Stateful CPU architecture extensions may require the signal frame
to grow to a size that exceeds the arch's MINSIGSTKSZ #define.
However, changing this #define is an ABI break.

To allow userspace the option of determining the signal frame size
in a more forwards-compatible way, this patch adds a new auxv entry
tagged with AT_MINSIGSTKSZ, which provides the maximum signal frame
size that the process can observe during its lifetime.

If AT_MINSIGSTKSZ is absent from the aux vector, the caller can
assume that the MINSIGSTKSZ #define is sufficient.  This allows for
a consistent interface with older kernels that do not provide
AT_MINSIGSTKSZ.

The idea is that libc could expose this via sysconf() or some
similar mechanism.

There is deliberately no AT_SIGSTKSZ.  The kernel knows nothing
about userspace's own stack overheads and should not pretend to
know.

For arm64:

The primary motivation for this interface is the Scalable Vector
Extension, which can require at least 4KB or so of extra space
in the signal frame for the largest hardware implementations.

To determine the correct value, a "Christmas tree" mode (via the
add_all argument) is added to setup_sigframe_layout(), to simulate
addition of all possible records to the signal frame at maximum
possible size.

If this procedure goes wrong somehow, resulting in a stupidly large
frame layout and hence failure of sigframe_alloc() to allocate a
record to the frame, then this is indicative of a kernel bug.  In
this case, we WARN() and no attempt is made to populate
AT_MINSIGSTKSZ for userspace.

For arm64 SVE:

The SVE context block in the signal frame needs to be considered
too when computing the maximum possible signal frame size.

Because the size of this block depends on the vector length, this
patch computes the size based not on the thread's current vector
length but instead on the maximum possible vector length: this
determines the maximum size of SVE context block that can be
observed in any signal frame for the lifetime of the process.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Alex Bennée <alex.bennee@linaro.org>

---

Changes since v4:

Requested by Will Deacon:

 * Fix typo in ARCH_INFO comment.

 * Remove special-casing of minsigstksz_setup() failure.  Just
   WARN() and don't populate AT_MINSIGSTKSZ for userspace in this
   case, rather than trying to make an intelligent guess about
   how to populate it when the kernel is obviously broken.
---
 arch/arm64/include/asm/elf.h         | 11 ++++++++
 arch/arm64/include/asm/processor.h   |  5 ++++
 arch/arm64/include/uapi/asm/auxvec.h |  3 ++-
 arch/arm64/kernel/cpufeature.c       |  1 +
 arch/arm64/kernel/signal.c           | 52 +++++++++++++++++++++++++++++++-----
 5 files changed, 64 insertions(+), 8 deletions(-)

Comments

Will Deacon May 29, 2018, 8:42 p.m. UTC | #1
Hi Dave,

Cheers for respinning this. Just one observation below, which I only just
thought about.

On Fri, May 25, 2018 at 04:17:08PM +0100, Dave Martin wrote:
> Stateful CPU architecture extensions may require the signal frame
> to grow to a size that exceeds the arch's MINSIGSTKSZ #define.
> However, changing this #define is an ABI break.
> 
> To allow userspace the option of determining the signal frame size
> in a more forwards-compatible way, this patch adds a new auxv entry
> tagged with AT_MINSIGSTKSZ, which provides the maximum signal frame
> size that the process can observe during its lifetime.
> 
> If AT_MINSIGSTKSZ is absent from the aux vector, the caller can
> assume that the MINSIGSTKSZ #define is sufficient.  This allows for
> a consistent interface with older kernels that do not provide
> AT_MINSIGSTKSZ.
> 
> The idea is that libc could expose this via sysconf() or some
> similar mechanism.
> 
> There is deliberately no AT_SIGSTKSZ.  The kernel knows nothing
> about userspace's own stack overheads and should not pretend to
> know.

[...]

> diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> index fac1c4d..8cf112b 100644
> --- a/arch/arm64/include/asm/elf.h
> +++ b/arch/arm64/include/asm/elf.h
> @@ -121,6 +121,9 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +#include <linux/bug.h>
> +#include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
> +
>  typedef unsigned long elf_greg_t;
>  
>  #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
> @@ -148,6 +151,14 @@ typedef struct user_fpsimd_state elf_fpregset_t;
>  do {									\
>  	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
>  		    (elf_addr_t)current->mm->context.vdso);		\
> +									\
> +	/*								\
> +	 * Should always be nonzero unless there's a kernel bug.	\
> +	 * If we haven't determined a sensible value to give to		\
> +	 * userspace, omit the entry:					\
> +	 */								\
> +	if (likely(signal_minsigstksz))					\
> +		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz);	\
>  } while (0)

I think this is the desired behaviour, but now I'm worried that we're forced
to have AT_VECTOR_SIZE_ARCH defined as 2 and, whilst you're correct that the
ELF loader deals with this gracefuly, the FDPIC loader looks a lot less
robust (in particular, my reading is that it decrements the stack pointer
and then pushes these entries in reverse order by overloading NEW_AUX_ENT).
There's also some checkpoint save/restore code in kernel/sys.c that looks
like it could end up with uninitialised stack for the omitted entry.

Can we spit out an AT_IGNORE entry as an else clause if signal_minsigstksz
is zero?

Will
Dave Martin May 30, 2018, 10:48 a.m. UTC | #2
On Tue, May 29, 2018 at 09:42:31PM +0100, Will Deacon wrote:
> Hi Dave,
> 
> Cheers for respinning this. Just one observation below, which I only just
> thought about.
> 
> On Fri, May 25, 2018 at 04:17:08PM +0100, Dave Martin wrote:
> > Stateful CPU architecture extensions may require the signal frame
> > to grow to a size that exceeds the arch's MINSIGSTKSZ #define.
> > However, changing this #define is an ABI break.
> > 
> > To allow userspace the option of determining the signal frame size
> > in a more forwards-compatible way, this patch adds a new auxv entry
> > tagged with AT_MINSIGSTKSZ, which provides the maximum signal frame
> > size that the process can observe during its lifetime.
> > 
> > If AT_MINSIGSTKSZ is absent from the aux vector, the caller can
> > assume that the MINSIGSTKSZ #define is sufficient.  This allows for
> > a consistent interface with older kernels that do not provide
> > AT_MINSIGSTKSZ.
> > 
> > The idea is that libc could expose this via sysconf() or some
> > similar mechanism.
> > 
> > There is deliberately no AT_SIGSTKSZ.  The kernel knows nothing
> > about userspace's own stack overheads and should not pretend to
> > know.
> 
> [...]
> 
> > diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> > index fac1c4d..8cf112b 100644
> > --- a/arch/arm64/include/asm/elf.h
> > +++ b/arch/arm64/include/asm/elf.h
> > @@ -121,6 +121,9 @@
> >  
> >  #ifndef __ASSEMBLY__
> >  
> > +#include <linux/bug.h>
> > +#include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
> > +
> >  typedef unsigned long elf_greg_t;
> >  
> >  #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
> > @@ -148,6 +151,14 @@ typedef struct user_fpsimd_state elf_fpregset_t;
> >  do {									\
> >  	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
> >  		    (elf_addr_t)current->mm->context.vdso);		\
> > +									\
> > +	/*								\
> > +	 * Should always be nonzero unless there's a kernel bug.	\
> > +	 * If we haven't determined a sensible value to give to		\
> > +	 * userspace, omit the entry:					\
> > +	 */								\
> > +	if (likely(signal_minsigstksz))					\
> > +		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz);	\
> >  } while (0)
> 
> I think this is the desired behaviour, but now I'm worried that we're forced
> to have AT_VECTOR_SIZE_ARCH defined as 2 and, whilst you're correct that the
> ELF loader deals with this gracefuly, the FDPIC loader looks a lot less
> robust (in particular, my reading is that it decrements the stack pointer
> and then pushes these entries in reverse order by overloading NEW_AUX_ENT).

config BINFMT_ELF_FDPIC
	/* ... */
	depends on (ARM || (SUPERH32 & !MMU) || C6X)


The FDPIC loader seems to assume it's 32-bit only and also looks broken
with regard to auxv:

	/* force 16 byte _final_ alignment here for generality */
#define DLINFO_ITEMS 15

/* ... */

		nr = 0;
		csp -= 2 * sizeof(unsigned long);
		NEW_AUX_ENT(AT_EXECFD, ...);
	}

/* ... */

	csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
	NEW_AUX_ENT(AT_HWCAP,   ELF_HWCAP);
#ifdef ELF_HWCAP2
	NEW_AUX_ENT(AT_HWCAP2,  ELF_HWCAP2);
#endif
	/* 14 more NEW_AUX_ENT() */


Looks like commit 2171364d1a92 ("powerpc: Add HWCAP2 aux entry") added
HWCAP2 without ensuring that space is reserved.

I can try to draft a patch to handle the auxv in a more sane way for
FDPIC, but either way I don't see that it should be relevant to arm64.


AT_IGNORE feels like a bit of a fig leaf, but it's harmless enough.  I'm
happy to add it if you prefer.

Cheers
---Dave
Will Deacon May 31, 2018, 5:20 p.m. UTC | #3
On Wed, May 30, 2018 at 11:48:59AM +0100, Dave Martin wrote:
> On Tue, May 29, 2018 at 09:42:31PM +0100, Will Deacon wrote:
> > On Fri, May 25, 2018 at 04:17:08PM +0100, Dave Martin wrote:
> > > diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> > > index fac1c4d..8cf112b 100644
> > > --- a/arch/arm64/include/asm/elf.h
> > > +++ b/arch/arm64/include/asm/elf.h
> > > @@ -121,6 +121,9 @@
> > >  
> > >  #ifndef __ASSEMBLY__
> > >  
> > > +#include <linux/bug.h>
> > > +#include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
> > > +
> > >  typedef unsigned long elf_greg_t;
> > >  
> > >  #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
> > > @@ -148,6 +151,14 @@ typedef struct user_fpsimd_state elf_fpregset_t;
> > >  do {									\
> > >  	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
> > >  		    (elf_addr_t)current->mm->context.vdso);		\
> > > +									\
> > > +	/*								\
> > > +	 * Should always be nonzero unless there's a kernel bug.	\
> > > +	 * If we haven't determined a sensible value to give to		\
> > > +	 * userspace, omit the entry:					\
> > > +	 */								\
> > > +	if (likely(signal_minsigstksz))					\
> > > +		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz);	\
> > >  } while (0)
> > 
> > I think this is the desired behaviour, but now I'm worried that we're forced
> > to have AT_VECTOR_SIZE_ARCH defined as 2 and, whilst you're correct that the
> > ELF loader deals with this gracefuly, the FDPIC loader looks a lot less
> > robust (in particular, my reading is that it decrements the stack pointer
> > and then pushes these entries in reverse order by overloading NEW_AUX_ENT).
> 
> config BINFMT_ELF_FDPIC
> 	/* ... */
> 	depends on (ARM || (SUPERH32 & !MMU) || C6X)

Ok, that's a relief. The checkpoint stuff is still a bit worrying though
(prctl_set_mm_map).

> The FDPIC loader seems to assume it's 32-bit only and also looks broken
> with regard to auxv:
> 
> 	/* force 16 byte _final_ alignment here for generality */
> #define DLINFO_ITEMS 15
> 
> /* ... */
> 
> 		nr = 0;
> 		csp -= 2 * sizeof(unsigned long);
> 		NEW_AUX_ENT(AT_EXECFD, ...);
> 	}
> 
> /* ... */
> 
> 	csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
> 	NEW_AUX_ENT(AT_HWCAP,   ELF_HWCAP);
> #ifdef ELF_HWCAP2
> 	NEW_AUX_ENT(AT_HWCAP2,  ELF_HWCAP2);
> #endif
> 	/* 14 more NEW_AUX_ENT() */
> 
> 
> Looks like commit 2171364d1a92 ("powerpc: Add HWCAP2 aux entry") added
> HWCAP2 without ensuring that space is reserved.
> 
> I can try to draft a patch to handle the auxv in a more sane way for
> FDPIC, but either way I don't see that it should be relevant to arm64.
> 
> 
> AT_IGNORE feels like a bit of a fig leaf, but it's harmless enough.  I'm
> happy to add it if you prefer.

The only userspace code I could find that uses it is something that prints
out auxv, but I'd still better spitting it out so we don't have to worry
about being smaller than AT_VECTOR_SIZE_ARCH.

Thanks,

Will
Dave Martin June 1, 2018, 8:44 a.m. UTC | #4
On Thu, May 31, 2018 at 06:20:49PM +0100, Will Deacon wrote:
> On Wed, May 30, 2018 at 11:48:59AM +0100, Dave Martin wrote:
> > On Tue, May 29, 2018 at 09:42:31PM +0100, Will Deacon wrote:
> > > On Fri, May 25, 2018 at 04:17:08PM +0100, Dave Martin wrote:
> > > > diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
> > > > index fac1c4d..8cf112b 100644
> > > > --- a/arch/arm64/include/asm/elf.h
> > > > +++ b/arch/arm64/include/asm/elf.h
> > > > @@ -121,6 +121,9 @@
> > > >  
> > > >  #ifndef __ASSEMBLY__
> > > >  
> > > > +#include <linux/bug.h>
> > > > +#include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
> > > > +
> > > >  typedef unsigned long elf_greg_t;
> > > >  
> > > >  #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
> > > > @@ -148,6 +151,14 @@ typedef struct user_fpsimd_state elf_fpregset_t;
> > > >  do {									\
> > > >  	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
> > > >  		    (elf_addr_t)current->mm->context.vdso);		\
> > > > +									\
> > > > +	/*								\
> > > > +	 * Should always be nonzero unless there's a kernel bug.	\
> > > > +	 * If we haven't determined a sensible value to give to		\
> > > > +	 * userspace, omit the entry:					\
> > > > +	 */								\
> > > > +	if (likely(signal_minsigstksz))					\
> > > > +		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz);	\
> > > >  } while (0)
> > > 
> > > I think this is the desired behaviour, but now I'm worried that we're forced
> > > to have AT_VECTOR_SIZE_ARCH defined as 2 and, whilst you're correct that the
> > > ELF loader deals with this gracefuly, the FDPIC loader looks a lot less
> > > robust (in particular, my reading is that it decrements the stack pointer
> > > and then pushes these entries in reverse order by overloading NEW_AUX_ENT).
> > 
> > config BINFMT_ELF_FDPIC
> > 	/* ... */
> > 	depends on (ARM || (SUPERH32 & !MMU) || C6X)
> 
> Ok, that's a relief. The checkpoint stuff is still a bit worrying though
> (prctl_set_mm_map).

This looks like a non-issue to me, although stuffing the gap with
AT_IGNORE reduces the scope for unexpected consequences here.

Apart from avoiding buffer overruns in the kernel when stashing the
data, I don't really see why we care what garbage userspace puts in the
auxv that it gives to itself.  It can be invalid in many ways that the
code doesn't check, such as a bad pointer for AT_PLATFORM etc. etc.

> > The FDPIC loader seems to assume it's 32-bit only and also looks broken
> > with regard to auxv:
> > 
> > 	/* force 16 byte _final_ alignment here for generality */
> > #define DLINFO_ITEMS 15
> > 
> > /* ... */
> > 
> > 		nr = 0;
> > 		csp -= 2 * sizeof(unsigned long);
> > 		NEW_AUX_ENT(AT_EXECFD, ...);
> > 	}
> > 
> > /* ... */
> > 
> > 	csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
> > 	NEW_AUX_ENT(AT_HWCAP,   ELF_HWCAP);
> > #ifdef ELF_HWCAP2
> > 	NEW_AUX_ENT(AT_HWCAP2,  ELF_HWCAP2);
> > #endif
> > 	/* 14 more NEW_AUX_ENT() */
> > 
> > 
> > Looks like commit 2171364d1a92 ("powerpc: Add HWCAP2 aux entry") added
> > HWCAP2 without ensuring that space is reserved.
> > 
> > I can try to draft a patch to handle the auxv in a more sane way for
> > FDPIC, but either way I don't see that it should be relevant to arm64.
> > 
> > 
> > AT_IGNORE feels like a bit of a fig leaf, but it's harmless enough.  I'm
> > happy to add it if you prefer.
> 
> The only userspace code I could find that uses it is something that prints
> out auxv, but I'd still better spitting it out so we don't have to worry
> about being smaller than AT_VECTOR_SIZE_ARCH.

OK, I'll add AT_IGNORE and respin.

I wondered whether we can just get rid of AT_VECTOR_SIZE{,_ARCH}, since
they're just asking to be wrong in any case.  But that would be a battle
for another day.

Cheers
---Dave
diff mbox

Patch

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index fac1c4d..8cf112b 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -121,6 +121,9 @@ 
 
 #ifndef __ASSEMBLY__
 
+#include <linux/bug.h>
+#include <asm/processor.h> /* for signal_minsigstksz, used by ARCH_DLINFO */
+
 typedef unsigned long elf_greg_t;
 
 #define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
@@ -148,6 +151,14 @@  typedef struct user_fpsimd_state elf_fpregset_t;
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
 		    (elf_addr_t)current->mm->context.vdso);		\
+									\
+	/*								\
+	 * Should always be nonzero unless there's a kernel bug.	\
+	 * If we haven't determined a sensible value to give to		\
+	 * userspace, omit the entry:					\
+	 */								\
+	if (likely(signal_minsigstksz))					\
+		NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz);	\
 } while (0)
 
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 7675989..65ab83e 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -35,6 +35,8 @@ 
 #ifdef __KERNEL__
 
 #include <linux/build_bug.h>
+#include <linux/cache.h>
+#include <linux/init.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
 
@@ -244,6 +246,9 @@  void cpu_enable_pan(const struct arm64_cpu_capabilities *__unused);
 void cpu_enable_cache_maint_trap(const struct arm64_cpu_capabilities *__unused);
 void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused);
 
+extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */
+extern void __init minsigstksz_setup(void);
+
 /* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */
 #define SVE_SET_VL(arg)	sve_set_current_vl(arg)
 #define SVE_GET_VL()	sve_get_current_vl()
diff --git a/arch/arm64/include/uapi/asm/auxvec.h b/arch/arm64/include/uapi/asm/auxvec.h
index ec0a86d..743c0b8 100644
--- a/arch/arm64/include/uapi/asm/auxvec.h
+++ b/arch/arm64/include/uapi/asm/auxvec.h
@@ -19,7 +19,8 @@ 
 
 /* vDSO location */
 #define AT_SYSINFO_EHDR	33
+#define AT_MINSIGSTKSZ	51	/* stack needed for signal delivery */
 
-#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */
+#define AT_VECTOR_SIZE_ARCH 2 /* entries in ARCH_DLINFO */
 
 #endif
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9d1b06d..0e0b53d 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -1619,6 +1619,7 @@  void __init setup_cpu_features(void)
 		pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n");
 
 	sve_setup();
+	minsigstksz_setup();
 
 	/* Advertise that we have computed the system capabilities */
 	set_sys_caps_initialised();
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 154b7d3..e7da5db 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -17,6 +17,7 @@ 
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/cache.h>
 #include <linux/compat.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -570,8 +571,15 @@  asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
 	return 0;
 }
 
-/* Determine the layout of optional records in the signal frame */
-static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
+/*
+ * Determine the layout of optional records in the signal frame
+ *
+ * add_all: if true, lays out the biggest possible signal frame for
+ *	this task; otherwise, generates a layout for the current state
+ *	of the task.
+ */
+static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
+				 bool add_all)
 {
 	int err;
 
@@ -581,7 +589,7 @@  static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 		return err;
 
 	/* fault information, if valid */
-	if (current->thread.fault_code) {
+	if (add_all || current->thread.fault_code) {
 		err = sigframe_alloc(user, &user->esr_offset,
 				     sizeof(struct esr_context));
 		if (err)
@@ -591,8 +599,14 @@  static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 	if (system_supports_sve()) {
 		unsigned int vq = 0;
 
-		if (test_thread_flag(TIF_SVE))
-			vq = sve_vq_from_vl(current->thread.sve_vl);
+		if (add_all || test_thread_flag(TIF_SVE)) {
+			int vl = sve_max_vl;
+
+			if (!add_all)
+				vl = current->thread.sve_vl;
+
+			vq = sve_vq_from_vl(vl);
+		}
 
 		err = sigframe_alloc(user, &user->sve_offset,
 				     SVE_SIG_CONTEXT_SIZE(vq));
@@ -603,7 +617,6 @@  static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 	return sigframe_alloc_end(user);
 }
 
-
 static int setup_sigframe(struct rt_sigframe_user_layout *user,
 			  struct pt_regs *regs, sigset_t *set)
 {
@@ -701,7 +714,7 @@  static int get_sigframe(struct rt_sigframe_user_layout *user,
 	int err;
 
 	init_user_layout(user);
-	err = setup_sigframe_layout(user);
+	err = setup_sigframe_layout(user, false);
 	if (err)
 		return err;
 
@@ -936,3 +949,28 @@  asmlinkage void do_notify_resume(struct pt_regs *regs,
 		thread_flags = READ_ONCE(current_thread_info()->flags);
 	} while (thread_flags & _TIF_WORK_MASK);
 }
+
+unsigned long __ro_after_init signal_minsigstksz;
+
+/*
+ * Determine the stack space required for guaranteed signal devliery.
+ * This function is used to populate AT_MINSIGSTKSZ at process startup.
+ * cpufeatures setup is assumed to be complete.
+ */
+void __init minsigstksz_setup(void)
+{
+	struct rt_sigframe_user_layout user;
+
+	init_user_layout(&user);
+
+	/*
+	 * If this fails, SIGFRAME_MAXSZ needs to be enlarged.  It won't
+	 * be big enough, but it's our best guess:
+	 */
+	if (WARN_ON(setup_sigframe_layout(&user, true)))
+		return;
+
+	signal_minsigstksz = sigframe_size(&user) +
+		round_up(sizeof(struct frame_record), 16) +
+		16; /* max alignment padding */
+}