Skip to content

Commit f4fd2b8

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 f4fd2b8

File tree

1 file changed

+122
-1
lines changed

1 file changed

+122
-1
lines changed

monitor/src/main.c

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,104 @@ 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+
{
373+
switch (code) {
374+
case UBSAN_ADD_OVERFLOW:
375+
return "add overflow";
376+
case UBSAN_BUILTIN_UNREACHABLE:
377+
return "builtin unreachable";
378+
case UBSAN_CFI_CHECK_FAIL:
379+
return "control-flow-integrity check fail";
380+
case UBSAN_DIVREM_OVERFLOW:
381+
return "division remainder overflow";
382+
case UBSAN_DYNAMIC_TYPE_CACHE_MISS:
383+
return "dynamic type cache miss";
384+
case UBSAN_FLOAT_CAST_OVERFLOW:
385+
return "float case overflow";
386+
case UBSAN_FUNCTION_TYPE_MISMATCH:
387+
return "function type mismatch";
388+
case UBSAN_IMPLICIT_CONVERSION:
389+
return "implicit conversion";
390+
case UBSAN_INVALID_BUILTIN:
391+
return "invalid builtin";
392+
case UBSAN_INVALID_OBJC_CAST:
393+
return "invalid objc cast";
394+
case UBSAN_LOAD_INVALID_VALUE:
395+
return "load invalid value";
396+
case UBSAN_MISSING_RETURN:
397+
return "missing return";
398+
case UBSAN_MUL_OVERFLOW:
399+
return "multiplication overflow";
400+
case UBSAN_NEGATE_OVERFLOW:
401+
return "negate overlfow";
402+
case UBSAN_NULLABILITY_ARG:
403+
return "nullability argument";
404+
case UBSAN_NULLABILITY_RETURN:
405+
return "nullability return";
406+
case UBSAN_NONNULL_ARG:
407+
return "non-null argument";
408+
case UBSAN_NONNULL_RETURN:
409+
return "non-null return";
410+
case UBSAN_OUT_OF_BOUNDS:
411+
return "out of bounds access";
412+
case UBSAN_POINTER_OVERFLOW:
413+
return "pointer overflow";
414+
case UBSAN_SHIFT_OUT_OF_BOUNDS:
415+
return "shift out of bounds";
416+
case UBSAN_SUB_OVERFLOW:
417+
return "subtraction overflow";
418+
case UBSAN_TYPE_MISMATCH:
419+
return "type mismatch";
420+
case UBSAN_ALIGNMENT_ASSUMPTION:
421+
return "alignment assumption";
422+
case UBSAN_VLA_BOUND_NOT_POSITIVE:
423+
return "variable-length-array bound not positive";
424+
default:
425+
return "unknown reason";
426+
}
427+
}
428+
#endif
429+
332430
static void check_untypeds_match(seL4_BootInfo *bi)
333431
{
334432
/* Check that untypeds list generate from build matches the kernel */
@@ -930,8 +1028,31 @@ static void monitor(void)
9301028

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

0 commit comments

Comments
 (0)