Hi, I spotted this when trying to run an Android application under UBSan. Upon digging, I found this issue:
A Clang Control Flow Integrity (CFI) type mismatch occurs in src/arm/linux/cpuinfo.c when invoking the parse_line callback through the cpuinfo_line_callback function pointer. This triggers a runtime SIGTRAP when CFI is enabled.
The issue is that parse_line is defined with a specific structure pointer as its third argument, but it is cast to cpuinfo_line_callback which expects void* for that argument.
In src/arm/linux/cpuinfo.c we have parse_line which takes a proc_cpuinfo_parser_state argument
|
static bool parse_line( |
|
const char* line_start, |
|
const char* line_end, |
|
struct proc_cpuinfo_parser_state state[restrict static 1], |
|
uint64_t line_number) { |
In cpuinfo_arm_linux_parse_proc_cpuinfo:
|
CPUINFO_INTERNAL bool cpuinfo_arm_linux_parse_proc_cpuinfo( |
|
char hardware[restrict static CPUINFO_HARDWARE_VALUE_MAX], |
|
char revision[restrict static CPUINFO_REVISION_VALUE_MAX], |
|
uint32_t max_processors_count, |
|
struct cpuinfo_arm_linux_processor processors[restrict static max_processors_count]); |
The callback type is defined in src/linux/api.h as:
|
typedef bool (*cpuinfo_line_callback)(const char*, const char*, void*, uint64_t); |
The problem is specifically here, where we cast parse_line to cpuinfo_line_callback. These functions have different signatures:
|
return cpuinfo_linux_parse_multiline_file( |
|
"/proc/cpuinfo", BUFFER_SIZE, (cpuinfo_line_callback)parse_line, &state); |
|
} |
Calling a function through a pointer of a different type (even if they are pointer-compatible in some ABIs) is Undefined Behavior in C and is flagged by Clang's -fsanitize=cfi-icall.
Suggested fix: Change parse_line to accept void* for the context argument, and cast it inside the function. Remove the cast when passing it to cpuinfo_linux_parse_multiline_file.
--- a/src/arm/linux/cpuinfo.c
+++ b/src/arm/linux/cpuinfo.c
@@ -726,8 +726,9 @@
static bool parse_line(
const char* line_start,
const char* line_end,
- struct proc_cpuinfo_parser_state state[restrict static 1],
+ void* context,
uint64_t line_number) {
+ struct proc_cpuinfo_parser_state* restrict state = (struct proc_cpuinfo_parser_state*)context;
/* Empty line. Skip. */
if (line_start == line_end) {
return true;
@@ -1019,5 +1018,5 @@
.processors = processors,
};
return cpuinfo_linux_parse_multiline_file(
- "/proc/cpuinfo", BUFFER_SIZE, (cpuinfo_line_callback)parse_line, &state);
+ "/proc/cpuinfo", BUFFER_SIZE, parse_line, &state);
}
Hi, I spotted this when trying to run an Android application under UBSan. Upon digging, I found this issue:
A Clang Control Flow Integrity (CFI) type mismatch occurs in
src/arm/linux/cpuinfo.cwhen invoking theparse_linecallback through thecpuinfo_line_callbackfunction pointer. This triggers a runtimeSIGTRAPwhen CFI is enabled.The issue is that
parse_lineis defined with a specific structure pointer as its third argument, but it is cast tocpuinfo_line_callbackwhich expectsvoid*for that argument.In
src/arm/linux/cpuinfo.cwe haveparse_linewhich takes aproc_cpuinfo_parser_stateargumentcpuinfo/src/arm/linux/cpuinfo.c
Lines 726 to 730 in ae54436
In
cpuinfo_arm_linux_parse_proc_cpuinfo:cpuinfo/src/arm/linux/api.h
Lines 297 to 301 in ae54436
The callback type is defined in
src/linux/api.has:cpuinfo/src/linux/api.h
Line 37 in ae54436
The problem is specifically here, where we cast
parse_linetocpuinfo_line_callback. These functions have different signatures:cpuinfo/src/arm/linux/cpuinfo.c
Lines 1021 to 1023 in ae54436
Calling a function through a pointer of a different type (even if they are pointer-compatible in some ABIs) is Undefined Behavior in C and is flagged by Clang's
-fsanitize=cfi-icall.Suggested fix: Change
parse_lineto acceptvoid*for the context argument, and cast it inside the function. Remove the cast when passing it tocpuinfo_linux_parse_multiline_file.