github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/tools/check-syzos.sh (about)

     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  AWK_CMD="awk"
    22  if command -v gawk > /dev/null; then
    23      AWK_CMD="gawk"
    24  fi
    25  
    26  if [ "$TARGETOS" != "linux" ]; then
    27      echo "[INFO] TARGETOS is '$TARGETOS', not 'linux'. Skipping check."
    28      exit 0
    29  fi
    30  
    31  if [ -z "$TARGETARCH" ]; then
    32      echoerr "Error: \$TARGETARCH environment variable is not set."
    33      exit 1
    34  fi
    35  
    36  BINARY="bin/${TARGETOS}_${TARGETARCH}/syz-executor"
    37  
    38  if [ ! -f "$BINARY" ]; then
    39      echoerr "Error: Binary not found at '$BINARY'"
    40      exit 1
    41  fi
    42  
    43  echoerr "--> Analyzing architecture '$TARGETARCH'..."
    44  OBJDUMP_CMD=""
    45  
    46  if [ "$TARGETARCH" = "amd64" ]; then
    47      ARCH="x86_64"
    48      if command -v x86_64-linux-gnu-objdump > /dev/null; then
    49          OBJDUMP_CMD="x86_64-linux-gnu-objdump"
    50      fi
    51  elif [ "$TARGETARCH" = "arm64" ]; then
    52      ARCH="aarch64"
    53      PATTERNS_TO_FIND='adrp'
    54      if command -v aarch64-linux-gnu-objdump > /dev/null; then
    55          OBJDUMP_CMD="aarch64-linux-gnu-objdump"
    56      fi
    57  else
    58      echo "[INFO] Unsupported architecture '$TARGETARCH', skipping check."
    59      exit 0
    60  fi
    61  echoerr "--> Detected architecture: $ARCH"
    62  
    63  if [ -z "$OBJDUMP_CMD" ]; then
    64      echoerr "--> Arch-specific objdump not found, falling back to generic 'objdump'..."
    65      if command -v objdump > /dev/null; then
    66          OBJDUMP_CMD="objdump"
    67      fi
    68  fi
    69  
    70  if [ -z "$OBJDUMP_CMD" ]; then
    71      echoerr "Error: Could not find a usable objdump binary."
    72      exit 1
    73  fi
    74  echoerr "--> Using objdump: $OBJDUMP_CMD"
    75  
    76  echoerr "--> Verifying existence of section '$SECTION_TO_CHECK' in '$BINARY'..."
    77  if ! "$OBJDUMP_CMD" -h --section="$SECTION_TO_CHECK" "$BINARY" >/dev/null 2>&1; then
    78      echo
    79      echo "[INFO] Section '$SECTION_TO_CHECK' not found in '$BINARY'. Skipping check."
    80      exit 0
    81  fi
    82  
    83  echoerr "--> Disassembling section '$SECTION_TO_CHECK' and scanning for problematic instructions..."
    84  
    85  DISASSEMBLY_STATUS=0
    86  DISASSEMBLY_OUTPUT=$("$OBJDUMP_CMD" -d --section="$SECTION_TO_CHECK" "$BINARY" 2>/dev/null) || DISASSEMBLY_STATUS=$?
    87  
    88  if [ $DISASSEMBLY_STATUS -ne 0 ]; then
    89      echoerr "Error: '$OBJDUMP_CMD' failed to disassemble the '$SECTION_TO_CHECK' section."
    90      # Attempt to show the actual error to the user
    91      "$OBJDUMP_CMD" -d --section="$SECTION_TO_CHECK" "$BINARY" >/dev/null
    92      exit 1
    93  fi
    94  
    95  if [ "$TARGETARCH" = "amd64" ]; then
    96      echoerr "--> Getting guest section boundaries..."
    97      SECTION_INFO=$("$OBJDUMP_CMD" -h "$BINARY" | grep " $SECTION_TO_CHECK ")
    98      if [ -z "$SECTION_INFO" ]; then
    99          echoerr "Error: Could not get section info for '$SECTION_TO_CHECK'"
   100          exit 1
   101      fi
   102      GUEST_VMA=$(echo "$SECTION_INFO" | $AWK_CMD '{print "0x"$4}')
   103      GUEST_SIZE=$(echo "$SECTION_INFO" | $AWK_CMD '{print "0x"$3}')
   104      GUEST_START=$(printf "%d" "$GUEST_VMA")
   105      GUEST_END=$((GUEST_START + $(printf "%d" "$GUEST_SIZE")))
   106      echoerr "--> Guest section range (hex): [$(printf "0x%x" "$GUEST_START"), $(printf "0x%x" "$GUEST_END"))"
   107  
   108      FOUND_INSTRUCTIONS=$(echo "$DISASSEMBLY_OUTPUT" | {
   109          current_func=""
   110          problematic_lines=""
   111          while IFS= read -r line; do
   112              if echo "$line" | grep -q -E '^[0-9a-f]+ <.*>:$'; then
   113                  current_func=$(echo "$line" | sed -n 's/.*<\(.*\)>:/\1/p')
   114                  continue
   115              fi
   116              if echo "$line" | grep -q '(%rip)'; then
   117                  target_addr_hex=$(echo "$line" | sed -n 's/.*# \([0-9a-f]\+\).*/\1/p')
   118                  if [ -z "$target_addr_hex" ]; then
   119                      continue
   120                  fi
   121                  target_addr_dec=$(printf "%d" "0x$target_addr_hex")
   122                  if [ "$target_addr_dec" -lt "$GUEST_START" ] || [ "$target_addr_dec" -gt "$GUEST_END" ]; then
   123                      if [ -n "$current_func" ]; then
   124                          problematic_lines="${problematic_lines}In function <${current_func}>:\n"
   125                      fi
   126                      problematic_lines="${problematic_lines}\t${line}\n"
   127                  fi
   128              fi
   129          done
   130          printf "%b" "$problematic_lines"
   131      })
   132  else
   133      # The original logic for other architectures (e.g. arm64)
   134      FOUND_INSTRUCTIONS=$(echo "$DISASSEMBLY_OUTPUT" | $AWK_CMD -v pattern="$PATTERNS_TO_FIND" '
   135      # Match a function header, e.g., "0000000000401136 <my_func>:"
   136      /^[0-9a-f]+ <.*>:$/ {
   137          match($0, /<.*>/)
   138          current_func = substr($0, RSTART, RLENGTH)
   139      }
   140      # If the line matches the instruction pattern, print the context.
   141      $0 ~ pattern {
   142          if (current_func) {
   143              print "In function " current_func ":"
   144          }
   145          print "\t" $0
   146      }
   147  ' || true)
   148  fi
   149  
   150  if [ -n "$FOUND_INSTRUCTIONS" ]; then
   151      echo
   152      echo "------------------------------------------------------------------"
   153      echo "[FAIL] Found problematic data access instructions in '$SECTION_TO_CHECK'."
   154      echo "The following instructions are likely to cause crashes in SyzOS:"
   155      echo "$FOUND_INSTRUCTIONS" | sed 's/^/  /'
   156      echo "------------------------------------------------------------------"
   157      echo
   158      echo "This typically happens when the C compiler emits read-only constants for"
   159      echo "zero-initializing structs or for jump tables in switch statements."
   160      exit 1
   161  else
   162      # Do not print anything to stdout unless there's an error.
   163      echoerr
   164      echoerr "[OK] No problematic data access instructions found in '$SECTION_TO_CHECK'."
   165      exit 0
   166  fi