Download raw body.
stacktrace_save_utrace() should be more robust
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.
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