Skip to content

Commit 25b8400

Browse files
committed
arm64: Support Clang UBSAN trap codes for better reporting
When building with CONFIG_UBSAN_TRAP=y on arm64, Clang encodes the UBSAN check (handler) type in the esr. Extract this and actually report these traps as coming from the specific UBSAN check that tripped. Before: Internal error: BRK handler: 00000000f20003e8 [#1] PREEMPT SMP After: Internal error: UBSAN: shift out of bounds: 00000000f2005514 [#1] PREEMPT SMP Acked-by: Mark Rutland <[email protected]> Reviewed-by: Ard Biesheuvel <[email protected]> Acked-by: Mukesh Ojha <[email protected]> Reviewed-by: Fangrui Song <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Will Deacon <[email protected]> Cc: John Stultz <[email protected]> Cc: Yongqin Liu <[email protected]> Cc: Sami Tolvanen <[email protected]> Cc: Yury Norov <[email protected]> Cc: Andrey Konovalov <[email protected]> Cc: Marco Elver <[email protected]> Cc: [email protected] Cc: [email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent 48df133 commit 25b8400

File tree

6 files changed

+133
-2
lines changed

6 files changed

+133
-2
lines changed

arch/arm64/include/asm/brk-imm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* 0x401: for compile time BRK instruction
1818
* 0x800: kernel-mode BUG() and WARN() traps
1919
* 0x9xx: tag-based KASAN trap (allowed values 0x900 - 0x9ff)
20+
* 0x55xx: Undefined Behavior Sanitizer traps ('U' << 8)
2021
* 0x8xxx: Control-Flow Integrity traps
2122
*/
2223
#define KPROBES_BRK_IMM 0x004
@@ -28,6 +29,8 @@
2829
#define BUG_BRK_IMM 0x800
2930
#define KASAN_BRK_IMM 0x900
3031
#define KASAN_BRK_MASK 0x0ff
32+
#define UBSAN_BRK_IMM 0x5500
33+
#define UBSAN_BRK_MASK 0x00ff
3134

3235
#define CFI_BRK_IMM_TARGET GENMASK(4, 0)
3336
#define CFI_BRK_IMM_TYPE GENMASK(9, 5)

arch/arm64/kernel/traps.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/syscalls.h>
2727
#include <linux/mm_types.h>
2828
#include <linux/kasan.h>
29+
#include <linux/ubsan.h>
2930
#include <linux/cfi.h>
3031

3132
#include <asm/atomic.h>
@@ -1074,6 +1075,19 @@ static struct break_hook kasan_break_hook = {
10741075
};
10751076
#endif
10761077

1078+
#ifdef CONFIG_UBSAN_TRAP
1079+
static int ubsan_handler(struct pt_regs *regs, unsigned long esr)
1080+
{
1081+
die(report_ubsan_failure(regs, esr & UBSAN_BRK_MASK), regs, esr);
1082+
return DBG_HOOK_HANDLED;
1083+
}
1084+
1085+
static struct break_hook ubsan_break_hook = {
1086+
.fn = ubsan_handler,
1087+
.imm = UBSAN_BRK_IMM,
1088+
.mask = UBSAN_BRK_MASK,
1089+
};
1090+
#endif
10771091

10781092
#define esr_comment(esr) ((esr) & ESR_ELx_BRK64_ISS_COMMENT_MASK)
10791093

@@ -1091,6 +1105,10 @@ int __init early_brk64(unsigned long addr, unsigned long esr,
10911105
#ifdef CONFIG_KASAN_SW_TAGS
10921106
if ((esr_comment(esr) & ~KASAN_BRK_MASK) == KASAN_BRK_IMM)
10931107
return kasan_handler(regs, esr) != DBG_HOOK_HANDLED;
1108+
#endif
1109+
#ifdef CONFIG_UBSAN_TRAP
1110+
if ((esr_comment(esr) & ~UBSAN_BRK_MASK) == UBSAN_BRK_IMM)
1111+
return ubsan_handler(regs, esr) != DBG_HOOK_HANDLED;
10941112
#endif
10951113
return bug_handler(regs, esr) != DBG_HOOK_HANDLED;
10961114
}
@@ -1104,6 +1122,9 @@ void __init trap_init(void)
11041122
register_kernel_break_hook(&fault_break_hook);
11051123
#ifdef CONFIG_KASAN_SW_TAGS
11061124
register_kernel_break_hook(&kasan_break_hook);
1125+
#endif
1126+
#ifdef CONFIG_UBSAN_TRAP
1127+
register_kernel_break_hook(&ubsan_break_hook);
11071128
#endif
11081129
debug_traps_init();
11091130
}

include/linux/ubsan.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _LINUX_UBSAN_H
3+
#define _LINUX_UBSAN_H
4+
5+
#ifdef CONFIG_UBSAN_TRAP
6+
const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type);
7+
#endif
8+
9+
#endif

lib/Makefile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,7 @@ quiet_cmd_build_OID_registry = GEN $@
340340
clean-files += oid_registry_data.c
341341

342342
obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
343-
ifneq ($(CONFIG_UBSAN_TRAP),y)
344343
obj-$(CONFIG_UBSAN) += ubsan.o
345-
endif
346344

347345
UBSAN_SANITIZE_ubsan.o := n
348346
KASAN_SANITIZE_ubsan.o := n

lib/ubsan.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,76 @@
1414
#include <linux/types.h>
1515
#include <linux/sched.h>
1616
#include <linux/uaccess.h>
17+
#include <linux/ubsan.h>
1718
#include <kunit/test-bug.h>
1819

1920
#include "ubsan.h"
2021

22+
#ifdef CONFIG_UBSAN_TRAP
23+
/*
24+
* Only include matches for UBSAN checks that are actually compiled in.
25+
* The mappings of struct SanitizerKind (the -fsanitize=xxx args) to
26+
* enum SanitizerHandler (the traps) in Clang is in clang/lib/CodeGen/.
27+
*/
28+
const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type)
29+
{
30+
switch (check_type) {
31+
#ifdef CONFIG_UBSAN_BOUNDS
32+
/*
33+
* SanitizerKind::ArrayBounds and SanitizerKind::LocalBounds
34+
* emit SanitizerHandler::OutOfBounds.
35+
*/
36+
case ubsan_out_of_bounds:
37+
return "UBSAN: array index out of bounds";
38+
#endif
39+
#ifdef CONFIG_UBSAN_SHIFT
40+
/*
41+
* SanitizerKind::ShiftBase and SanitizerKind::ShiftExponent
42+
* emit SanitizerHandler::ShiftOutOfBounds.
43+
*/
44+
case ubsan_shift_out_of_bounds:
45+
return "UBSAN: shift out of bounds";
46+
#endif
47+
#ifdef CONFIG_UBSAN_DIV_ZERO
48+
/*
49+
* SanitizerKind::IntegerDivideByZero emits
50+
* SanitizerHandler::DivremOverflow.
51+
*/
52+
case ubsan_divrem_overflow:
53+
return "UBSAN: divide/remainder overflow";
54+
#endif
55+
#ifdef CONFIG_UBSAN_UNREACHABLE
56+
/*
57+
* SanitizerKind::Unreachable emits
58+
* SanitizerHandler::BuiltinUnreachable.
59+
*/
60+
case ubsan_builtin_unreachable:
61+
return "UBSAN: unreachable code";
62+
#endif
63+
#if defined(CONFIG_UBSAN_BOOL) || defined(CONFIG_UBSAN_ENUM)
64+
/*
65+
* SanitizerKind::Bool and SanitizerKind::Enum emit
66+
* SanitizerHandler::LoadInvalidValue.
67+
*/
68+
case ubsan_load_invalid_value:
69+
return "UBSAN: loading invalid value";
70+
#endif
71+
#ifdef CONFIG_UBSAN_ALIGNMENT
72+
/*
73+
* SanitizerKind::Alignment emits SanitizerHandler::TypeMismatch
74+
* or SanitizerHandler::AlignmentAssumption.
75+
*/
76+
case ubsan_alignment_assumption:
77+
return "UBSAN: alignment assumption";
78+
case ubsan_type_mismatch:
79+
return "UBSAN: type mismatch";
80+
#endif
81+
default:
82+
return "UBSAN: unrecognized failure code";
83+
}
84+
}
85+
86+
#else
2187
static const char * const type_check_kinds[] = {
2288
"load of",
2389
"store to",
@@ -384,3 +450,5 @@ void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
384450
ubsan_epilogue();
385451
}
386452
EXPORT_SYMBOL(__ubsan_handle_alignment_assumption);
453+
454+
#endif /* !CONFIG_UBSAN_TRAP */

lib/ubsan.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,38 @@
22
#ifndef _LIB_UBSAN_H
33
#define _LIB_UBSAN_H
44

5+
/*
6+
* ABI defined by Clang's UBSAN enum SanitizerHandler:
7+
* https://github.com/llvm/llvm-project/blob/release/16.x/clang/lib/CodeGen/CodeGenFunction.h#L113
8+
*/
9+
enum ubsan_checks {
10+
ubsan_add_overflow,
11+
ubsan_builtin_unreachable,
12+
ubsan_cfi_check_fail,
13+
ubsan_divrem_overflow,
14+
ubsan_dynamic_type_cache_miss,
15+
ubsan_float_cast_overflow,
16+
ubsan_function_type_mismatch,
17+
ubsan_implicit_conversion,
18+
ubsan_invalid_builtin,
19+
ubsan_invalid_objc_cast,
20+
ubsan_load_invalid_value,
21+
ubsan_missing_return,
22+
ubsan_mul_overflow,
23+
ubsan_negate_overflow,
24+
ubsan_nullability_arg,
25+
ubsan_nullability_return,
26+
ubsan_nonnull_arg,
27+
ubsan_nonnull_return,
28+
ubsan_out_of_bounds,
29+
ubsan_pointer_overflow,
30+
ubsan_shift_out_of_bounds,
31+
ubsan_sub_overflow,
32+
ubsan_type_mismatch,
33+
ubsan_alignment_assumption,
34+
ubsan_vla_bound_not_positive,
35+
};
36+
537
enum {
638
type_kind_int = 0,
739
type_kind_float = 1,

0 commit comments

Comments
 (0)