Skip to content

Commit a421b92

Browse files
monitor: decode faults caused by UBSAN
In a freestanding environment on ARM64, running with LLVM's UB sanitizers will result in a `brk` instruction with a particular encoding that contains the reason UB was detected. Unfortunately, on RISC-V UBSAN just emits an unimp instruction and from what I can tell there's no way to get further information as to *why* UB was detected. Signed-off-by: Ivan-Velickovic <i.velickovic@unsw.edu.au>
1 parent fdfa088 commit a421b92

File tree

1 file changed

+121
-1
lines changed

1 file changed

+121
-1
lines changed

monitor/src/main.c

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,103 @@ static char *data_abort_dfsc_to_string(uintptr_t dfsc)
329329
}
330330
#endif
331331

332+
/* UBSAN decoding related functionality */
333+
#define UBSAN_ARM64_BRK_IMM 0x5500
334+
#define UBSAN_ARM64_BRK_MASK 0x00ff
335+
#define ESR_COMMENT_MASK ((1 << 16) - 1)
336+
#define ARM64_BRK_EC 60
337+
338+
/*
339+
* ABI defined by Clang's UBSAN enum SanitizerHandler:
340+
* https://github.com/llvm/llvm-project/blob/release/16.x/clang/lib/CodeGen/CodeGenFunction.h#L113
341+
*/
342+
enum UBSAN_CHECKS {
343+
UBSAN_ADD_OVERFLOW,
344+
UBSAN_BUILTIN_UNREACHABLE,
345+
UBSAN_CFI_CHECK_FAIL,
346+
UBSAN_DIVREM_OVERFLOW,
347+
UBSAN_DYNAMIC_TYPE_CACHE_MISS,
348+
UBSAN_FLOAT_CAST_OVERFLOW,
349+
UBSAN_FUNCTION_TYPE_MISMATCH,
350+
UBSAN_IMPLICIT_CONVERSION,
351+
UBSAN_INVALID_BUILTIN,
352+
UBSAN_INVALID_OBJC_CAST,
353+
UBSAN_LOAD_INVALID_VALUE,
354+
UBSAN_MISSING_RETURN,
355+
UBSAN_MUL_OVERFLOW,
356+
UBSAN_NEGATE_OVERFLOW,
357+
UBSAN_NULLABILITY_ARG,
358+
UBSAN_NULLABILITY_RETURN,
359+
UBSAN_NONNULL_ARG,
360+
UBSAN_NONNULL_RETURN,
361+
UBSAN_OUT_OF_BOUNDS,
362+
UBSAN_POINTER_OVERFLOW,
363+
UBSAN_SHIFT_OUT_OF_BOUNDS,
364+
UBSAN_SUB_OVERFLOW,
365+
UBSAN_TYPE_MISMATCH,
366+
UBSAN_ALIGNMENT_ASSUMPTION,
367+
UBSAN_VLA_BOUND_NOT_POSITIVE,
368+
};
369+
370+
#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
371+
static char *usban_code_to_string(seL4_Word code) {
372+
switch (code) {
373+
case UBSAN_ADD_OVERFLOW:
374+
return "add overflow";
375+
case UBSAN_BUILTIN_UNREACHABLE:
376+
return "builtin unreachable";
377+
case UBSAN_CFI_CHECK_FAIL:
378+
return "control-flow-integrity check fail";
379+
case UBSAN_DIVREM_OVERFLOW:
380+
return "division remainder overflow";
381+
case UBSAN_DYNAMIC_TYPE_CACHE_MISS:
382+
return "dynamic type cache miss";
383+
case UBSAN_FLOAT_CAST_OVERFLOW:
384+
return "float case overflow";
385+
case UBSAN_FUNCTION_TYPE_MISMATCH:
386+
return "function type mismatch";
387+
case UBSAN_IMPLICIT_CONVERSION:
388+
return "implicit conversion";
389+
case UBSAN_INVALID_BUILTIN:
390+
return "invalid builtin";
391+
case UBSAN_INVALID_OBJC_CAST:
392+
return "invalid objc cast";
393+
case UBSAN_LOAD_INVALID_VALUE:
394+
return "load invalid value";
395+
case UBSAN_MISSING_RETURN:
396+
return "missing return";
397+
case UBSAN_MUL_OVERFLOW:
398+
return "multiplication overflow";
399+
case UBSAN_NEGATE_OVERFLOW:
400+
return "negate overlfow";
401+
case UBSAN_NULLABILITY_ARG:
402+
return "nullability argument";
403+
case UBSAN_NULLABILITY_RETURN:
404+
return "nullability return";
405+
case UBSAN_NONNULL_ARG:
406+
return "non-null argument";
407+
case UBSAN_NONNULL_RETURN:
408+
return "non-null return";
409+
case UBSAN_OUT_OF_BOUNDS:
410+
return "out of bounds access";
411+
case UBSAN_POINTER_OVERFLOW:
412+
return "pointer overflow";
413+
case UBSAN_SHIFT_OUT_OF_BOUNDS:
414+
return "shift out of bounds";
415+
case UBSAN_SUB_OVERFLOW:
416+
return "subtraction overflow";
417+
case UBSAN_TYPE_MISMATCH:
418+
return "type mismatch";
419+
case UBSAN_ALIGNMENT_ASSUMPTION:
420+
return "alignment assumption";
421+
case UBSAN_VLA_BOUND_NOT_POSITIVE:
422+
return "variable-length-array bound not positive";
423+
default:
424+
return "unknown reason";
425+
}
426+
}
427+
#endif
428+
332429
static void check_untypeds_match(seL4_BootInfo *bi)
333430
{
334431
/* Check that untypeds list generate from build matches the kernel */
@@ -930,8 +1027,31 @@ static void monitor(void)
9301027

9311028
break;
9321029
}
1030+
#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
1031+
case seL4_Fault_VCPUFault: {
1032+
seL4_Word esr = seL4_GetMR(seL4_VCPUFault_HSR);
1033+
seL4_Word ec = esr >> 26;
1034+
1035+
puts("MON|ERROR: received vCPU fault with ESR: ");
1036+
puthex64(esr);
1037+
puts("\n");
1038+
1039+
seL4_Word esr_comment = esr & ESR_COMMENT_MASK;
1040+
if (ec == ARM64_BRK_EC && ((esr_comment & ~UBSAN_ARM64_BRK_MASK) == UBSAN_ARM64_BRK_IMM)) {
1041+
/* We likely have a UBSAN check going off from a brk instruction */
1042+
seL4_Word ubsan_code = esr_comment & UBSAN_ARM64_BRK_MASK;
1043+
puts("MON|ERROR: potential undefined behaviour detected by UBSAN for: '");
1044+
puts(usban_code_to_string(ubsan_code));
1045+
puts("'\n");
1046+
} else {
1047+
puts("MON|ERROR: Unknown vCPU fault\n");
1048+
}
1049+
break;
1050+
}
1051+
#endif
9331052
default:
934-
puts("Unknown fault\n");
1053+
puts("MON|ERROR: Unknown fault\n");
1054+
puthex64(label);
9351055
break;
9361056
}
9371057
}

0 commit comments

Comments
 (0)