Skip to content

Commit 31ba65f

Browse files
tools: add check-syzos.sh
As shown in #5565, SYZOS code in the `guest` section cannot reference global data, because it is relocated into the guest memory. While arm64 executor has a dynamic check for data accesses, it is virtually impossible to do the same on x86 without implementing an x86 disassembler. Instead of doing so, introduce a build-time script that will detect instructions referencing global data on a best-effort basis.
1 parent fdeaa69 commit 31ba65f

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ endif
118118

119119
all: host target
120120
host: manager repro mutate prog2c db upgrade
121-
target: execprog executor
121+
target: execprog executor check_syzos
122122

123123
executor: descriptions
124124
ifeq ($(TARGETOS),fuchsia)
@@ -427,6 +427,9 @@ check_links:
427427
check_html:
428428
./tools/check-html.sh
429429

430+
check_syzos: executor
431+
./tools/check-syzos.sh 2>/dev/null
432+
430433
# Check that the diff is empty. This is meant to be executed after generating
431434
# and formatting the code to make sure that everything is committed.
432435
check_diff:

tools/check-syzos.sh

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#!/bin/sh
2+
# Copyright 2025 syzkaller project authors. All rights reserved.
3+
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
4+
#
5+
# This script scans the syz-executor binary for data relocations accesses
6+
# within the "guest" ELF section that are problematic for the SYZOS guest
7+
# code.
8+
#
9+
# It uses $TARGETOS and $TARGETARCH to locate the binary and determine the
10+
# correct architecture.
11+
#
12+
13+
set -e
14+
15+
SECTION_TO_CHECK="guest"
16+
17+
echoerr() {
18+
echo "$@" >&2
19+
}
20+
21+
if [ "$TARGETOS" != "linux" ]; then
22+
echo "[INFO] TARGETOS is '$TARGETOS', not 'linux'. Skipping check."
23+
exit 0
24+
fi
25+
26+
if [ -z "$TARGETARCH" ]; then
27+
echoerr "Error: \$TARGETARCH environment variable is not set."
28+
exit 1
29+
fi
30+
31+
BINARY="bin/${TARGETOS}_${TARGETARCH}/syz-executor"
32+
33+
if [ ! -f "$BINARY" ]; then
34+
echoerr "Error: Binary not found at '$BINARY'"
35+
exit 1
36+
fi
37+
38+
echoerr "--> Analyzing architecture '$TARGETARCH'..."
39+
OBJDUMP_CMD=""
40+
41+
if [ "$TARGETARCH" = "amd64" ]; then
42+
ARCH="x86_64"
43+
PATTERNS_TO_FIND='\(%rip\)'
44+
if command -v x86_64-linux-gnu-objdump > /dev/null; then
45+
OBJDUMP_CMD="x86_64-linux-gnu-objdump"
46+
fi
47+
elif [ "$TARGETARCH" = "arm64" ]; then
48+
ARCH="aarch64"
49+
PATTERNS_TO_FIND='adrp'
50+
if command -v aarch64-linux-gnu-objdump > /dev/null; then
51+
OBJDUMP_CMD="aarch64-linux-gnu-objdump"
52+
fi
53+
else
54+
echo "[INFO] Unsupported architecture '$TARGETARCH', skipping check."
55+
exit 0
56+
fi
57+
echoerr "--> Detected architecture: $ARCH"
58+
59+
if [ -z "$OBJDUMP_CMD" ]; then
60+
echoerr "--> Arch-specific objdump not found, falling back to generic 'objdump'..."
61+
if command -v objdump > /dev/null; then
62+
OBJDUMP_CMD="objdump"
63+
fi
64+
fi
65+
66+
if [ -z "$OBJDUMP_CMD" ]; then
67+
echoerr "Error: Could not find a usable objdump binary."
68+
exit 1
69+
fi
70+
echoerr "--> Using objdump: $OBJDUMP_CMD"
71+
72+
echoerr "--> Verifying existence of section '$SECTION_TO_CHECK' in '$BINARY'..."
73+
if ! "$OBJDUMP_CMD" -h --section="$SECTION_TO_CHECK" "$BINARY" >/dev/null 2>&1; then
74+
echo
75+
echo "[INFO] Section '$SECTION_TO_CHECK' not found in '$BINARY'. Skipping check."
76+
exit 0
77+
fi
78+
79+
echoerr "--> Disassembling section '$SECTION_TO_CHECK' and scanning for patterns ('$PATTERNS_TO_FIND')..."
80+
81+
DISASSEMBLY_STATUS=0
82+
DISASSEMBLY_OUTPUT=$("$OBJDUMP_CMD" -d --section="$SECTION_TO_CHECK" "$BINARY" 2>/dev/null) || DISASSEMBLY_STATUS=$?
83+
84+
if [ $DISASSEMBLY_STATUS -ne 0 ]; then
85+
echoerr "Error: '$OBJDUMP_CMD' failed to disassemble the '$SECTION_TO_CHECK' section."
86+
# Attempt to show the actual error to the user
87+
"$OBJDUMP_CMD" -d --section="$SECTION_TO_CHECK" "$BINARY" >/dev/null
88+
exit 1
89+
fi
90+
91+
FOUND_INSTRUCTIONS=$(echo "$DISASSEMBLY_OUTPUT" | awk -v pattern="$PATTERNS_TO_FIND" '
92+
# Match a function header, e.g., "0000000000401136 <my_func>:"
93+
/^[0-9a-f]+ <.*>:$/ {
94+
match($0, /<.*>/)
95+
current_func = substr($0, RSTART, RLENGTH)
96+
}
97+
# If the line matches the instruction pattern, print the context.
98+
$0 ~ pattern {
99+
if (current_func) {
100+
print "In function " current_func ":"
101+
}
102+
print "\t" $0
103+
}
104+
' || true)
105+
106+
if [ -n "$FOUND_INSTRUCTIONS" ]; then
107+
echo
108+
echo "------------------------------------------------------------------"
109+
echo "[FAIL] Found problematic data access instructions in '$SECTION_TO_CHECK'."
110+
echo "The following instructions are likely to cause crashes in SyzOS:"
111+
echo "$FOUND_INSTRUCTIONS" | sed 's/^/ /'
112+
echo "------------------------------------------------------------------"
113+
echo
114+
echo "This typically happens when the C compiler emits read-only constants for"
115+
echo "zero-initializing structs or for jump tables in switch statements."
116+
exit 1
117+
else
118+
echo
119+
echo "[OK] No problematic data access instructions found in '$SECTION_TO_CHECK'."
120+
exit 0
121+
fi

0 commit comments

Comments
 (0)