aboutsummaryrefslogtreecommitdiff
path: root/infra/cifuzz/docker.py
blob: 935773d925275bba77f2b5ca6c154d6bb3c6d12f (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
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for dealing with docker."""
import logging
import os
import sys

# pylint: disable=wrong-import-position,import-error
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import constants
import utils

BASE_BUILDER_TAG = 'gcr.io/oss-fuzz-base/base-builder'
PROJECT_TAG_PREFIX = 'gcr.io/oss-fuzz/'

# Default fuzz configuration.
_DEFAULT_DOCKER_RUN_ARGS = [
    '--cap-add', 'SYS_PTRACE', '-e',
    'FUZZING_ENGINE=' + constants.DEFAULT_ENGINE, '-e',
    'ARCHITECTURE=' + constants.DEFAULT_ARCHITECTURE, '-e', 'CIFUZZ=True'
]

EXTERNAL_PROJECT_IMAGE = 'external-project'

_DEFAULT_DOCKER_RUN_COMMAND = [
    'docker',
    'run',
    '--rm',
    '--privileged',
]


def get_docker_env_vars(env_mapping):
  """Returns a list of docker arguments that sets each key in |env_mapping| as
  an env var and the value of that key in |env_mapping| as the value."""
  env_var_args = []
  for env_var, env_var_val in env_mapping.items():
    env_var_args.extend(['-e', f'{env_var}={env_var_val}'])
  return env_var_args


def get_project_image_name(project):
  """Returns the name of the project builder image for |project_name|."""
  # TODO(ochang): We may need unique names to support parallel fuzzing.
  if project:
    return PROJECT_TAG_PREFIX + project

  return EXTERNAL_PROJECT_IMAGE


def delete_images(images):
  """Deletes |images|."""
  command = ['docker', 'rmi', '-f'] + images
  utils.execute(command)
  utils.execute(['docker', 'builder', 'prune', '-f'])


def get_base_docker_run_args(workspace,
                             sanitizer=constants.DEFAULT_SANITIZER,
                             language=constants.DEFAULT_LANGUAGE,
                             docker_in_docker=False):
  """Returns arguments that should be passed to every invocation of 'docker
  run'."""
  docker_args = _DEFAULT_DOCKER_RUN_ARGS.copy()
  env_mapping = {
      'SANITIZER': sanitizer,
      'FUZZING_LANGUAGE': language,
      'OUT': workspace.out
  }
  docker_args += get_docker_env_vars(env_mapping)
  docker_container = utils.get_container_name()
  logging.info('Docker container: %s.', docker_container)
  if docker_container and not docker_in_docker:
    # Don't map specific volumes if in a docker container, it breaks when
    # running a sibling container.
    docker_args += ['--volumes-from', docker_container]
  else:
    docker_args += _get_args_mapping_host_path_to_container(workspace.workspace)
  return docker_args, docker_container


def get_base_docker_run_command(workspace,
                                sanitizer=constants.DEFAULT_SANITIZER,
                                language=constants.DEFAULT_LANGUAGE,
                                docker_in_docker=False):
  """Returns part of the command that should be used everytime 'docker run' is
  invoked."""
  docker_args, docker_container = get_base_docker_run_args(
      workspace, sanitizer, language, docker_in_docker=docker_in_docker)
  command = _DEFAULT_DOCKER_RUN_COMMAND.copy() + docker_args
  return command, docker_container


def _get_args_mapping_host_path_to_container(host_path, container_path=None):
  """Get arguments to docker run that will map |host_path| a path on the host to
  a path in the container. If |container_path| is specified, that path is mapped
  to. If not, then |host_path| is mapped to itself in the container."""
  # WARNING: Do not use this function when running in production (and
  # --volumes-from) is used for mapping volumes. It will break production.
  container_path = host_path if container_path is None else container_path
  return ['-v', f'{host_path}:{container_path}']