aboutsummaryrefslogtreecommitdiffstats
path: root/tools/check-syzos.sh
blob: 163753f03dc639f8198218effa5ebd0c44396614 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/bin/sh
# Copyright 2025 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
#
# This script scans the syz-executor binary for data relocations accesses
# within the "guest" ELF section that are problematic for the SYZOS guest
# code.
#
# It uses $TARGETOS and $TARGETARCH to locate the binary and determine the
# correct architecture.
#

set -e

SECTION_TO_CHECK="guest"

echoerr() {
    echo "$@" >&2
}

AWK_CMD="awk"
if command -v gawk > /dev/null; then
    AWK_CMD="gawk"
fi

if [ "$TARGETOS" != "linux" ]; then
    echo "[INFO] TARGETOS is '$TARGETOS', not 'linux'. Skipping check."
    exit 0
fi

if [ -z "$TARGETARCH" ]; then
    echoerr "Error: \$TARGETARCH environment variable is not set."
    exit 1
fi

BINARY="bin/${TARGETOS}_${TARGETARCH}/syz-executor"

if [ ! -f "$BINARY" ]; then
    echoerr "Error: Binary not found at '$BINARY'"
    exit 1
fi

echoerr "--> Analyzing architecture '$TARGETARCH'..."
OBJDUMP_CMD=""

if [ "$TARGETARCH" = "amd64" ]; then
    ARCH="x86_64"
    if command -v x86_64-linux-gnu-objdump > /dev/null; then
        OBJDUMP_CMD="x86_64-linux-gnu-objdump"
    fi
elif [ "$TARGETARCH" = "arm64" ]; then
    ARCH="aarch64"
    PATTERNS_TO_FIND='adrp'
    if command -v aarch64-linux-gnu-objdump > /dev/null; then
        OBJDUMP_CMD="aarch64-linux-gnu-objdump"
    fi
else
    echo "[INFO] Unsupported architecture '$TARGETARCH', skipping check."
    exit 0
fi
echoerr "--> Detected architecture: $ARCH"

if [ -z "$OBJDUMP_CMD" ]; then
    echoerr "--> Arch-specific objdump not found, falling back to generic 'objdump'..."
    if command -v objdump > /dev/null; then
        OBJDUMP_CMD="objdump"
    fi
fi

if [ -z "$OBJDUMP_CMD" ]; then
    echoerr "Error: Could not find a usable objdump binary."
    exit 1
fi
echoerr "--> Using objdump: $OBJDUMP_CMD"

echoerr "--> Verifying existence of section '$SECTION_TO_CHECK' in '$BINARY'..."
if ! "$OBJDUMP_CMD" -h --section="$SECTION_TO_CHECK" "$BINARY" >/dev/null 2>&1; then
    echo
    echo "[INFO] Section '$SECTION_TO_CHECK' not found in '$BINARY'. Skipping check."
    exit 0
fi

echoerr "--> Disassembling section '$SECTION_TO_CHECK' and scanning for problematic instructions..."

DISASSEMBLY_STATUS=0
DISASSEMBLY_OUTPUT=$("$OBJDUMP_CMD" -d --section="$SECTION_TO_CHECK" "$BINARY" 2>/dev/null) || DISASSEMBLY_STATUS=$?

if [ $DISASSEMBLY_STATUS -ne 0 ]; then
    echoerr "Error: '$OBJDUMP_CMD' failed to disassemble the '$SECTION_TO_CHECK' section."
    # Attempt to show the actual error to the user
    "$OBJDUMP_CMD" -d --section="$SECTION_TO_CHECK" "$BINARY" >/dev/null
    exit 1
fi

if [ "$TARGETARCH" = "amd64" ]; then
    echoerr "--> Getting guest section boundaries..."
    SECTION_INFO=$("$OBJDUMP_CMD" -h "$BINARY" | grep " $SECTION_TO_CHECK ")
    if [ -z "$SECTION_INFO" ]; then
        echoerr "Error: Could not get section info for '$SECTION_TO_CHECK'"
        exit 1
    fi
    GUEST_VMA=$(echo "$SECTION_INFO" | $AWK_CMD '{print "0x"$4}')
    GUEST_SIZE=$(echo "$SECTION_INFO" | $AWK_CMD '{print "0x"$3}')
    GUEST_START=$(printf "%d" "$GUEST_VMA")
    GUEST_END=$((GUEST_START + $(printf "%d" "$GUEST_SIZE")))
    echoerr "--> Guest section range (hex): [$(printf "0x%x" "$GUEST_START"), $(printf "0x%x" "$GUEST_END"))"

    FOUND_INSTRUCTIONS=$(echo "$DISASSEMBLY_OUTPUT" | {
        current_func=""
        problematic_lines=""
        while IFS= read -r line; do
            if echo "$line" | grep -q -E '^[0-9a-f]+ <.*>:$'; then
                current_func=$(echo "$line" | sed -n 's/.*<\(.*\)>:/\1/p')
                continue
            fi
            if echo "$line" | grep -q '(%rip)'; then
                target_addr_hex=$(echo "$line" | sed -n 's/.*# \([0-9a-f]\+\).*/\1/p')
                if [ -z "$target_addr_hex" ]; then
                    continue
                fi
                target_addr_dec=$(printf "%d" "0x$target_addr_hex")
                if [ "$target_addr_dec" -lt "$GUEST_START" ] || [ "$target_addr_dec" -gt "$GUEST_END" ]; then
                    if [ -n "$current_func" ]; then
                        problematic_lines="${problematic_lines}In function <${current_func}>:\n"
                    fi
                    problematic_lines="${problematic_lines}\t${line}\n"
                fi
            fi
        done
        printf "%b" "$problematic_lines"
    })
else
    # The original logic for other architectures (e.g. arm64)
    FOUND_INSTRUCTIONS=$(echo "$DISASSEMBLY_OUTPUT" | $AWK_CMD -v pattern="$PATTERNS_TO_FIND" '
    # Match a function header, e.g., "0000000000401136 <my_func>:"
    /^[0-9a-f]+ <.*>:$/ {
        match($0, /<.*>/)
        current_func = substr($0, RSTART, RLENGTH)
    }
    # If the line matches the instruction pattern, print the context.
    $0 ~ pattern {
        if (current_func) {
            print "In function " current_func ":"
        }
        print "\t" $0
    }
' || true)
fi

if [ -n "$FOUND_INSTRUCTIONS" ]; then
    echo
    echo "------------------------------------------------------------------"
    echo "[FAIL] Found problematic data access instructions in '$SECTION_TO_CHECK'."
    echo "The following instructions are likely to cause crashes in SyzOS:"
    echo "$FOUND_INSTRUCTIONS" | sed 's/^/  /'
    echo "------------------------------------------------------------------"
    echo
    echo "This typically happens when the C compiler emits read-only constants for"
    echo "zero-initializing structs or for jump tables in switch statements."
    exit 1
else
    # Do not print anything to stdout unless there's an error.
    echoerr
    echoerr "[OK] No problematic data access instructions found in '$SECTION_TO_CHECK'."
    exit 0
fi