| # 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}'] |