All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ji.Zhang <ji.zhang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
To: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
Cc: wsd_upstream-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org,
	Xie XiuQi <xiexiuqi-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>,
	Ard Biesheuvel
	<ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Marc Zyngier <marc.zyngier-5wv7dgnIgG8@public.gmane.org>,
	Catalin Marinas <catalin.marinas-5wv7dgnIgG8@public.gmane.org>,
	Julien Thierry <julien.thierry-5wv7dgnIgG8@public.gmane.org>,
	Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	shadanji-9Onoh4P/yGk@public.gmane.org,
	James Morse <james.morse-5wv7dgnIgG8@public.gmane.org>,
	Matthias Brugger
	<matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Michael Weiser <michael.weiser-Mmb7MZpHnFY@public.gmane.org>,
	Dave Martin <Dave.Martin-5wv7dgnIgG8@public.gmane.org>,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
Subject: Re: [PATCH] arm64: avoid race condition issue in dump_backtrace
Date: Wed, 11 Apr 2018 14:30:28 +0800	[thread overview]
Message-ID: <1523428228.26617.100.camel@mtksdccf07> (raw)
In-Reply-To: <20180409112559.uh76jpiytznymw6w-agMKViyK24J5pKCnmE3YQBJ8xKzm50AiAL8bYrjMMd8@public.gmane.org>

On Mon, 2018-04-09 at 12:26 +0100, Mark Rutland wrote:
> On Sun, Apr 08, 2018 at 03:58:48PM +0800, Ji.Zhang wrote:
> > Yes, I see where the loop is, I have missed that the loop may cross
> > different stacks.
> > Define a nesting order and check against is a good idea, and it can
> > resolve the issue exactly, but as you mentioned before, we have no idea
> > how to handle with overflow and sdei stack, and the nesting order is
> > strongly related with the scenario of the stack, which means if someday
> > we add another stack, we should consider the relationship of the new
> > stack with other stacks. From the perspective of your experts, is that
> > suitable for doing this in unwind?
> > 
> > Or could we just find some way easier but not so accurate, eg.
> > Proposal 1: 
> > When we do unwind and detect that the stack spans, record the last fp of
> > previous stack and next time if we get into the same stack, compare it
> > with that last fp, the new fp should still smaller than last fp, or
> > there should be potential loop.
> > For example, when we unwind from irq to task, we record the last fp in
> > irq stack such as last_irq_fp, and if it unwind task stack back to irq
> > stack, no matter if it is the same irq stack with previous, just let it
> > go and compare the new irq fp with last_irq_fp, although the process may
> > be wrong since from task stack it could not unwind to irq stack, but the
> > whole process will eventually stop.
> 
> I agree that saving the last fp per-stack could work.
> 
> > Proposal 2:
> > So far we have four types of stack: task, irq, overflow and sdei, could
> > we just assume that the MAX number of stack spanning is just 3
> > times?(task->irq->overflow->sdei or task->irq->sdei->overflow), if yes,
> > we can just check the number of stack spanning when we detect the stack
> > spans.
> 
> I also agree that counting the number of stack transitions will prevent
> an inifinite loop, even if less accurately than proposal 1.
> 
> I don't have a strong preference either way.
Thank you for your comment.
Compared with proposal 1 and 2, I decide to use proposal2 since
proposal1 seems a little complicated and it is not as easy as proposal2
when new stack is added.
The sample is as below:
diff --git a/arch/arm64/include/asm/stacktrace.h
b/arch/arm64/include/asm/stacktrace.h
index 902f9ed..72d1f34 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -92,4 +92,22 @@ static inline bool on_accessible_stack(struct
task_struct *tsk, unsigned long sp
        return false;
 }
 
+#define MAX_STACK_SPAN 3
+DECLARE_PER_CPU(int, num_stack_span);
+
+static inline bool on_same_stack(struct task_struct *tsk,
+                               unsigned long sp1, unsigned long sp2)
+{
+       if (on_task_stack(tsk, sp1) && on_task_stack(tsk, sp2))
+               return true;
+       if (on_irq_stack(sp1) && on_irq_stack(sp2))
+               return true;
+       if (on_overflow_stack(sp1) && on_overflow_stack(sp2))
+               return true;
+       if (on_sdei_stack(sp1) && on_sdei_stack(sp2))
+               return true;
+
+       return false;
+}
+
 #endif /* __ASM_STACKTRACE_H */
diff --git a/arch/arm64/kernel/stacktrace.c
b/arch/arm64/kernel/stacktrace.c
index d5718a0..db905e8 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -27,6 +27,8 @@
 #include <asm/stack_pointer.h>
 #include <asm/stacktrace.h>
 
+DEFINE_PER_CPU(int, num_stack_span);
+
 /*
  * AArch64 PCS assigns the frame pointer to x29.
  *
@@ -56,6 +58,20 @@ int notrace unwind_frame(struct task_struct *tsk,
struct stackframe *frame)
        frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
        frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
 
+       if (!on_same_stack(tsk, fp, frame->fp)) {
+               int num = (int)__this_cpu_read(num_stack_span);
+
+               if (num >= MAX_STACK_SPAN)
+                       return -EINVAL;
+               num++;
+               __this_cpu_write(num_stack_span, num);
+               fp = frame->fp + 0x8;
+       }
+       if (fp <= frame->fp) {
+               pr_notice("fp invalid, stop unwind\n");
+               return -EINVAL;
+       }
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (tsk->ret_stack &&
                        (frame->pc == (unsigned long)return_to_handler))
{
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index eb2d151..e6b5181 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -102,6 +102,8 @@ void dump_backtrace(struct pt_regs *regs, struct
task_struct *tsk)
        struct stackframe frame;
        int skip;
 
+       __this_cpu_write(num_stack_span, 0);
+
        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
        if (!tsk)
@@ -144,6 +146,7 @@ void dump_backtrace(struct pt_regs *regs, struct
task_struct *tsk)
        } while (!unwind_frame(tsk, &frame));
 
        put_task_stack(tsk);
+       __this_cpu_write(num_stack_span, 0);
 }
 
 void show_stack(struct task_struct *tsk, unsigned long *sp)
-- 
1.9.1

If that is ok then I will submit a new patch.

Best Regards,
Ji
> 
> Thanks,
> Mark.

WARNING: multiple messages have this Message-ID (diff)
From: ji.zhang@mediatek.com (Ji.Zhang)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] arm64: avoid race condition issue in dump_backtrace
Date: Wed, 11 Apr 2018 14:30:28 +0800	[thread overview]
Message-ID: <1523428228.26617.100.camel@mtksdccf07> (raw)
In-Reply-To: <20180409112559.uh76jpiytznymw6w@lakrids.cambridge.arm.com>

On Mon, 2018-04-09 at 12:26 +0100, Mark Rutland wrote:
> On Sun, Apr 08, 2018 at 03:58:48PM +0800, Ji.Zhang wrote:
> > Yes, I see where the loop is, I have missed that the loop may cross
> > different stacks.
> > Define a nesting order and check against is a good idea, and it can
> > resolve the issue exactly, but as you mentioned before, we have no idea
> > how to handle with overflow and sdei stack, and the nesting order is
> > strongly related with the scenario of the stack, which means if someday
> > we add another stack, we should consider the relationship of the new
> > stack with other stacks. From the perspective of your experts, is that
> > suitable for doing this in unwind?
> > 
> > Or could we just find some way easier but not so accurate, eg.
> > Proposal 1: 
> > When we do unwind and detect that the stack spans, record the last fp of
> > previous stack and next time if we get into the same stack, compare it
> > with that last fp, the new fp should still smaller than last fp, or
> > there should be potential loop.
> > For example, when we unwind from irq to task, we record the last fp in
> > irq stack such as last_irq_fp, and if it unwind task stack back to irq
> > stack, no matter if it is the same irq stack with previous, just let it
> > go and compare the new irq fp with last_irq_fp, although the process may
> > be wrong since from task stack it could not unwind to irq stack, but the
> > whole process will eventually stop.
> 
> I agree that saving the last fp per-stack could work.
> 
> > Proposal 2:
> > So far we have four types of stack: task, irq, overflow and sdei, could
> > we just assume that the MAX number of stack spanning is just 3
> > times?(task->irq->overflow->sdei or task->irq->sdei->overflow), if yes,
> > we can just check the number of stack spanning when we detect the stack
> > spans.
> 
> I also agree that counting the number of stack transitions will prevent
> an inifinite loop, even if less accurately than proposal 1.
> 
> I don't have a strong preference either way.
Thank you for your comment.
Compared with proposal 1 and 2, I decide to use proposal2 since
proposal1 seems a little complicated and it is not as easy as proposal2
when new stack is added.
The sample is as below:
diff --git a/arch/arm64/include/asm/stacktrace.h
b/arch/arm64/include/asm/stacktrace.h
index 902f9ed..72d1f34 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -92,4 +92,22 @@ static inline bool on_accessible_stack(struct
task_struct *tsk, unsigned long sp
        return false;
 }
 
+#define MAX_STACK_SPAN 3
+DECLARE_PER_CPU(int, num_stack_span);
+
+static inline bool on_same_stack(struct task_struct *tsk,
+                               unsigned long sp1, unsigned long sp2)
+{
+       if (on_task_stack(tsk, sp1) && on_task_stack(tsk, sp2))
+               return true;
+       if (on_irq_stack(sp1) && on_irq_stack(sp2))
+               return true;
+       if (on_overflow_stack(sp1) && on_overflow_stack(sp2))
+               return true;
+       if (on_sdei_stack(sp1) && on_sdei_stack(sp2))
+               return true;
+
+       return false;
+}
+
 #endif /* __ASM_STACKTRACE_H */
diff --git a/arch/arm64/kernel/stacktrace.c
b/arch/arm64/kernel/stacktrace.c
index d5718a0..db905e8 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -27,6 +27,8 @@
 #include <asm/stack_pointer.h>
 #include <asm/stacktrace.h>
 
+DEFINE_PER_CPU(int, num_stack_span);
+
 /*
  * AArch64 PCS assigns the frame pointer to x29.
  *
@@ -56,6 +58,20 @@ int notrace unwind_frame(struct task_struct *tsk,
struct stackframe *frame)
        frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
        frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8));
 
+       if (!on_same_stack(tsk, fp, frame->fp)) {
+               int num = (int)__this_cpu_read(num_stack_span);
+
+               if (num >= MAX_STACK_SPAN)
+                       return -EINVAL;
+               num++;
+               __this_cpu_write(num_stack_span, num);
+               fp = frame->fp + 0x8;
+       }
+       if (fp <= frame->fp) {
+               pr_notice("fp invalid, stop unwind\n");
+               return -EINVAL;
+       }
+
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (tsk->ret_stack &&
                        (frame->pc == (unsigned long)return_to_handler))
{
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index eb2d151..e6b5181 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -102,6 +102,8 @@ void dump_backtrace(struct pt_regs *regs, struct
task_struct *tsk)
        struct stackframe frame;
        int skip;
 
+       __this_cpu_write(num_stack_span, 0);
+
        pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
 
        if (!tsk)
@@ -144,6 +146,7 @@ void dump_backtrace(struct pt_regs *regs, struct
task_struct *tsk)
        } while (!unwind_frame(tsk, &frame));
 
        put_task_stack(tsk);
+       __this_cpu_write(num_stack_span, 0);
 }
 
 void show_stack(struct task_struct *tsk, unsigned long *sp)
-- 
1.9.1

If that is ok then I will submit a new patch.

Best Regards,
Ji
> 
> Thanks,
> Mark.

  parent reply	other threads:[~2018-04-11  6:30 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-22  3:06 [PATCH] arm64: avoid race condition issue in dump_backtrace Ji Zhang
2018-03-22  3:06 ` Ji Zhang
2018-03-22  3:06 ` Ji Zhang
2018-03-22  4:57 ` Baruch Siach
2018-03-22  4:57   ` Baruch Siach
     [not found]   ` <20180322045710.vmmjr2wcankea45o-MwjkAAnuF3khR1HGirfZ1z4kX+cae0hd@public.gmane.org>
2018-03-22  5:33     ` Ji.Zhang
2018-03-22  5:33       ` Ji.Zhang
2018-03-22  5:59 ` Mark Rutland
2018-03-22  5:59   ` Mark Rutland
2018-03-22  9:35   ` Ji.Zhang
2018-03-22  9:35     ` Ji.Zhang
2018-03-26 11:39     ` Mark Rutland
2018-03-26 11:39       ` Mark Rutland
     [not found]       ` <20180326113932.2i6qp3776jtmcqk4-agMKViyK24J5pKCnmE3YQBJ8xKzm50AiAL8bYrjMMd8@public.gmane.org>
2018-03-28  9:33         ` Ji.Zhang
2018-03-28  9:33           ` Ji.Zhang
2018-03-28 10:12           ` Mark Rutland
2018-03-28 10:12             ` Mark Rutland
     [not found]             ` <20180328101240.moo44g5qd3qjuxgn-agMKViyK24J5pKCnmE3YQBJ8xKzm50AiAL8bYrjMMd8@public.gmane.org>
2018-03-30  8:08               ` Ji.Zhang
2018-03-30  8:08                 ` Ji.Zhang
2018-04-04  9:04                 ` Mark Rutland
2018-04-04  9:04                   ` Mark Rutland
     [not found]                   ` <20180404090431.rqwtaqovipxa5gta-agMKViyK24J5pKCnmE3YQBJ8xKzm50AiAL8bYrjMMd8@public.gmane.org>
2018-04-08  7:58                     ` Ji.Zhang
2018-04-08  7:58                       ` Ji.Zhang
2018-04-09 11:26                       ` Mark Rutland
2018-04-09 11:26                         ` Mark Rutland
     [not found]                         ` <20180409112559.uh76jpiytznymw6w-agMKViyK24J5pKCnmE3YQBJ8xKzm50AiAL8bYrjMMd8@public.gmane.org>
2018-04-11  6:30                           ` Ji.Zhang [this message]
2018-04-11  6:30                             ` Ji.Zhang
2018-04-11 10:46                             ` Mark Rutland
2018-04-11 10:46                               ` Mark Rutland
     [not found]                               ` <20180411104656.4afhb4durpntxqxl-agMKViyK24J5pKCnmE3YQBJ8xKzm50AiAL8bYrjMMd8@public.gmane.org>
2018-04-12  6:13                                 ` Ji.Zhang
2018-04-12  6:13                                   ` Ji.Zhang
2018-04-20  5:43                                   ` Ji.Zhang
2018-04-20  5:43                                     ` Ji.Zhang
2018-03-24 11:01 ` kbuild test robot
2018-03-24 11:01   ` kbuild test robot
2018-03-24 11:01   ` kbuild test robot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1523428228.26617.100.camel@mtksdccf07 \
    --to=ji.zhang-nus5lvnupcjwk0htik3j/w@public.gmane.org \
    --cc=Dave.Martin-5wv7dgnIgG8@public.gmane.org \
    --cc=ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
    --cc=catalin.marinas-5wv7dgnIgG8@public.gmane.org \
    --cc=james.morse-5wv7dgnIgG8@public.gmane.org \
    --cc=julien.thierry-5wv7dgnIgG8@public.gmane.org \
    --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
    --cc=marc.zyngier-5wv7dgnIgG8@public.gmane.org \
    --cc=mark.rutland-5wv7dgnIgG8@public.gmane.org \
    --cc=matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=michael.weiser-Mmb7MZpHnFY@public.gmane.org \
    --cc=shadanji-9Onoh4P/yGk@public.gmane.org \
    --cc=will.deacon-5wv7dgnIgG8@public.gmane.org \
    --cc=wsd_upstream-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org \
    --cc=xiexiuqi-hv44wF8Li93QT0dZR+AlfA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.