Download raw body.
stacktrace_save_utrace() should be more robust
> Date: Wed, 21 May 2025 16:02:13 +0200
> From: Alexandr Nedvedicky <sashan@fastmail.net>
>
> Hello,
>
> On Wed, May 21, 2025 at 01:11:40PM +0200, Mark Kettenis wrote:
>
> </snip>
> >
> > That seems like a reasonable assumption. But we should probably avoid
> > the copyin() altogether (and just terminate the trace) if f.f_frame is
> > a kernel address. So something like:
> >
> > if (userland == 1 && INKERNEL(f.f_frame))
> > break;
> >
> > somewhere near the top of the while loop.
> >
>
> yes, it makes perfect sense. thanks for the suggestion.
> updated diff follows. it still works on i386.
But you just moved the f.f_retaddr check, I'm talking about adding an
f.f_frame check.
> regards
> sashan
>
> --------8<---------------8<---------------8<------------------8<--------
> diff --git a/sys/arch/amd64/amd64/db_trace.c b/sys/arch/amd64/amd64/db_trace.c
> index 1e7fcf2208a..b3891efc54d 100644
> --- a/sys/arch/amd64/amd64/db_trace.c
> +++ b/sys/arch/amd64/amd64/db_trace.c
> @@ -292,6 +292,7 @@ stacktrace_save_utrace(struct stacktrace *st)
> {
> struct callframe f, *frame, *lastframe;
> struct pcb *pcb = curpcb;
> + int userland = 0;
>
> st->st_count = 0;
>
> @@ -304,6 +305,9 @@ stacktrace_save_utrace(struct stacktrace *st)
>
> curcpu()->ci_inatomic++;
> while (st->st_count < STACKTRACE_MAX) {
> + if (userland == 1 && INKERNEL(f.f_retaddr))
> + break;
> +
> if (f.f_retaddr != 0 && !INKERNEL(f.f_retaddr))
> st->st_pc[st->st_count++] = f.f_retaddr;
>
> @@ -322,6 +326,7 @@ stacktrace_save_utrace(struct stacktrace *st)
> break;
> if (copyin(frame, &f, sizeof(f)) != 0)
> break;
> + userland = 1;
> }
> curcpu()->ci_inatomic--;
> }
> diff --git a/sys/arch/i386/i386/db_trace.c b/sys/arch/i386/i386/db_trace.c
> index 2e1c9faefca..221909077f4 100644
> --- a/sys/arch/i386/i386/db_trace.c
> +++ b/sys/arch/i386/i386/db_trace.c
> @@ -291,6 +291,7 @@ stacktrace_save_utrace(struct stacktrace *st)
> {
> struct callframe f, *frame, *lastframe;
> struct pcb *pcb = curpcb;
> + int userland = 0;
>
> st->st_count = 0;
>
> @@ -303,6 +304,9 @@ stacktrace_save_utrace(struct stacktrace *st)
>
> curcpu()->ci_inatomic++;
> while (st->st_count < STACKTRACE_MAX) {
> + if (userland == 1 && INKERNEL(f.f_retaddr))
> + break;
> +
> if (f.f_retaddr != 0 && !INKERNEL(f.f_retaddr))
> st->st_pc[st->st_count++] = f.f_retaddr;
>
> @@ -311,6 +315,9 @@ stacktrace_save_utrace(struct stacktrace *st)
>
> if (frame == NULL)
> break;
> + /*
> + * Don't trust f.f_retaddr if it came from userland via copyin
> + */
> if (INKERNEL(f.f_retaddr)) {
> if (frame <= lastframe)
> break;
> @@ -321,6 +328,7 @@ stacktrace_save_utrace(struct stacktrace *st)
> break;
> if (copyin(frame, &f, sizeof(f)) != 0)
> break;
> + userland = 1;
> }
> curcpu()->ci_inatomic--;
> }
>
stacktrace_save_utrace() should be more robust