summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/uapi/asm/sigcontext.h19
-rw-r--r--arch/arm64/kernel/signal.c43
2 files changed, 55 insertions, 7 deletions
diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index ee469be1ae1d..1328a2c14371 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -34,6 +34,25 @@ struct sigcontext {
};
/*
+ * Allocation of __reserved[]:
+ * (Note: records do not necessarily occur in the order shown here.)
+ *
+ * size description
+ *
+ * 0x210 fpsimd_context
+ * 0x10 esr_context
+ * 0x10 terminator (null _aarch64_ctx)
+ *
+ * 0xdd0 (reserved for future allocation)
+ *
+ * New records that can exceed this space need to be opt-in for userspace, so
+ * that an expanded signal frame is not generated unexpectedly. The mechanism
+ * for opting in will depend on the extension that generates each new record.
+ * The above table documents the maximum set and sizes of records than can be
+ * generated when userspace does not opt in for any such extension.
+ */
+
+/*
* Header to be used at the beginning of structures extending the user
* context. Such structures must be placed after the rt_sigframe on the stack
* and be 16-byte aligned. The last structure must be a dummy one with the
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index eaef530579f8..fa787e6ac7c2 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -79,6 +79,22 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)
return round_up(max(user->size, sizeof(struct rt_sigframe)), 16);
}
+/*
+ * Allocate space for an optional record of <size> bytes in the user
+ * signal frame. The offset from the signal frame base address to the
+ * allocated block is assigned to *offset.
+ */
+static int sigframe_alloc(struct rt_sigframe_user_layout *user,
+ unsigned long *offset, size_t size)
+{
+ size_t padded_size = round_up(size, 16);
+
+ *offset = user->size;
+ user->size += padded_size;
+
+ return 0;
+}
+
static void __user *apply_user_offset(
struct rt_sigframe_user_layout const *user, unsigned long offset)
{
@@ -287,19 +303,32 @@ badframe:
/* Determine the layout of optional records in the signal frame */
static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
{
- user->fpsimd_offset = user->size;
- user->size += round_up(sizeof(struct fpsimd_context), 16);
+ int err;
+
+ err = sigframe_alloc(user, &user->fpsimd_offset,
+ sizeof(struct fpsimd_context));
+ if (err)
+ return err;
/* fault information, if valid */
if (current->thread.fault_code) {
- user->esr_offset = user->size;
- user->size += round_up(sizeof(struct esr_context), 16);
+ err = sigframe_alloc(user, &user->esr_offset,
+ sizeof(struct esr_context));
+ if (err)
+ return err;
}
- /* set the "end" magic */
- user->end_offset = user->size;
+ /*
+ * Allocate space for the terminator record.
+ * HACK: here we undo the reservation of space for the end record.
+ * This bodge should be replaced with a cleaner approach later on.
+ */
+ user->limit = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved) +
+ sizeof(user->sigframe->uc.uc_mcontext.__reserved);
- return 0;
+ err = sigframe_alloc(user, &user->end_offset,
+ sizeof(struct _aarch64_ctx));
+ return err;
}