From patchwork Fri Nov 25 19:38:50 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 17903 Received: (qmail 129749 invoked by alias); 25 Nov 2016 19:39:54 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 129648 invoked by uid 89); 25 Nov 2016 19:39:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.9 required=5.0 tests=BAYES_00, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=locate, optional, 35215 X-HELO: foss.arm.com From: Dave Martin To: linux-arm-kernel@lists.infradead.org Cc: Florian Weimer , libc-alpha@sourceware.org Subject: [RFC PATCH 02/29] arm64: signal: factor frame layout and population into separate passes Date: Fri, 25 Nov 2016 19:38:50 +0000 Message-Id: <1480102762-23647-3-git-send-email-Dave.Martin@arm.com> In-Reply-To: <1480102762-23647-1-git-send-email-Dave.Martin@arm.com> References: <1480102762-23647-1-git-send-email-Dave.Martin@arm.com> In preparation for expanding the signal frame, this patch refactors the signal frame setup code in setup_sigframe() into two separate passes. The first pass, setup_sigframe_layout(), determines the sizeof the signal frame and its internal layout, including the presence and location of optional records. The resulting knowledge is used to allocate and locate the user stack space required for the signal frame and to determine which optional records to include. The second pass, setup_sigframe(), is called once the stack frame is allocated in order to populate it with the necessary context information. This change has no effect on the signal ABI, but will make it easier to expand the signal frame in future patches. Signed-off-by: Dave Martin --- arch/arm64/kernel/signal.c | 112 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 24 deletions(-) diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 4f8dbe0..fc08371 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -49,8 +50,39 @@ struct rt_sigframe { struct rt_sigframe_user_layout { struct rt_sigframe __user *sigframe; + + unsigned long size; /* size of allocated sigframe data */ + unsigned long limit; /* largest allowed size */ + + unsigned long fpsimd_offset; + unsigned long esr_offset; + unsigned long end_offset; }; +static void init_user_layout(struct rt_sigframe_user_layout *user) +{ + memset(user, 0, sizeof(*user)); + user->size = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved); + + user->limit = user->size + + sizeof(user->sigframe->uc.uc_mcontext.__reserved) - + round_up(sizeof(struct _aarch64_ctx), 16); + /* ^ reserve space for terminator */ +} + +static size_t sigframe_size(struct rt_sigframe_user_layout const *user) +{ + return round_up(max(user->size, sizeof(struct rt_sigframe)), 16); +} + +static void __user *apply_user_offset( + struct rt_sigframe_user_layout const *user, unsigned long offset) +{ + char __user *base = (char __user *)user->sigframe; + + return base + offset; +} + static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) { struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state; @@ -106,26 +138,35 @@ static int parse_user_sigframe(struct user_ctxs *user, struct rt_sigframe __user *sf) { struct sigcontext __user *sc = &sf->uc.uc_mcontext; - struct _aarch64_ctx __user *head = - (struct _aarch64_ctx __user *)&sc->__reserved; + struct _aarch64_ctx __user *head; + char __user *base = (char __user *)&sc->__reserved; size_t offset = 0; + size_t limit = sizeof(sc->__reserved); user->fpsimd = NULL; + if (!IS_ALIGNED((unsigned long)base, 16)) + goto invalid; + while (1) { - int err; + int err = 0; u32 magic, size; - head = (struct _aarch64_ctx __user *)&sc->__reserved[offset]; - if (!IS_ALIGNED((unsigned long)head, 16)) + if (limit - offset < sizeof(*head)) goto invalid; - err = 0; + if (!IS_ALIGNED(offset, 16)) + goto invalid; + + head = (struct _aarch64_ctx __user *)(base + offset); __get_user_error(magic, &head->magic, err); __get_user_error(size, &head->size, err); if (err) return err; + if (limit - offset < size) + goto invalid; + switch (magic) { case 0: if (size) @@ -137,9 +178,7 @@ static int parse_user_sigframe(struct user_ctxs *user, if (user->fpsimd) goto invalid; - if (offset > sizeof(sc->__reserved) - - sizeof(*user->fpsimd) || - size < sizeof(*user->fpsimd)) + if (size < sizeof(*user->fpsimd)) goto invalid; user->fpsimd = (struct fpsimd_context __user *)head; @@ -156,7 +195,7 @@ static int parse_user_sigframe(struct user_ctxs *user, if (size < sizeof(*head)) goto invalid; - if (size > sizeof(sc->__reserved) - (sizeof(*head) + offset)) + if (limit - offset < size) goto invalid; offset += size; @@ -241,13 +280,30 @@ 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) +{ + user->fpsimd_offset = user->size; + user->size += round_up(sizeof(struct fpsimd_context), 16); + + /* fault information, if valid */ + if (current->thread.fault_code) { + user->esr_offset = user->size; + user->size += round_up(sizeof(struct esr_context), 16); + } + + /* set the "end" magic */ + user->end_offset = user->size; + + return 0; +} + + static int setup_sigframe(struct rt_sigframe_user_layout *user, struct pt_regs *regs, sigset_t *set) { int i, err = 0; struct rt_sigframe __user *sf = user->sigframe; - void *aux = sf->uc.uc_mcontext.__reserved; - struct _aarch64_ctx *end; /* set up the stack frame for unwinding */ __put_user_error(regs->regs[29], &sf->fp, err); @@ -265,26 +321,29 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user, err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); if (err == 0) { - struct fpsimd_context *fpsimd_ctx = - container_of(aux, struct fpsimd_context, head); + struct fpsimd_context __user *fpsimd_ctx = + apply_user_offset(user, user->fpsimd_offset); err |= preserve_fpsimd_context(fpsimd_ctx); - aux += sizeof(*fpsimd_ctx); } /* fault information, if valid */ - if (current->thread.fault_code) { - struct esr_context *esr_ctx = - container_of(aux, struct esr_context, head); + if (err == 0 && user->esr_offset) { + struct esr_context __user *esr_ctx = + apply_user_offset(user, user->esr_offset); + __put_user_error(ESR_MAGIC, &esr_ctx->head.magic, err); __put_user_error(sizeof(*esr_ctx), &esr_ctx->head.size, err); __put_user_error(current->thread.fault_code, &esr_ctx->esr, err); - aux += sizeof(*esr_ctx); } /* set the "end" magic */ - end = aux; - __put_user_error(0, &end->magic, err); - __put_user_error(0, &end->size, err); + if (err == 0) { + struct _aarch64_ctx __user *end = + apply_user_offset(user, user->end_offset); + + __put_user_error(0, &end->magic, err); + __put_user_error(0, &end->size, err); + } return err; } @@ -293,10 +352,15 @@ static int get_sigframe(struct rt_sigframe_user_layout *user, struct ksignal *ksig, struct pt_regs *regs) { unsigned long sp, sp_top; + int err; - sp = sp_top = sigsp(regs->sp, ksig); + init_user_layout(user); + err = setup_sigframe_layout(user); + if (err) + return err; - sp = (sp - sizeof(struct rt_sigframe)) & ~15; + sp = sp_top = sigsp(regs->sp, ksig); + sp = (sp & ~15) - sigframe_size(user); user->sigframe = (struct rt_sigframe __user *)sp; /*