github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/docs/setup_syzbot.md (about)

     1  # How to set up syzbot
     2  
     3  This doc will be useful to you:
     4  - should you wish to hack on user interface bits like the dashboard / mailing list integration or
     5  - should you wish to continuously run a separate syzbot dashboard for your own kernels
     6  
     7  Note: For most development purposes you don't need a full syzbot setup. The meat of syzkaller is really located in syz-manager, syz-fuzzer and syz-executor. You can run syz-manager directly which is usually what you will want to do during fuzzer development. [See this documentation for syz-manager setup instructions](setup.md).
     8  
     9  This doc assumes that you:
    10  - have a GCP account and billing setup
    11  - created a GCP project for running syzbot in
    12  - are running a reasonably modern linux distro
    13  - locally installed `gcloud`, `ssh`, `go` and `build-essential`
    14  - may need to install `google-cloud-sdk-app-engine-go` for the GAE deployment to work
    15  - ran `gcloud auth login` to run authenticated gcloud commands
    16  - read [go/syzbot-setup](https://goto.google.com/syzbot-setup) if you are a Googler
    17  
    18  While most syzkaller bits happily run on various operating systems, the syzbot dashboard does not. The dashboard is a Google App Engine or GAE project. GAE allows developers to develop web applications without needing to worry about the underlying servers. Instead developers just push their code and GAE takes care of web servers, load balancers and more. Hence this document is more Google Cloud focused than the rest of our documentation.
    19  
    20  We will also deploy a syz-ci instance. syz-ci keeps track of the syzkaller and kernel repositories and continuously rebuilds the kernel under test, itself and other syzkaller components when new commits land in the upstream repositories. syz-ci also takes care of (re)starting syz-manager instances, which in turn (re)start VMs fuzzing the target kernel. For simplicity we will run everything in this doc on GCP even though syz-ci could run elsewhere.
    21  
    22  ![Overall picture of syzbot setup](/docs/syzbot_architecture.png)
    23  
    24  
    25  ## Deploying Syz-ci
    26  
    27  [local] First prepare an initial syz-ci build locally (later syz-ci rebuilds itself) and a rootfs:
    28  
    29  ```sh
    30  # Most syzkaller components can be build even outside of the GOPATH, however
    31  # the syzbot app engine deployment only works from the GOPATH right now..
    32  export GOOGLE_GO=$HOME/gopath/src/github.com/google/
    33  mkdir -p $GOOGLE_GO
    34  git clone https://github.com/google/syzkaller.git
    35  mv syzkaller $GOOGLE_GO/
    36  cd $GOOGLE_GO/syzkaller
    37  make ci
    38  
    39  cd ~/repos
    40  git clone git://git.buildroot.net/buildroot
    41  cd buildroot
    42  $GOOGLE_GO/syzkaller/tools/create-buildroot-image.sh
    43  ```
    44  
    45  [local] Enable various services in the project, create a VM, storage bucket, scp assets and login:
    46  
    47  ```sh
    48  export PROJECT='your-gcp-project'
    49  export CI_HOSTNAME='ci-linux'
    50  export GOOGLE_GO=$HOME/gopath/src/github.com/google/
    51  
    52  gcloud services enable compute.googleapis.com --project="$PROJECT"
    53  gcloud compute instances create "$CI_HOSTNAME" --image-family=debian-11 --image-project=debian-cloud --machine-type=e2-standard-16 --zone=us-central1-a --boot-disk-size=250 --scopes=cloud-platform --project="$PROJECT"
    54  
    55  # Enabling compute.googleapis.com created a service account. We allow the syz-ci VM
    56  # to assume the permissions of that service account. As syz-ci needs query / create / delete
    57  # other VMs in the project, we need to give the new service account various permissions
    58  gcloud services enable iam.googleapis.com --project $PROJECT
    59  SERVICE_ACCOUNT=`gcloud iam service-accounts list --filter 'displayName:Compute Engine default service account' --format='value(email)' --project $PROJECT`
    60  gcloud projects add-iam-policy-binding "$PROJECT" --role="roles/editor" --member="serviceAccount:$SERVICE_ACCOUNT" --quiet
    61  
    62  gcloud services enable storage-api.googleapis.com --project="$PROJECT"
    63  gsutil mb -p "$PROJECT" "gs://$PROJECT-bucket"
    64  
    65  gcloud services enable cloudbuild.googleapis.com --project="$PROJECT"
    66  
    67  # We need to wait a bit for the VM to become accessible. Let's just…
    68  sleep 10
    69  
    70  # Copy in buildroot
    71  gcloud compute scp --zone us-central1-a --project="$PROJECT" ~/repos/buildroot/output/images/disk.img "$CI_HOSTNAME":~/
    72  
    73  # Copy in syz-ci binary
    74  gcloud compute scp --zone us-central1-a --project="$PROJECT" $GOOGLE_GO/syzkaller/bin/syz-ci "$CI_HOSTNAME":~/
    75  
    76  # Prepare syz-ci config
    77  cat <<EOF > /tmp/config.ci
    78  {
    79          "name": "$CI_HOSTNAME",
    80          "http": ":80",
    81          "manager_port_start": 50010,
    82          "syzkaller_repo": "https://github.com/google/syzkaller.git",
    83          "managers": [
    84                  {
    85                          "repo": "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git",
    86                          "repo_alias": "upstream",
    87                          "userspace": "disk.img",
    88                          "kernel_config": "config/linux/upstream-apparmor-kasan.config",
    89                          "manager_config": {
    90                                  "name": "ci-upstream-kasan-gce",
    91                                  "target": "linux/amd64",
    92                                  "procs": 6,
    93                                  "type": "gce",
    94                                  "vm": {
    95                                          "count": 5,
    96                                          "machine_type": "e2-standard-2",
    97                                          "gcs_path": "$PROJECT-bucket/disks"
    98                                  },
    99                                  "disable_syscalls": [ "perf_event_open*" ]
   100                          }
   101                  }
   102          ]
   103  }
   104  EOF
   105  gcloud compute scp --zone us-central1-a --project="$PROJECT" /tmp/config.ci "$CI_HOSTNAME":~/
   106  
   107  # ssh into the syz-ci machine. Will be required in the next step.
   108  gcloud compute ssh "$CI_HOSTNAME" --zone us-central1-a --project="$PROJECT"
   109  ```
   110  
   111  [syz-ci] Let's install and configure the syz-ci service on our syz-ci VM:
   112  
   113  ```sh
   114  sudo apt install -y wget git docker.io build-essential
   115  
   116  # We need a recent go version, not yet available in debian 11
   117  wget 'https://go.dev/dl/go1.18.linux-amd64.tar.gz'
   118  sudo tar -zxvf go1.18.linux-amd64.tar.gz -C /usr/local/
   119  echo "export PATH=/usr/local/go/bin:${PATH}" | sudo tee /etc/profile.d/go.sh
   120  source /etc/profile.d/go.sh
   121  
   122  sudo mkdir /syzkaller
   123  sudo mv ~/syz-ci /syzkaller/
   124  sudo mv ~/disk.img /syzkaller/
   125  sudo mv ~/config.ci /syzkaller/
   126  sudo ln -s /syzkaller/gopath/src/github.com/google/syzkaller/dashboard/config /syzkaller/config
   127  
   128  # Pull docker container used by syz-ci for building the linux kernel
   129  # We also do this on systemd start, but the first pull might take a long time,
   130  # resulting in startup timeouts if we don't pull here once first.
   131  sudo /usr/bin/docker pull gcr.io/syzkaller/syzbot
   132  
   133  cat <<EOF > /tmp/syz-ci.service
   134  [Unit]
   135  Description=syz-ci
   136  Requires=docker.service
   137  After=docker.service
   138  
   139  [Service]
   140  Type=simple
   141  User=root
   142  ExecStartPre=-/usr/bin/docker rm --force syz-ci
   143  ExecStartPre=/usr/bin/docker pull gcr.io/syzkaller/syzbot
   144  ExecStartPre=/usr/bin/docker image prune --filter="dangling=true" -f
   145  # --privileged is required for pkg/osutil sandboxing,
   146  # otherwise unshare syscall fails with EPERM.
   147  # Consider giving it finer-grained permissions,
   148  # or maybe running an unpriv container is better than
   149  # our sandboxing (?) then we could instead add
   150  # --env SYZ_DISABLE_SANDBOXING=yes.
   151  # However, we will also need to build GCE images,
   152  # which requires access to loop devices, mount, etc.
   153  # Proxying /dev is required for image build,
   154  # otherwise partition devices (/dev/loop0p1)
   155  # don't appear inside of the container.
   156  # Host network is required because syz-manager inside
   157  # of the container will create GCE VMs which will
   158  # connect back to the syz-manager using this VM's IP
   159  # and syz-manager port generated inside of the container.
   160  # Without host networking the port is not open on the machine.
   161  ExecStart=/usr/bin/docker run --rm --name syz-ci \
   162          --privileged \
   163          --network host \
   164          --volume /var/run/docker.sock:/var/run/docker.sock \
   165          --volume /syzkaller:/syzkaller \
   166          --volume /dev:/dev \
   167          --workdir /syzkaller \
   168          --env HOME=/syzkaller \
   169          gcr.io/syzkaller/syzbot \
   170          /syzkaller/syz-ci -config config.ci
   171  ExecStop=/usr/bin/docker stop -t 600 syz-ci
   172  Restart=always
   173  RestartSec=10
   174  KillMode=mixed
   175  
   176  [Install]
   177  WantedBy=multi-user.target
   178  EOF
   179  sudo mv /tmp/syz-ci.service /etc/systemd/system/
   180  sudo systemctl daemon-reload
   181  sudo systemctl restart syz-ci
   182  sudo systemctl enable syz-ci
   183  sudo journalctl -fu syz-ci
   184  ```
   185  
   186  Check the syc-ci journal logs at this point to see if the service comes up fine. Now syz-ci needs to do a bunch of time consuming stuff like building the kernel under test, so be patient.
   187  
   188  If you want to hack on syz-ci you can stop here. Otherwise the next section builds on the syz-ci instructions and extends the setup with a dashboard deployment.
   189  
   190  ## Deploying Syzbot dashboard
   191  
   192  [locally] deploy the dashboard to Google App Engine:
   193  
   194  ```sh
   195  export PROJECT='your-gcp-project'
   196  export CI_HOSTNAME='ci-linux'
   197  # A random string used by the syz-ci to authenticate against the dashboard
   198  export CI_KEY='fill-with-random-ci-key-string'
   199  # A random string used by the syz-manager to authenticate against the dashboard
   200  export MANAGER_KEY='fill-with-random-manager-key-string'
   201  # A random string used for hashing, can be anything, but once fixed it can't
   202  # be changed as it becomes a part of persistent bug identifiers.
   203  export KEY='fill-with-random-key-string'
   204  # This email will receive all of the crashes found by your instance.
   205  export EMAIL='syzkaller@example.com'
   206  
   207  gcloud app create --region us-central --project $PROJECT --quiet
   208  
   209  # Grant the app engine service account access to Datastore
   210  SERVICE_ACCOUNT=`gcloud iam service-accounts list --filter 'displayName:App Engine default service account' --format='value(email)' --project $PROJECT`
   211  gcloud projects add-iam-policy-binding "$PROJECT" \
   212      --member="serviceAccount:$SERVICE_ACCOUNT" \
   213      --role="roles/editor"
   214  gcloud projects add-iam-policy-binding "$PROJECT" \
   215      --member="serviceAccount:$SERVICE_ACCOUNT" \
   216      --role="roles/datastore.owner"
   217  
   218  GOOGLE_GO=$HOME/gopath/src/github.com/google/
   219  cd $GOOGLE_GO/syzkaller
   220  
   221  # Enable some crons for sending emails and such
   222  gcloud services enable cloudscheduler.googleapis.com --project $PROJECT
   223  gcloud app deploy ./dashboard/app/cron.yaml --project $PROJECT --quiet
   224  
   225  # Create required Datastore indexes. Requires a few minutes to
   226  # generate before they (and hence syzbot) become usable
   227  gcloud datastore indexes create ./dashboard/app/index.yaml --project $PROJECT --quiet
   228  
   229  cat <<EOF > ./dashboard/app/config_not_prod.go
   230  package main
   231  import (
   232          "time"
   233          "github.com/google/syzkaller/dashboard/dashapi"
   234  )
   235  const (
   236          reportingUpstream    = "upstream"
   237          moderationDailyLimit = 30
   238          internalDailyLimit   = 30
   239          reportingDelay       = 0
   240          domainLinux          = "linux"
   241  )
   242  func init() {
   243          checkConfig(prodConfig)
   244          mainConfig = prodConfig
   245  }
   246  var prodConfig = &GlobalConfig{
   247          AccessLevel:         AccessPublic,
   248          AuthDomain:          "@google.com",
   249          CoverPath:           "https://storage.googleapis.com/syzkaller/cover/",
   250          Clients: map[string]string{
   251                  "$CI_HOSTNAME":     "$CI_KEY",
   252          },
   253          Obsoleting: ObsoletingConfig{
   254                  MinPeriod:         90 * 24 * time.Hour,
   255                  MaxPeriod:         120 * 24 * time.Hour,
   256                  NonFinalMinPeriod: 60 * 24 * time.Hour,
   257                  NonFinalMaxPeriod: 90 * 24 * time.Hour,
   258          },
   259          DefaultNamespace: "upstream",
   260          Namespaces: map[string]*Config{
   261                  "upstream": {
   262                          AccessLevel:      AccessPublic,
   263                          DisplayTitle:     "Linux",
   264                          SimilarityDomain: domainLinux,
   265                          Key:              "$KEY",
   266                          Clients: map[string]string{
   267                                  "ci-upstream-kasan-gce":  "$MANAGER_KEY",
   268                          },
   269                          Repos: []KernelRepo{
   270                                  {
   271                                          URL:               "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git",
   272                                          Branch:            "master",
   273                                          Alias:             "upstream",
   274                                          ReportingPriority: 9,
   275                                  },
   276                          },
   277                          MailWithoutReport: true,
   278                          ReportingDelay:    reportingDelay,
   279                          WaitForRepro:      0,
   280                          Managers: map[string]ConfigManager{},
   281                          Reporting: []Reporting{
   282                                  {
   283                                          AccessLevel: AccessPublic,
   284                                          Name:        reportingUpstream,
   285                                          DailyLimit:  30,
   286                                          Config: &EmailConfig{
   287                                                  Email:              "$EMAIL",
   288                                                  SubjectPrefix:      "[syzbot-test]",
   289                                                  MailMaintainers:    false,
   290                                          },
   291                                  },
   292                          },
   293                          TransformCrash: func(build *Build, crash *dashapi.Crash) bool {
   294                                  return true
   295                          },
   296                          NeedRepro: func(bug *Bug) bool {
   297                                  return true
   298                          },
   299                  },
   300          },
   301  }
   302  EOF
   303  
   304  # Deploy the actual dashboard GAE application
   305  GOPATH=~/gopath GO111MODULE=off gcloud beta app deploy ./dashboard/app/app.yaml --project "$PROJECT" --quiet
   306  ```
   307  
   308  ### Integrating Syz-ci with syzbot
   309  
   310  [locally] Prepare config and login to syz-ci VM:
   311  
   312  ```sh
   313  export PROJECT='your-gcp-project'
   314  export CI_HOSTNAME='ci-linux'
   315  export CI_KEY='fill-with-random-ci-key-string'
   316  export MANAGER_KEY='fill-with-random-manager-key-string'
   317  export DASHBOARD_FQDN=`gcloud app describe --project $PROJECT --format 'value(defaultHostname)'`
   318  
   319  cat <<EOF > /tmp/config.ci
   320  {
   321          "name": "$CI_HOSTNAME",
   322          "http": ":80",
   323          "manager_port_start": 50010,
   324          "dashboard_addr": "https://$DASHBOARD_FQDN",
   325          "dashboard_client": "$CI_HOSTNAME",
   326          "dashboard_key": "$CI_KEY",
   327          "syzkaller_repo": "https://github.com/google/syzkaller.git",
   328          "managers": [
   329                  {
   330                          "repo": "git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git",
   331                          "repo_alias": "upstream",
   332                          "dashboard_client": "ci-upstream-kasan-gce",
   333                          "dashboard_key": "$MANAGER_KEY",
   334                          "userspace": "disk.img",
   335                          "kernel_config": "config/linux/upstream-apparmor-kasan.config",
   336                          "manager_config": {
   337                                  "name": "ci-upstream",
   338                                  "target": "linux/amd64",
   339                                  "procs": 6,
   340                                  "type": "gce",
   341                                  "vm": {
   342                                          "count": 5,
   343                                          "machine_type": "e2-standard-2",
   344                                          "gcs_path": "$PROJECT-bucket/disks"
   345                                  },
   346                                  "disable_syscalls": [ "perf_event_open*" ]
   347                          }
   348                  }
   349          ]
   350  }
   351  EOF
   352  gcloud compute scp --zone us-central1-a --project="$PROJECT" /tmp/config.ci "$CI_HOSTNAME":~/
   353  
   354  gcloud compute ssh "$CI_HOSTNAME" --zone us-central1-a --project="$PROJECT"
   355  ```
   356  
   357  [syz-ci] Reconfigure syz-ci to start sending results to the dashboard:
   358  
   359  ```sh
   360  sudo mv ~/config.ci /syzkaller/
   361  sudo systemctl restart syz-ci
   362  sudo journalctl -fu syz-ci
   363  ```
   364  
   365  [locally] Open the dashboard in your browser:
   366  ```
   367  gcloud app browse --project=$PROJECT
   368  ```
   369  Once syzkaller finds the first crashes they should show up here. This might take a while.