[PATCH 18/18] powerpc/fault: Use analyse_instr() to check for store with updates to sp
Daniel Axtens
dja at axtens.net
Thu Dec 19 01:11:33 AEDT 2019
Jordan Niethe <jniethe5 at gmail.com> writes:
> A user-mode access to an address a long way below the stack pointer is
> only valid if the instruction is one that would update the stack pointer
> to the address accessed. This is checked by directly looking at the
> instructions op-code. As a result is does not take into account prefixed
> instructions. Instead of looking at the instruction our self, use
> analyse_instr() determine if this a store instruction that will update
> the stack pointer.
>
> Something to note is that there currently are not any store with update
> prefixed instructions. Actually there is no plan for prefixed
> update-form loads and stores. So this patch is probably not needed but
> it might be preferable to use analyse_instr() rather than open coding
> the test anyway.
Yes please. I was looking through this code recently and was
horrified. This improves things a lot and I think is justification
enough as-is.
Regards,
Daniel
>
> Signed-off-by: Jordan Niethe <jniethe5 at gmail.com>
> ---
> arch/powerpc/mm/fault.c | 39 +++++++++++----------------------------
> 1 file changed, 11 insertions(+), 28 deletions(-)
>
> diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
> index b5047f9b5dec..cb78b3ca1800 100644
> --- a/arch/powerpc/mm/fault.c
> +++ b/arch/powerpc/mm/fault.c
> @@ -41,37 +41,17 @@
> #include <asm/siginfo.h>
> #include <asm/debug.h>
> #include <asm/kup.h>
> +#include <asm/sstep.h>
>
> /*
> * Check whether the instruction inst is a store using
> * an update addressing form which will update r1.
> */
> -static bool store_updates_sp(unsigned int inst)
> +static bool store_updates_sp(struct instruction_op *op)
> {
> - /* check for 1 in the rA field */
> - if (((inst >> 16) & 0x1f) != 1)
> - return false;
> - /* check major opcode */
> - switch (inst >> 26) {
> - case OP_STWU:
> - case OP_STBU:
> - case OP_STHU:
> - case OP_STFSU:
> - case OP_STFDU:
> - return true;
> - case OP_STD: /* std or stdu */
> - return (inst & 3) == 1;
> - case OP_31:
> - /* check minor opcode */
> - switch ((inst >> 1) & 0x3ff) {
> - case OP_31_XOP_STDUX:
> - case OP_31_XOP_STWUX:
> - case OP_31_XOP_STBUX:
> - case OP_31_XOP_STHUX:
> - case OP_31_XOP_STFSUX:
> - case OP_31_XOP_STFDUX:
> + if (GETTYPE(op->type) == STORE) {
> + if ((op->type & UPDATE) && (op->update_reg == 1))
> return true;
> - }
> }
> return false;
> }
> @@ -278,14 +258,17 @@ static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address,
>
> if ((flags & FAULT_FLAG_WRITE) && (flags & FAULT_FLAG_USER) &&
> access_ok(nip, sizeof(*nip))) {
> - unsigned int inst;
> + unsigned int inst, sufx;
> + struct instruction_op op;
> int res;
>
> pagefault_disable();
> - res = __get_user_inatomic(inst, nip);
> + res = __get_user_instr_inatomic(inst, sufx, nip);
> pagefault_enable();
> - if (!res)
> - return !store_updates_sp(inst);
> + if (!res) {
> + analyse_instr(&op, uregs, inst, sufx);
> + return !store_updates_sp(&op);
> + }
> *must_retry = true;
> }
> return true;
> --
> 2.20.1
More information about the Linuxppc-dev
mailing list