fuzz: syzkaller semi automation script

Jira CAMERASW-30740

Change-Id: I429c9465b1fa1873d3a5e9ef3d9a182e22e486c9
Signed-off-by: Xiaoming Xiang <xxiang@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3314647
Reviewed-by: Ming Chang (SW-TEGRA) <mingchang@nvidia.com>
Reviewed-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Patrick Young <payoung@nvidia.com>
This commit is contained in:
Xiaoming Xiang
2025-03-06 06:57:41 +00:00
committed by Jon Hunter
parent 9192e31e0a
commit f717989baf
3 changed files with 595 additions and 0 deletions

View File

@@ -0,0 +1,398 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#!/bin/bash
# Display help message with usage instructions and available options
show_help() {
echo "Shell Script to syzkaller automation"
echo "Usage:"
echo " source ./syzkaller_automation.sh [options]"
echo ""
echo "Options:"
echo " --fuzz_module test mode: all cdi_mgr.txt cdi_dev.txt capture_vi_channel.txt"
echo " capture_isp_channel.txt cam_fsync.txt"
echo " --tegra_top project directory"
echo " --colossus_ip Colossus ip address"
echo " --tegra_ip Tegra ip address"
echo " --mode MODE Automation Mode valid mode: semi, full (default:semi)"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " source ./syzkaller_automation.sh \\"
echo " --fuzz_module all \\"
echo " --tegra_top /home/xx/automotive-dev-main-xxx \\"
echo " --colossus_ip 10.176.197.155 \\"
echo " --tegra_ip 192.168.1.141 \\"
echo " --mode full"
}
# Display confirmation message and wait for user input
# Returns: 0 on success (Y), 1 on failure (N or invalid input)
confirm_message() {
RED='\033[0;31m'
NC='\033[0m' # No Color
msg="*********************************************************************************\n"
msg+="* *\n"
msg+="* please confirm *\n"
msg+="* *\n"
msg+="*********************************************************************************"
echo -e "${RED}${msg}${NC}"
local patch_base="https://git-master.nvidia.com/r/c/"
echo -e "1. When building the system image, please ensure\n" \
" that the following two changes are included:\n" \
" ${patch_base}linux-stable/+/3326676\n" \
" ${patch_base}device/hardware/nvidia/platform/t23x/auto-pct/+/3207558\n"\
" Recompile the foundation and linux none debug, and flash the board.\n"
echo -e "2. Please update the configs file. <sshkey>,<user>,<repo-path> and module_obj path.\n"\
" sshkey: /home/user/.ssh/id_rsa\n" \
" repo-path:automotive-dev-main-20250310T181236003\n"
echo -e "3. Please add LocalForward 50000 127.0.0.1:50000 to the ~/.ssh/config file.\n"
echo -e "Please confirm whether the above operations have been completed: (y/N)"
read -r user_input
if [[ "$user_input" =~ ^[Yy]$ ]]; then
echo "continue syzkaller automation...."
elif [[ "$user_input" =~ ^[Nn]$ ]]; then
echo "exit syzkaller automation...."
return 1
else
echo "Invalid input. Please enter Y or N."
return 1
fi
}
# Setup syzkaller environment
# Checks installation, creates directories, and configures toolchain
# Returns: 0 on success, 1 on failure
syzkaller_setup() {
echo "check syzkaller installation"
if [ -d "$SYZKALLER_DIR" ]; then
echo "syzkaller directory exists:${SYZKALLER_DIR}"
if [ -d "$SYZKALLER_DIR/syzkaller" ]; then
echo "syzkaller already installation"
else
echo "syzkaller directory not found:${SYZKALLER_DIR}/syzkaller"
syzkaller_installation
fi
else
echo "directory not found:${SYZKALLER_DIR}"
mkdir -p "$SYZKALLER_DIR"
syzkaller_installation
fi
echo "check go installation"
if [ -d "$GO_DIR" ]; then
echo "go already installation"
else
echo "go directory not found:${GO_DIR}"
mkdir -p $GO_DIR
cd $GO_DIR
wget https://dl.google.com/go/go1.22.2.linux-amd64.tar.gz
tar -xf go1.22.2.linux-amd64.tar.gz
fi
if command -v clang >/dev/null 2>&1 && dpkg -l clang 2>/dev/null | grep -q ^ii; then
echo "Clang already installed"
else
echo "need install Clang"
sudo apt update
sudo apt-get install -y clang
fi
TOOLCHAIN=/home/jenkins/p4/sw/embedded/tools/toolchains/bootlin/gcc-13.2.0
CC=$TOOLCHAIN/aarch64--glibc--bleeding-edge-2024.02-1/bin/aarch64-buildroot-linux-gnu-gcc
CXX=$TOOLCHAIN/aarch64--glibc--bleeding-edge-2024.02-1/bin/aarch64-buildroot-linux-gnu-g++
export PATH=$TOOLCHAIN/aarch64--glibc--bleeding-edge-2024.02-1/bin:$PATH
echo "check binutils"
rm -rf ~/bin/aarch64
mkdir -p ~/bin/aarch64
ln -s `which aarch64-buildroot-linux-gnu-addr2line` ~/bin/aarch64/addr2line
ln -s `which aarch64-buildroot-linux-gnu-nm` ~/bin/aarch64/nm
ln -s `which aarch64-buildroot-linux-gnu-objdump` ~/bin/aarch64/objdump
ln -s `which aarch64-buildroot-linux-gnu-readelf` ~/bin/aarch64/readelf
export PATH=~/bin/aarch64:$PATH
}
# Install syzkaller by cloning from GitHub repository
# Returns: 0 on success, 1 on failure
syzkaller_installation() {
echo "begin installation syzkaller..."
cd "$SYZKALLER_DIR" || exit
git clone https://gitlab-master.nvidia.com/williliu/syzkaller.git
if [ $? -ne 0 ]; then
echo "Error: Failed to clone the syzkaller repository"
return 1
fi
echo "syzkaller installation complete"
}
# Build syzkaller
# Sets up environment variables and compiles syzkaller
# Returns: 0 on success, 1 on failure
syzkaller_build() {
echo "begin build syzkaller..."
if [ ! -d "$SYZKALLER_DIR/syzkaller" ]; then
echo "Error: syzkaller directory not found: $SYZKALLER_DIR/syzkaller"
return 1
fi
cd $SYZKALLER_DIR/syzkaller
export GOROOT=$GO_DIR/go
export PATH=$GOROOT/bin:$PATH
export GOPATH=$SYZKALLER_DIR/syzkaller
OS="linux"
ARCH="arm64"
SOURCEDIR="$TEGRA_TOP/kernel/kernel-oot"
build_base_path="$TEGRA_TOP/out/embedded-linux-generic-debug-none/nvidia/kernel-oot/"
BUILDDIR="$build_base_path/kernel_prod-rt_patches-nvidia-oot/linux-headers/"
echo "syzkaller building..."
make HOSTOS=linux HOSTARCH=amd64 TARGETOS=linux TARGETARCH=arm64 ./bin/syz-extract
if [ ! -d "$SYZKALLER_DIR/syzkaller/sys/linux" ]; then
echo "syzkaller/sys/linux directory not found"
mkdir -p $SYZKALLER_DIR/syzkaller/sys/linux
fi
if [ "$fuzz_module" = "all" ]; then
for module_file in $(list_tests); do
source_file="$(get_module_file_path $module_file)"
echo "source_file: $source_file"
if [ ! -f "$source_file" ]; then
echo "Error: Source file not found: $source_file"
return 1
else
cp "$source_file" "$SYZKALLER_DIR/syzkaller/sys/linux"
fi
done
for module_file in $(list_tests); do
INCLUDEDIRS="$(get_module_include_path $module_file)"
echo "run syzkaller:$SYZKALLER_DIR/syzkaller/bin/syz-extract" \
" -os $OS -arch $ARCH" \
" -sourcedir $SOURCEDIR" \
" -builddir $BUILDDIR" \
" -includedirs $INCLUDEDIRS $module_file"
$SYZKALLER_DIR/syzkaller/bin/syz-extract \
-os $OS \
-arch $ARCH \
-sourcedir $SOURCEDIR \
-builddir $BUILDDIR \
-includedirs $INCLUDEDIRS \
$module_file
if [ $? -ne 0 ]; then
echo "Error: Failed to run syz-extract on $module_file."
return 1
else
const_file="$SYZKALLER_DIR/syzkaller/sys/linux/${module_file}.const"
if [ -f "$const_file" ]; then
echo "Success: Generated valid const file $const_file"
else
echo "Warning: Expected const file $const_file was not generated."
fi
fi
done
fi
make HOSTOS=linux HOSTARCH=amd64 TARGETOS=linux TARGETARCH=arm64
}
# List all available test modules
list_tests() {
echo "$module_tests"
}
# Get include paths for specified module
# Parameters:
# $1 - module name
# Returns: String containing include paths
get_module_include_path() {
local module=$1
local base_path="$TEGRA_TOP/kernel/nvidia-oot"
case $module in
cdi_mgr.txt)
echo "${base_path}/include,"\
"${base_path}/include/uapi/asm-generic" | tr -d ' '
;;
cdi_dev.txt)
echo "${base_path}/include"
;;
capture_vi_channel.txt)
echo "${base_path},${base_path}/include,${base_path}/include/uapi,"\
"${TEGRA_TOP}/camera/firmware-api/kernel-include,"\
"${TEGRA_TOP}/core/include" | tr -d ' '
;;
capture_isp_channel.txt)
echo "${base_path},${base_path}/include,${base_path}/include/uapi,"\
"${TEGRA_TOP}/camera/firmware-api/kernel-include,"\
"${TEGRA_TOP}/core/include" | tr -d ' '
;;
cam_fsync.txt)
echo "${base_path}/include/uapi/media" | tr -d ' '
;;
esac
}
# Get file path for specified module
# Parameters:
# $1 - module name
# Returns: Complete path to module file
get_module_file_path() {
local module=$1
local base_path="$TEGRA_TOP/kernel/nvidia-oot/drivers/media/platform/tegra/fuzz"
case $module in
cdi_mgr.txt)
echo "${base_path}/cdi/cdi_mgr.txt"
;;
cdi_dev.txt)
echo "${base_path}/cdi/cdi_dev.txt"
;;
isc_mgr.txt)
echo "${base_path}/isc/isc_mgr.txt"
;;
capture_vi_channel.txt)
echo "${base_path}/kmd_capture/capture_vi_channel.txt"
;;
capture_isp_channel.txt)
echo "${base_path}/kmd_capture/capture_isp_channel.txt"
;;
cam_fsync.txt)
echo "${base_path}/cam_fsync/cam_fsync.txt"
;;
esac
}
# Execute script on Colossus machine
# Parameters:
# $1 - Colossus IP address
# $2 - Script command to execute
run_script_colossus() {
local colossus_ip=$1
local script_cmd=$2
ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no "$colossus_ip" "$script_cmd"
}
# Get script path for automation
get_script_path() {
echo "$TEGRA_TOP/kernel/nvidia-oot/drivers/media/platform/tegra/fuzz/semi_automation"
}
SYZKALLER_DIR="${HOME}/syzkaller"
GO_DIR="${HOME}/go"
# Test case lists as strings
module_tests="cdi_mgr.txt
cdi_dev.txt
capture_vi_channel.txt
capture_isp_channel.txt
cam_fsync.txt"
automation_mode="semi"
# Main function
# Processes command line arguments and coordinates automation workflow
# Returns: 0 on success, 1 on failure
# Handles:
# - Parameter validation
# - Environment setup
# - Syzkaller build and configuration
# - SSH setup and tunneling
# - Fuzzer execution
main() {
if [ $# -eq 0 ]; then
show_help
return 1
fi
# Parse command-line options
while [ $# -gt 0 ]; do
case $1 in
--fuzz_module)
fuzz_module="$2"
shift 2
;;
--tegra_top)
TEGRA_TOP="$2"
shift 2
;;
--colossus_ip)
colossus_ip_address="$2"
shift 2
;;
--tegra_ip)
tegra_ip_address="$2"
shift 2
;;
--mode)
automation_mode="$2"
shift 2
;;
-h|--help)
show_help
return 0
;;
*)
echo "Invalid option: $1"
show_help
return 1
;;
esac
done
if [ "$automation_mode" = "semi" ]; then
confirm_message || return 1
fi
syzkaller_setup || return 1
syzkaller_build || return 1
local colossus="$USER@$colossus_ip_address"
echo "Colossus:$colossus"
echo "tegra IP:$tegra_ip_address"
local script_cmd="source $(get_script_path)/syzkaller_host_setup.sh --target_ip $tegra_ip_address"
echo "script_cmd:$script_cmd"
run_script_colossus "$colossus" "$script_cmd"
echo "To setup passwordless SSH to host"
ssh-copy-id -f $colossus
echo "To make a SSH tunnel from drivefarm to host"
ps -ef | grep "ssh.*-L 20000" | awk '{print $2}' | xargs -r sudo kill -9
ssh -o StrictHostKeyChecking=no -fN -L 20000:$tegra_ip_address:22 $colossus
echo "To setup passwordless SSH to target"
ssh-copy-id -f -p 20000 root@127.0.0.1
echo "To make a SSH tunnel from drivefarm to target"
ssh -fN -p 20000 root@127.0.0.1
# It needs to be executed on the local PC.
# ssh -fN -L 50000:127.0.0.1:50000 ubuntu24
config_base_path="$TEGRA_TOP/kernel/nvidia-oot/drivers/media/platform/tegra/fuzz"
config_file="$config_base_path/syzkaller_config/configs"
if [ ! -f "$config_file" ]; then
echo "Error: Config file not found at $config_file"
return 1
fi
cp $config_file $SYZKALLER_DIR/syzkaller/bin/
echo "run syzkaller fuzzer"
cd $SYZKALLER_DIR/syzkaller/bin
./syz-manager -config=configs
}
# Call main function with all passed arguments
main "$@"

View File

@@ -0,0 +1,82 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#!/bin/bash
# @brief Display the help message
display_help() {
echo "Usage: syzkaller_host_setup.sh "
echo
echo "Arguments:"
echo " --target_ip IP address of the target device."
echo " --help Show this help message"
echo
echo "Examples:"
echo " $0 --target-ip 192.168.1.100"
}
# @brief send command to Tegra device
# @param $1 command to execute
# @return 0 success, 1 failure
send_command_tegra() {
echo "sshpass -p $TARGET_USERNAME ssh -oUserKnownHostsFile=/dev/null \
-oStrictHostKeyChecking=no ${TARGET_USERNAME}@${TARGET_IP} $1"
sshpass -p $TARGET_USERNAME ssh \
-oUserKnownHostsFile=/dev/null \
-oStrictHostKeyChecking=no \
${TARGET_USERNAME}@${TARGET_IP} "$1" || return 1
}
TARGET_USERNAME=nvidia
TARGET_ROOT=root
# Main function to handle component and cleaning logic
main() {
while [ "$#" -gt 0 ]; do
case $1 in
--target_ip)
TARGET_IP="$2"
shift 2
;;
--help)
display_help
return 0
;;
*)
echo "Invalid option: $1"
display_help
return 1
;;
esac
done
# create working directory
send_command_tegra "mkdir /tmp/syzkaller"
# # configure SSH
send_command_tegra "echo 'PermitRootLogin yes' | sudo tee -a /etc/ssh/sshd_config"
send_command_tegra "echo 'AllowTcpForwarding yes' | sudo tee -a /etc/ssh/sshd_config"
# set root password
send_command_tegra "echo 'root:root' | sudo chpasswd"
# clear dmesg and restart ssh
send_command_tegra "sudo dmesg --clear"
send_command_tegra "sudo systemctl restart ssh"
echo "Waiting for SSH to be ready..."
sleep 5
sshpass -p $TARGET_ROOT ssh-copy-id -f -o StrictHostKeyChecking=no ${TARGET_ROOT}@${TARGET_IP}
ssh -oUserKnownHostsFile=/dev/null -oStrictHostKeyChecking=no ${TARGET_ROOT}@${TARGET_IP} exit
if [ $? -eq 0 ]; then
echo "[SUCCESS] SSH passwordless configured"
else
echo "[ERROR] Configuration failed"
return 1
fi
echo "Tegra setup complete"
}
# Call main function with all passed arguments
main "$@"

View File

@@ -0,0 +1,115 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
{
# URL that will display information about the running syz-manager process (e.g. "localhost:50000").
"http": "127.0.0.1:50000",
# TCP address to serve RPC for fuzzer processes (optional).
"rpc": "127.0.0.1:50002",
# Number of parallel test processes inside of each VM.
# Allowed values are 1-32, recommended range is ~4-8, default value is 6.
# It should be chosen to saturate CPU inside of the VM and maximize number of test executions,
# but to not oversubscribe CPU and memory too severe to not cause OOMs and false hangs/stalls.
"procs": 1,
# Type of sandbox to use during fuzzing:
# "none": test under root;
# don't do anything special beyond resource sandboxing,
# gives the most coverage, default
"sandbox": "none",
# Location (on the host machine) of a root SSH identity to use for communicating with
# the target device.
"sshkey" : "/home/<user>/.ssh/id_ecdsa",
# Location of the syzkaller checkout, syz-manager will look
# for binaries in bin subdir (does not have to be syzkaller checkout as
# long as it preserves `bin` dir structure)
"syzkaller": "/home/<user>/syzkaller/syzkaller",
# Target OS/arch, e.g. "linux/arm64" or "linux/amd64/386" (amd64 OS with 386 test process).
"target": "linux/arm64",
# Reproduce, localize and minimize crashers (default: true).
"reproduce": false,
# Use KCOV coverage (default: true).
"cover": true,
# Experimental options.
"experimental": {
# Hash adjacent PCs to form fuzzing feedback signal, otherwise use PCs as signal (default: true).
"cover_edges": false
},
# For each prog in the corpus, remember the raw array of PCs obtained from the kernel.
# It can be useful for debugging syzkaller descriptions and syzkaller itself.
# Disabled by default as it slows down fuzzing.
"raw_cover": true,
# Type of virtual machine to use, e.g. "qemu", "gce", "android", "isolated", etc.
"type": "isolated",
# VM-type-specific parameters.
"vm": {
# target machines: (hostname|ip)(:port)
"targets" : [ "127.0.0.1:20000" ],
# use crashlogs from pstore
"pstore": false,
# directory to copy/run on target
"target_dir" : "/tmp/syzkaller",
# reboot target on repair
"target_reboot" : false
},
# Kernel source directory (if not set defaults to KernelObj).
"kernel_src": "/home/<user>/<repo-path>/kernel/kernel-oot",
# Directory with kernel object files (e.g. `vmlinux` for linux)
# (used for report symbolization, coverage reports and in tree modules finding, optional).
"kernel_obj": "/home/<user>/<repo-path>/out/embedded-linux-generic-debug-none/nvidia/kernel-oot/kernel-rt_patches/",
# Directories with out-of-tree kernel module object files for coverage report generation (optional).
# KernelObj is also scanned for in-tree kernel modules and does not need to be duplicated here.
# Note: the modules need to be unstripped and contain debug info.
"module_obj": [
"/home/<user>/<repo-path>/out/embedded-linux-generic-debug-none/nvidia/kernel-oot/kernel-rt_patches-nvidia-oot/nvidia-oot/drivers/media/platform/tegra"
],
# Location of a working directory for the syz-manager process. Outputs here include:
# - <workdir>/crashes/: crash output files
# - <workdir>/corpus.db: corpus with interesting programs
# - <workdir>/instance-x: per VM instance temporary files
"workdir":"/home/<user>/<repo-path>/workdir",
# List of syscalls to test (optional). For example:
# "enable_syscalls": [ "mmap", "openat$ashmem", "ioctl$ASHMEM*" ]
"enable_syscalls" : [
"openat$cam_fsync",
"ioctl$CAM_FSYNC_*",
"openat$cdi_mgr",
"ioctl$CDI_MGR_IOCTL_*",
"openat$cdi_dev",
"ioctl$CDI_DEV_IOCTL_*",
"syz_open_dev$isp_channel",
"ioctl$ISP_CAPTURE_*",
"syz_open_dev$capture_vi_channel",
"ioctl$VI_CAPTURE_*"
],
# List of syscalls that should not be mutated by the fuzzer (optional).
"no_mutate_syscalls" : [
"ioctl$VI_CAPTURE_SET_CONFIG",
"ioctl$CDI_MGR_IOCTL_INTR_CONFIG"
],
# List of system calls that should be treated as disabled (optional).
"disable_syscalls" : [
"ioctl$CDI_MGR_IOCTL_DISABLE_DES_POWER"
]
}