On Tue, Dec 03, 2013 at 02:56:25PM +0530, Anurag Aggarwal wrote:
> Signed-off-by: Anurag Aggarwal <a.anu...@samsung.com>

Move the S-o-b line to the end of your commit message.  I'm getting
tired of saying this.

> 
> While unwinding backtrace, stack overflow is possible. This stack
> overflow can sometimes lead to data abort in system if the area after
> stack is not mapped to physical memory.
> 
> To prevent this problem from happening, execute the instructions that
> can cause a data abort in separate helper functions, where a check for
> feasibility is made before reading data from the stack.

This is looking better now overall, but please take a moment to respond
to the comments I just made on the v2 thread.

Other comments on this patch below.

Cheers
---Dave

> 
> ---
>  arch/arm/kernel/unwind.c |  207 
> ++++++++++++++++++++++++++++++++++------------
>  1 files changed, 153 insertions(+), 54 deletions(-)
> 
> diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
> index 00df012..a140725 100644
> --- a/arch/arm/kernel/unwind.c
> +++ b/arch/arm/kernel/unwind.c
> @@ -49,6 +49,8 @@
>  #include <asm/traps.h>
>  #include <asm/unwind.h>
>  
> +#define TOTAL_REGISTERS 16
> +
>  /* Dummy functions to avoid linker complaints */
>  void __aeabi_unwind_cpp_pr0(void)
>  {
> @@ -66,8 +68,9 @@ void __aeabi_unwind_cpp_pr2(void)
>  EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
>  
>  struct unwind_ctrl_block {
> -     unsigned long vrs[16];          /* virtual register set */
> +     unsigned long vrs[TOTAL_REGISTERS];     /* virtual register set */
>       const unsigned long *insn;      /* pointer to the current instructions 
> word */
> +     unsigned long sp_high;          /* highest value of sp allowed*/
>       int entries;                    /* number of entries left to interpret 
> */
>       int byte;                       /* current byte number in the 
> instructions word */
>  };
> @@ -235,6 +238,148 @@ static unsigned long unwind_get_byte(struct 
> unwind_ctrl_block *ctrl)
>       return ret;
>  }
>  
> +static int unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_block *ctrl,
> +                                             unsigned long insn)
> +{
> +     int available_stack;
> +     unsigned long mask;
> +     unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> +     int load_sp, reg = 4;
> +
> +     /* caculate the space available on stack */
> +     available_stack = ctrl->sp_high - ctrl->vrs[SP];

sp_high and vrs[SP] are just integers, to available_stack is a number of
bytes, not words.

All your checks involving available_sp seem to assume words.

(Previously this was correct because you computed available_stack by
subtracting two unsigned long *).

> +
> +     insn = (insn << 8) | unwind_get_byte(ctrl);
> +     mask = insn & 0x0fff;
> +     if (mask == 0) {
> +             pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n",
> +                     insn);
> +             return -URC_FAILURE;
> +     }

For cleanliness, we should keep decode in unwind_exec_insn() and do
only the execution of the specific insn in these functions.

mask could be a parameter instead of insn, for example.

> +
> +     /*
> +      *  Check whether there is enough space
> +      *  on stack to execute the instruction
> +      *  if not then return failure

(Minor nit: in these multiline comments, please use just one space
after *.  Also, feel free to use longer lines up to 79 chars -- this
could fit on two lines.  My example had short lines because I needed to
demonstrate a multiline comment...)

> +      */
> +     if (available_stack < TOTAL_REGISTERS) {
> +             unsigned long mask_copy = mask;
> +             int required_stack = 0;
> +
> +             while (mask_copy) {
> +                     if (mask_copy & 1)
> +                             required_stack++;
> +                     mask_copy >>= 1;
> +             }
> +
> +             if (available_stack < required_stack)
> +                     return -URC_FAILURE;
> +     }
> +
> +     load_sp = mask & (1 << (13 - 4));
> +     while (mask) {
> +             if (mask & 1)
> +                     ctrl->vrs[reg] = *vsp++;
> +             mask >>= 1;
> +             reg++;
> +     }
> +     if (!load_sp)
> +             ctrl->vrs[SP] = (unsigned long)vsp;
> +
> +     pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
> +             ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
> +
> +     return URC_OK;
> +}
> +
> +static int unwind_exec_pop_r4_to_rN(struct unwind_ctrl_block *ctrl,
> +                                     unsigned long insn)
> +{
> +     int available_stack;
> +     unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> +     int reg;
> +
> +     /* caculate the space available on stack */
> +     available_stack = ctrl->sp_high - ctrl->vrs[SP];
> +
> +     /*
> +      *  Check whether there is enough space
> +      *  on stack to execute the instruction
> +      *  if not then return failure
> +      */
> +     if (available_stack < TOTAL_REGISTERS) {
> +             int required_stack;
> +
> +             required_stack = insn & 7;
> +             required_stack += (insn & 0x80) ? 1 : 0;
> +
> +             if (available_stack < required_stack)
> +                     return -URC_FAILURE;
> +     }
> +
> +     /* pop R4-R[4+bbb] */
> +     for (reg = 4; reg <= 4 + (insn & 7); reg++)
> +             ctrl->vrs[reg] = *vsp++;
> +     if (insn & 0x80)
> +             ctrl->vrs[14] = *vsp++;
> +     ctrl->vrs[SP] = (unsigned long)vsp;
> +
> +     pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
> +             ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
> +
> +     return URC_OK;
> +}
> +
> +static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
> +                                     unsigned long insn)
> +{
> +     int available_stack;
> +     unsigned long mask = unwind_get_byte(ctrl);
> +     unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> +     int reg = 0;
> +
> +     if (mask == 0 || mask & 0xf0) {
> +             pr_warning("unwind: Spare encoding %04lx\n",
> +                     (insn << 8) | mask);
> +             return -URC_FAILURE;
> +     }
> +
> +     /* caculate the space available on stack */
> +     available_stack = ctrl->sp_high - ctrl->vrs[SP];
> +
> +     /*
> +      *  Check whether there is enough space
> +      *  on stack to execute the instruction
> +      *  if not then return failure
> +      */
> +     if (available_stack < TOTAL_REGISTERS) {
> +             unsigned long mask_copy = mask;
> +             int required_stack = 0;
> +
> +             while (mask_copy) {
> +                     if (mask_copy & 1)
> +                             required_stack++;
> +                     mask_copy >>= 1;
> +             }
> +             if (available_stack < required_stack)
> +                     return -URC_FAILURE;
> +     }
> +
> +     /* pop R0-R3 according to mask */
> +     while (mask) {
> +             if (mask & 1)
> +                     ctrl->vrs[reg] = *vsp++;
> +             mask >>= 1;
> +             reg++;
> +     }
> +     ctrl->vrs[SP] = (unsigned long)vsp;
> +
> +     pr_debug("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx\n", __func__,
> +             ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
> +
> +     return URC_OK;
> +}
> +
>  /*
>   * Execute the current unwind instruction.
>   */
> @@ -249,65 +394,19 @@ static int unwind_exec_insn(struct unwind_ctrl_block 
> *ctrl)
>       else if ((insn & 0xc0) == 0x40)
>               ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
>       else if ((insn & 0xf0) == 0x80) {

Many of the { } in this ifelse are now unnecessary.  You should remove
the ones that aren't needed any more.

> -             unsigned long mask;
> -             unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> -             int load_sp, reg = 4;
> -
> -             insn = (insn << 8) | unwind_get_byte(ctrl);
> -             mask = insn & 0x0fff;
> -             if (mask == 0) {
> -                     pr_warning("unwind: 'Refuse to unwind' instruction 
> %04lx\n",
> -                                insn);
> -                     return -URC_FAILURE;
> -             }
> -
> -             /* pop R4-R15 according to mask */
> -             load_sp = mask & (1 << (13 - 4));
> -             while (mask) {
> -                     if (mask & 1)
> -                             ctrl->vrs[reg] = *vsp++;
> -                     mask >>= 1;
> -                     reg++;
> -             }
> -             if (!load_sp)
> -                     ctrl->vrs[SP] = (unsigned long)vsp;
> +             return unwind_exec_pop_subset_r4_to_r13(ctrl, insn);
>       } else if ((insn & 0xf0) == 0x90 &&
>                  (insn & 0x0d) != 0x0d)
>               ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
>       else if ((insn & 0xf0) == 0xa0) {
> -             unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> -             int reg;
> -
> -             /* pop R4-R[4+bbb] */
> -             for (reg = 4; reg <= 4 + (insn & 7); reg++)
> -                     ctrl->vrs[reg] = *vsp++;
> -             if (insn & 0x80)
> -                     ctrl->vrs[14] = *vsp++;
> -             ctrl->vrs[SP] = (unsigned long)vsp;
> +             return unwind_exec_pop_r4_to_rN(ctrl, insn);
>       } else if (insn == 0xb0) {
>               if (ctrl->vrs[PC] == 0)
>                       ctrl->vrs[PC] = ctrl->vrs[LR];
>               /* no further processing */
>               ctrl->entries = 0;
>       } else if (insn == 0xb1) {
> -             unsigned long mask = unwind_get_byte(ctrl);
> -             unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
> -             int reg = 0;
> -
> -             if (mask == 0 || mask & 0xf0) {
> -                     pr_warning("unwind: Spare encoding %04lx\n",
> -                            (insn << 8) | mask);
> -                     return -URC_FAILURE;
> -             }
> -
> -             /* pop R0-R3 according to mask */
> -             while (mask) {
> -                     if (mask & 1)
> -                             ctrl->vrs[reg] = *vsp++;
> -                     mask >>= 1;
> -                     reg++;
> -             }
> -             ctrl->vrs[SP] = (unsigned long)vsp;
> +             return unwind_exec_pop_subset_r0_to_r3(ctrl, insn);
>       } else if (insn == 0xb2) {
>               unsigned long uleb128 = unwind_get_byte(ctrl);
>  
> @@ -329,13 +428,13 @@ static int unwind_exec_insn(struct unwind_ctrl_block 
> *ctrl)
>   */
>  int unwind_frame(struct stackframe *frame)
>  {
> -     unsigned long high, low;
> +     unsigned long low;
>       const struct unwind_idx *idx;
>       struct unwind_ctrl_block ctrl;
>  
> -     /* only go to a higher address on the stack */
> +     /* store the highest address on the stack to avoid crossing it*/
>       low = frame->sp;
> -     high = ALIGN(low, THREAD_SIZE);
> +     ctrl.sp_high = ALIGN(low, THREAD_SIZE);
>  
>       pr_debug("%s(pc = %08lx lr = %08lx sp = %08lx)\n", __func__,
>                frame->pc, frame->lr, frame->sp);
> @@ -386,7 +485,7 @@ int unwind_frame(struct stackframe *frame)
>               int urc = unwind_exec_insn(&ctrl);
>               if (urc < 0)
>                       return urc;
> -             if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= high)
> +             if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= ctrl.sp_high)
>                       return -URC_FAILURE;
>       }
>  
> -- 
> 1.7.0.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-ker...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to