arm64: signal: factor out signal frame record allocation
authorDave Martin <Dave.Martin@arm.com>
Thu, 15 Jun 2017 14:03:41 +0000 (15:03 +0100)
committerWill Deacon <will.deacon@arm.com>
Tue, 20 Jun 2017 11:42:59 +0000 (12:42 +0100)
This patch factors out the allocator for signal frame optional
records into a separate function, to ensure consistency and
facilitate later expansion.

No overrun checking is currently done, because the allocation is in
user memory and anyway the kernel never tries to allocate enough
space in the signal frame yet for an overrun to occur.  This
behaviour will be refined in future patches.

The approach taken in this patch to allocation of the terminator
record is not very clean: this will also be replaced in subsequent
patches.

For future extension, a comment is added in sigcontext.h
documenting the current static allocations in __reserved[].  This
will be important for determining under what circumstances
userspace may or may not see an expanded signal frame.

Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm64/include/uapi/asm/sigcontext.h
arch/arm64/kernel/signal.c

index ee469be1ae1d10e26ef02e1bfc677c9961545d49..1328a2c143716e8cb2bcd427dc90f05ce4cdd3f3 100644 (file)
@@ -33,6 +33,25 @@ struct sigcontext {
        __u8 __reserved[4096] __attribute__((__aligned__(16)));
 };
 
+/*
+ * 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
index eaef530579f8731268381378c0ee077e89fabdc3..fa787e6ac7c2423f78cf85509699717170be03db 100644 (file)
@@ -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;
 }