huangcm
2025-02-24 69ed55dec4b2116a19e4cca4393cbc014fce5fb2
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
#!/bin/bash
# Copyright 2016 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.
 
# create-gce-image.sh creates a minimal bootable image suitable for syzkaller/GCE.
# The image will have password-less root login with a key stored in key file.
#
# Prerequisites:
# - you need a user-space system, a basic Debian system can be created with:
#   sudo debootstrap --include=openssh-server,curl,tar,gcc,libc6-dev,time,strace,sudo,less,psmisc,selinux-utils,policycoreutils,checkpolicy,selinux-policy-default stable debian
# - you need kernel to use with image (e.g. arch/x86/boot/bzImage)
#   note: kernel modules are not supported
# - you need grub:
#   sudo apt-get install grub-efi
#
# Usage:
#   ./create-gce-image.sh /dir/with/user/space/system /path/to/bzImage
#
# SYZ_VM_TYPE env var controls type of target test machine. Supported values:
# - qemu (default, uses /dev/loop)
# - gce (uses /dev/nbd0)
#   Needs nbd support in kernel and qemu-utils (qemu-nbd) installed.
#
# If SYZ_SYSCTL_FILE env var is set and points to a file,
# then its contents will be appended to the image /etc/sysctl.conf.
# If SYZ_CMDLINE_FILE env var is set and points to a file,
# then its contents will be appended to the kernel command line.
# If MKE2FS_CONFIG env var is set, it will affect invoked mkfs.ext4.
#
# Outputs are (in the current dir):
# - disk.raw: the image
# - key: root ssh key
# The script can also create/delete temp files in the current dir.
#
# The image then needs to be compressed with:
#   tar -Sczf disk.tar.gz disk.raw
# and uploaded to GCS with:
#   gsutil cp disk.tar.gz gs://my-images/image.tar.gz
# finally, my-images/image.tar.gz can be used to create a new GCE image.
#
# The image can be tested locally with e.g.:
#   qemu-system-x86_64 -hda disk.raw -net user,host=10.0.2.10,hostfwd=tcp::10022-:22 \
#       -net nic -enable-kvm -m 2G -display none -serial stdio
# once the kernel boots, you can ssh into it with:
#   ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentitiesOnly=yes \
#       -p 10022 -i key root@localhost
 
set -eux
 
CLEANUP=""
trap 'eval " $CLEANUP"' EXIT
 
if [ ! -e $1/sbin/init ]; then
   echo "usage: create-gce-image.sh /dir/with/user/space/system /path/to/bzImage"
   exit 1
fi
 
if [ "$(basename $2)" != "bzImage" ]; then
   echo "usage: create-gce-image.sh /dir/with/user/space/system /path/to/bzImage"
   exit 1
fi
 
SYZ_VM_TYPE="${SYZ_VM_TYPE:-qemu}"
if [ "$SYZ_VM_TYPE" == "qemu" ]; then
   :
elif [ "$SYZ_VM_TYPE" == "gce" ]; then
   :
else
   echo "SYZ_VM_TYPE has unsupported value $SYZ_VM_TYPE"
   exit 1
fi
 
# Clean up after previous unsuccessful run.
sudo umount disk.mnt || true
if [ "$SYZ_VM_TYPE" == "qemu" ]; then
   :
elif [ "$SYZ_VM_TYPE" == "gce" ]; then
   sudo modprobe nbd
   sudo qemu-nbd -d /dev/nbd0 || true
fi
rm -rf disk.mnt disk.raw || true
 
fallocate -l 2G disk.raw
if [ "$SYZ_VM_TYPE" == "qemu" ]; then
   DISKDEV="$(sudo losetup -f --show -P disk.raw)"
   CLEANUP="sudo losetup -d $DISKDEV; $CLEANUP"
elif [ "$SYZ_VM_TYPE" == "gce" ]; then
   DISKDEV="/dev/nbd0"
   sudo qemu-nbd -c $DISKDEV --format=raw disk.raw
   CLEANUP="sudo qemu-nbd -d $DISKDEV; $CLEANUP"
fi
echo -en "o\nn\np\n1\n\n\na\nw\n" | sudo fdisk $DISKDEV
PARTDEV=$DISKDEV"p1"
until [ -e $PARTDEV ]; do sleep 1; done
sudo -E mkfs.ext4 $PARTDEV
mkdir -p disk.mnt
CLEANUP="rm -rf disk.mnt; $CLEANUP"
sudo mount $PARTDEV disk.mnt
CLEANUP="sudo umount disk.mnt; $CLEANUP"
sudo cp -a $1/. disk.mnt/.
sudo cp $2 disk.mnt/vmlinuz
sudo sed -i "/^root/ { s/:x:/::/ }" disk.mnt/etc/passwd
echo "T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100" | sudo tee -a disk.mnt/etc/inittab
echo -en "auto lo\niface lo inet loopback\nauto eth0\niface eth0 inet dhcp\n" | sudo tee disk.mnt/etc/network/interfaces
echo "debugfs /sys/kernel/debug debugfs defaults 0 0" | sudo tee -a disk.mnt/etc/fstab
echo 'binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0' | sudo tee -a disk.mnt/etc/fstab
for i in {0..31}; do
   echo "KERNEL==\"binder$i\", NAME=\"binder$i\", MODE=\"0666\"" | \
       sudo tee -a disk.mnt/etc/udev/50-binder.rules
done
# We disable selinux for now because the default policy on wheezy prevents
# mounting of cgroup2 (and stretch we don't know how to configure yet).
echo 'SELINUX=disabled' | sudo tee disk.mnt/etc/selinux/config
 
# sysctls
echo "kernel.printk = 7 4 1 3" | sudo tee -a disk.mnt/etc/sysctl.conf
echo "debug.exception-trace = 0" | sudo tee -a disk.mnt/etc/sysctl.conf
SYZ_SYSCTL_FILE="${SYZ_SYSCTL_FILE:-}"
if [ "$SYZ_SYSCTL_FILE" != "" ]; then
   cat $SYZ_SYSCTL_FILE | sudo tee -a disk.mnt/etc/sysctl.conf
fi
 
echo -en "127.0.0.1\tlocalhost\n" | sudo tee disk.mnt/etc/hosts
echo "nameserver 8.8.8.8" | sudo tee -a disk.mnt/etc/resolve.conf
echo "ClientAliveInterval 420" | sudo tee -a disk.mnt/etc/ssh/sshd_config
echo "syzkaller" | sudo tee disk.mnt/etc/hostname
rm -f key key.pub
ssh-keygen -f key -t rsa -N ""
sudo mkdir -p disk.mnt/root/.ssh
sudo cp key.pub disk.mnt/root/.ssh/authorized_keys
sudo chown root disk.mnt/root/.ssh/authorized_keys
sudo mkdir -p disk.mnt/boot/grub
 
CMDLINE=""
SYZ_CMDLINE_FILE="${SYZ_CMDLINE_FILE:-}"
if [ "$SYZ_CMDLINE_FILE" != "" ]; then
   CMDLINE=$(awk '{printf("%s ", $0)}' $SYZ_CMDLINE_FILE)
fi
 
cat << EOF | sudo tee disk.mnt/boot/grub/grub.cfg
terminal_input console
terminal_output console
set timeout=0
# vsyscall=native: required to run x86_64 executables on android kernels
#   (for some reason they disable VDSO by default)
# rodata=n: mark_rodata_ro becomes very slow with KASAN (lots of PGDs)
# panic=86400: prevents kernel from rebooting so that we don't get reboot output in all crash reports
# debug is not set as it produces too much output
menuentry 'linux' --class gnu-linux --class gnu --class os {
   insmod vbe
   insmod vga
   insmod video_bochs
   insmod video_cirrus
   insmod gzio
   insmod part_msdos
   insmod ext2
   set root='(hd0,1)'
   linux /vmlinuz root=/dev/sda1 console=ttyS0 earlyprintk=serial vsyscall=native rodata=n ftrace_dump_on_oops=orig_cpu oops=panic panic_on_warn=1 nmi_watchdog=panic panic=86400 $CMDLINE
}
EOF
sudo grub-install --target=i386-pc --boot-directory=disk.mnt/boot --no-floppy $DISKDEV