Skip to content

Commit b08418b

Browse files
jpoimboeIngo Molnar
authored andcommitted
x86/unwind: Prevent false warnings for non-current tasks
There's some daring kernel code out there which dumps the stack of another task without first making sure the task is inactive. If the task happens to be running while the unwinder is reading the stack, unusual unwinder warnings can result. There's no race-free way for the unwinder to know whether such a warning is legitimate, so just disable unwinder warnings for all non-current tasks. Reviewed-by: Miroslav Benes <[email protected]> Signed-off-by: Josh Poimboeuf <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Dave Jones <[email protected]> Cc: Jann Horn <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vince Weaver <[email protected]> Link: https://lore.kernel.org/r/ec424a2aea1d461eb30cab48a28c6433de2ab784.1587808742.git.jpoimboe@redhat.com
1 parent 153eb22 commit b08418b

File tree

3 files changed

+28
-18
lines changed

3 files changed

+28
-18
lines changed

arch/x86/kernel/dumpstack_64.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
183183
*/
184184
if (visit_mask) {
185185
if (*visit_mask & (1UL << info->type)) {
186-
printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
186+
if (task == current)
187+
printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
187188
goto unknown;
188189
}
189190
*visit_mask |= 1UL << info->type;

arch/x86/kernel/unwind_frame.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,9 @@ bool unwind_next_frame(struct unwind_state *state)
344344
if (IS_ENABLED(CONFIG_X86_32))
345345
goto the_end;
346346

347+
if (state->task != current)
348+
goto the_end;
349+
347350
if (state->regs) {
348351
printk_deferred_once(KERN_WARNING
349352
"WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",

arch/x86/kernel/unwind_orc.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@
88
#include <asm/orc_lookup.h>
99

1010
#define orc_warn(fmt, ...) \
11-
printk_deferred_once(KERN_WARNING pr_fmt("WARNING: " fmt), ##__VA_ARGS__)
11+
printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__)
12+
13+
#define orc_warn_current(args...) \
14+
({ \
15+
if (state->task == current) \
16+
orc_warn(args); \
17+
})
1218

1319
extern int __start_orc_unwind_ip[];
1420
extern int __stop_orc_unwind_ip[];
@@ -446,42 +452,42 @@ bool unwind_next_frame(struct unwind_state *state)
446452

447453
case ORC_REG_R10:
448454
if (!state->regs || !state->full_regs) {
449-
orc_warn("missing regs for base reg R10 at ip %pB\n",
450-
(void *)state->ip);
455+
orc_warn_current("missing R10 value at %pB\n",
456+
(void *)state->ip);
451457
goto err;
452458
}
453459
sp = state->regs->r10;
454460
break;
455461

456462
case ORC_REG_R13:
457463
if (!state->regs || !state->full_regs) {
458-
orc_warn("missing regs for base reg R13 at ip %pB\n",
459-
(void *)state->ip);
464+
orc_warn_current("missing R13 value at %pB\n",
465+
(void *)state->ip);
460466
goto err;
461467
}
462468
sp = state->regs->r13;
463469
break;
464470

465471
case ORC_REG_DI:
466472
if (!state->regs || !state->full_regs) {
467-
orc_warn("missing regs for base reg DI at ip %pB\n",
468-
(void *)state->ip);
473+
orc_warn_current("missing RDI value at %pB\n",
474+
(void *)state->ip);
469475
goto err;
470476
}
471477
sp = state->regs->di;
472478
break;
473479

474480
case ORC_REG_DX:
475481
if (!state->regs || !state->full_regs) {
476-
orc_warn("missing regs for base reg DX at ip %pB\n",
477-
(void *)state->ip);
482+
orc_warn_current("missing DX value at %pB\n",
483+
(void *)state->ip);
478484
goto err;
479485
}
480486
sp = state->regs->dx;
481487
break;
482488

483489
default:
484-
orc_warn("unknown SP base reg %d for ip %pB\n",
490+
orc_warn("unknown SP base reg %d at %pB\n",
485491
orc->sp_reg, (void *)state->ip);
486492
goto err;
487493
}
@@ -509,8 +515,8 @@ bool unwind_next_frame(struct unwind_state *state)
509515

510516
case ORC_TYPE_REGS:
511517
if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) {
512-
orc_warn("can't dereference registers at %p for ip %pB\n",
513-
(void *)sp, (void *)orig_ip);
518+
orc_warn_current("can't access registers at %pB\n",
519+
(void *)orig_ip);
514520
goto err;
515521
}
516522

@@ -521,8 +527,8 @@ bool unwind_next_frame(struct unwind_state *state)
521527

522528
case ORC_TYPE_REGS_IRET:
523529
if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) {
524-
orc_warn("can't dereference iret registers at %p for ip %pB\n",
525-
(void *)sp, (void *)orig_ip);
530+
orc_warn_current("can't access iret registers at %pB\n",
531+
(void *)orig_ip);
526532
goto err;
527533
}
528534

@@ -532,7 +538,7 @@ bool unwind_next_frame(struct unwind_state *state)
532538
break;
533539

534540
default:
535-
orc_warn("unknown .orc_unwind entry type %d for ip %pB\n",
541+
orc_warn("unknown .orc_unwind entry type %d at %pB\n",
536542
orc->type, (void *)orig_ip);
537543
break;
538544
}
@@ -564,8 +570,8 @@ bool unwind_next_frame(struct unwind_state *state)
564570
if (state->stack_info.type == prev_type &&
565571
on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) &&
566572
state->sp <= prev_sp) {
567-
orc_warn("stack going in the wrong direction? ip=%pB\n",
568-
(void *)orig_ip);
573+
orc_warn_current("stack going in the wrong direction? at %pB\n",
574+
(void *)orig_ip);
569575
goto err;
570576
}
571577

0 commit comments

Comments
 (0)