lkml.org 
[lkml]   [2016]   [Aug]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 51/57] x86/unwind: warn if stack grows up
    Date
    Add a sanity check to ensure the stack only grows down, and print a
    warning if the check fails.

    Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
    ---
    arch/x86/kernel/unwind_frame.c | 26 ++++++++++++++++++++++++--
    1 file changed, 24 insertions(+), 2 deletions(-)

    diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
    index 4dbdf4f..140dac4 100644
    --- a/arch/x86/kernel/unwind_frame.c
    +++ b/arch/x86/kernel/unwind_frame.c
    @@ -32,6 +32,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
    }
    EXPORT_SYMBOL_GPL(unwind_get_return_address);

    +static size_t regs_size(struct pt_regs *regs)
    +{
    + /* x86_32 regs from kernel mode are two words shorter */
    + if (IS_ENABLED(CONFIG_X86_32) && !user_mode(regs))
    + return sizeof(*regs) - (2*sizeof(long));
    +
    + return sizeof(*regs);
    +}
    +
    static bool is_last_task_frame(struct unwind_state *state)
    {
    unsigned long bp = (unsigned long)state->bp;
    @@ -86,6 +95,7 @@ bool unwind_next_frame(struct unwind_state *state)
    struct pt_regs *regs;
    unsigned long *next_bp, *next_frame;
    size_t next_len;
    + enum stack_type prev_type = state->stack_info.type;

    if (unwind_done(state))
    return false;
    @@ -149,6 +159,18 @@ bool unwind_next_frame(struct unwind_state *state)
    goto bad_address;
    }

    + /* make sure it only unwinds up and doesn't overlap the last frame */
    + if (state->stack_info.type == prev_type) {
    + if (state->regs &&
    + (void *)next_frame < (void *)state->regs +
    + regs_size(state->regs))
    + goto bad_address;
    +
    + if (state->bp &&
    + (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE)
    + goto bad_address;
    + }
    +
    /* move to the next frame */
    if (regs) {
    state->regs = regs;
    @@ -165,12 +187,12 @@ bad_address:
    printk_deferred_once(KERN_WARNING
    "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
    state->regs, state->task->comm,
    - state->task->pid, next_bp);
    + state->task->pid, next_frame);
    else
    printk_deferred_once(KERN_WARNING
    "WARNING: kernel stack frame pointer at %p in %s:%d has bad value %p\n",
    state->bp, state->task->comm,
    - state->task->pid, next_bp);
    + state->task->pid, next_frame);
    the_end:
    state->stack_info.type = STACK_TYPE_UNKNOWN;
    return false;
    --
    2.7.4
    \
     
     \ /
      Last update: 2016-09-17 09:57    [W:2.886 / U:0.316 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site