diff --git a/tests/ci/README.md b/tests/ci/README.md index 48bc2d75..7a866b6f 100644 --- a/tests/ci/README.md +++ b/tests/ci/README.md @@ -61,3 +61,12 @@ CI Tool|C Compiler|Java Compiler|CPU platform|OS|Dimensions ------------ | -------------| -------------| -------------|-------------|------------- CodeBuild|gcc 7|corretto 11|x86-64|Ubuntu 20.04|both FIPS/non-FIPS CodeBuild|gcc 7|corretto 11|aarch|Ubuntu 20.04|both FIPS/non-FIPS + + +### Cryptofuzz + +Each change is built and tested with [Cryptofuzz](https://github.com/guidovranken/cryptofuzz) for an hour. A seed corpus +is included in tests/docker_images/cryptofuzz_data.zip. As new inputs are found they are saved in a shared corpus across +runs in AWS EFS. Cryptofuzz is built with 2 modules: +* ACCP +* CryptoPP diff --git a/tests/ci/cdk/app.py b/tests/ci/cdk/app.py index fd1f3011..33f66e92 100644 --- a/tests/ci/cdk/app.py +++ b/tests/ci/cdk/app.py @@ -6,6 +6,7 @@ from aws_cdk import core from cdk.accp_github_ci_stack import ACCPGitHubCIStack +from cdk.accp_github_fuzz_ci_stack import ACCPGitHubFuzzCIStack from cdk.linux_docker_image_batch_build_stack import LinuxDockerImageBatchBuildStack from cdk.windows_docker_image_build_stack import WindowsDockerImageBuildStack from cdk.ecr_stack import EcrStack @@ -33,6 +34,8 @@ ACCPGitHubCIStack(app, "accp-ci-pr-integration-linux-x86", LINUX_ECR_REPO, x86_build_spec_file, env=env) arm_build_spec_file = "./cdk/codebuild/pr_integration_linux_arm_omnibus.yaml" ACCPGitHubCIStack(app, "accp-ci-pr-integration-linux-arm", LINUX_ECR_REPO, arm_build_spec_file, env=env) +fuzz_build_spec_file = "cdk/codebuild/pr_fuzzing_omnibus.yaml" +ACCPGitHubFuzzCIStack(app, "accp-ci-fuzzing", LINUX_ECR_REPO, fuzz_build_spec_file, env=env) # TODO: Renable the code below when ACCP adds support for Windows. # Issue: https://github.com/corretto/amazon-corretto-crypto-provider/issues/48 diff --git a/tests/ci/cdk/cdk/accp_github_fuzz_ci_stack.py b/tests/ci/cdk/cdk/accp_github_fuzz_ci_stack.py index d99cc453..673213d0 100644 --- a/tests/ci/cdk/cdk/accp_github_fuzz_ci_stack.py +++ b/tests/ci/cdk/cdk/accp_github_fuzz_ci_stack.py @@ -1,23 +1,20 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 OR ISC -from aws_cdk import Duration, Size, Stack, aws_codebuild as codebuild, aws_iam as iam, aws_ec2 as ec2, aws_efs as efs -from constructs import Construct -from cdk.components import PruneStaleGitHubBuilds +from aws_cdk import core, aws_codebuild as codebuild, aws_iam as iam, aws_ec2 as ec2, aws_efs as efs from util.ecr_util import ecr_arn -from util.iam_policies import code_build_batch_policy_in_json, \ - code_build_publish_metrics_in_json -from util.metadata import AWS_ACCOUNT, AWS_REGION, GITHUB_PUSH_CI_BRANCH_TARGETS, GITHUB_REPO_OWNER, GITHUB_REPO_NAME -from util.build_spec_loader import BuildSpecLoader +from util.iam_policies import code_build_batch_policy_in_json +from util.metadata import AWS_ACCOUNT, AWS_REGION, GITHUB_BRANCH_EXCLUDE_CI, GITHUB_REPO_OWNER, GITHUB_REPO_NAME +from util.yml_loader import YmlLoader - -class AwsLcGitHubFuzzCIStack(Stack): - """Define a stack used to batch execute AWS-LC tests in GitHub.""" +class ACCPGitHubFuzzCIStack(core.Stack): + """Define a stack used to batch execute ACCP tests in GitHub.""" def __init__(self, - scope: Construct, + scope: core.Construct, id: str, + ecr_repo_name: str, spec_file_path: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) @@ -27,13 +24,14 @@ def __init__(self, owner=GITHUB_REPO_OWNER, repo=GITHUB_REPO_NAME, webhook=True, + fetch_submodules=True, webhook_filters=[ codebuild.FilterGroup.in_event_of( + codebuild.EventAction.PULL_REQUEST_MERGED, codebuild.EventAction.PULL_REQUEST_CREATED, codebuild.EventAction.PULL_REQUEST_UPDATED, - codebuild.EventAction.PULL_REQUEST_REOPENED), - codebuild.FilterGroup.in_event_of(codebuild.EventAction.PUSH).and_branch_is( - GITHUB_PUSH_CI_BRANCH_TARGETS), + codebuild.EventAction.PULL_REQUEST_REOPENED) + .and_base_branch_is_not(GITHUB_BRANCH_EXCLUDE_CI) ], webhook_triggers_batch_build=True) @@ -41,9 +39,7 @@ def __init__(self, code_build_batch_policy = iam.PolicyDocument.from_json( code_build_batch_policy_in_json([id]) ) - fuzz_policy = iam.PolicyDocument.from_json(code_build_publish_metrics_in_json()) - inline_policies = {"code_build_batch_policy": code_build_batch_policy, - "fuzz_policy": fuzz_policy} + inline_policies = {"code_build_batch_policy": code_build_batch_policy} role = iam.Role(scope=self, id="{}-role".format(id), assumed_by=iam.ServicePrincipal("codebuild.amazonaws.com"), @@ -51,7 +47,7 @@ def __init__(self, # Create the VPC for EFS and CodeBuild public_subnet = ec2.SubnetConfiguration(name="PublicFuzzingSubnet", subnet_type=ec2.SubnetType.PUBLIC) - private_subnet = ec2.SubnetConfiguration(name="PrivateFuzzingSubnet", subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS) + private_subnet = ec2.SubnetConfiguration(name="PrivateFuzzingSubnet", subnet_type=ec2.SubnetType.PRIVATE) # Create a VPC with a single public and private subnet in a single AZ. This is to avoid the elastic IP limit # being used up by a bunch of idle NAT gateways @@ -73,7 +69,7 @@ def __init__(self, description="Allow all traffic inside security group" ) - efs_subnet_selection = ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS) + efs_subnet_selection = ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE) # Create the EFS to store the corpus and logs. EFS allows new filesystems to burst to 100 MB/s for the first 2 # TB of data read/written, after that the rate is limited based on the size of the filesystem. As of late @@ -86,7 +82,7 @@ def __init__(self, fuzz_filesystem = efs.FileSystem( scope=self, id="{}-FuzzingEFS".format(id), - file_system_name="AWS-LC-Fuzz-Corpus", + file_system_name="ACCP-Fuzz-Corpus", enable_automatic_backups=True, encrypted=True, security_group=build_security_group, @@ -94,9 +90,19 @@ def __init__(self, vpc_subnets=efs_subnet_selection, performance_mode=efs.PerformanceMode.GENERAL_PURPOSE, throughput_mode=efs.ThroughputMode.PROVISIONED, - provisioned_throughput_per_second=Size.mebibytes(100), + provisioned_throughput_per_second=core.Size.mebibytes(100), ) + placeholder_map = {"ECR_REPO_PLACEHOLDER": ecr_arn(ecr_repo_name)} + build_spec_content = YmlLoader.load(spec_file_path, placeholder_map) + + # The EFS identifier needs to match tests/ci/common_fuzz.sh, CodeBuild defines an environment variable named + # codebuild_$identifier. + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projectfilesystemlocation.html + efs_location = codebuild.FileSystemLocation.efs( + identifier="fuzzing_root", + location="%s.efs.%s.amazonaws.com:/" % (fuzz_filesystem.file_system_id, AWS_REGION), + mount_point="/efs_fuzzing_root") # Define CodeBuild. fuzz_codebuild = codebuild.Project( scope=self, @@ -104,28 +110,13 @@ def __init__(self, project_name=id, source=git_hub_source, role=role, - timeout=Duration.minutes(120), + timeout=core.Duration.minutes(120), environment=codebuild.BuildEnvironment(compute_type=codebuild.ComputeType.LARGE, privileged=True, build_image=codebuild.LinuxBuildImage.STANDARD_4_0), - build_spec=BuildSpecLoader.load(spec_file_path), + build_spec=codebuild.BuildSpec.from_object(build_spec_content), vpc=fuzz_vpc, - security_groups=[build_security_group]) + security_groups=[build_security_group], + file_system_locations=[efs_location] + ) fuzz_codebuild.enable_batch_builds() - - # CDK raw overrides: https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_raw - # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-codebuild-project.html#aws-resource-codebuild-project-properties - # The EFS identifier needs to match tests/ci/common_fuzz.sh, CodeBuild defines an environment variable named - # codebuild_$identifier. - # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-codebuild-project-projectfilesystemlocation.html - # - # TODO: add this to the CDK project above when it supports EfsFileSystemLocation - cfn_codebuild = fuzz_codebuild.node.default_child - cfn_codebuild.add_override("Properties.FileSystemLocations", [{ - "Identifier": "fuzzing_root", - "Location": "%s.efs.%s.amazonaws.com:/" % (fuzz_filesystem.file_system_id, AWS_REGION), - "MountPoint": "/efs_fuzzing_root", - "Type": "EFS" - }]) - - PruneStaleGitHubBuilds(scope=self, id="PruneStaleGitHubBuilds", project=fuzz_codebuild) diff --git a/tests/ci/cdk/cdk/codebuild/pr_fuzzing_omnibus.yaml b/tests/ci/cdk/cdk/codebuild/pr_fuzzing_omnibus.yaml new file mode 100644 index 00000000..dbcb1649 --- /dev/null +++ b/tests/ci/cdk/cdk/codebuild/pr_fuzzing_omnibus.yaml @@ -0,0 +1,15 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 OR ISC + +version: 0.2 + +# Doc for batch https://docs.aws.amazon.com/codebuild/latest/userguide/batch-build-buildspec.html#build-spec.batch.build-list +batch: + build-list: + - identifier: amazonlinux2_clang11x_cryptofuzz_x86 + buildspec: ./tests/ci/codebuild/run_accp_cryptofuzz.yml + env: + type: LINUX_CONTAINER + privileged-mode: true + compute-type: BUILD_GENERAL1_LARGE + image: ECR_REPO_PLACEHOLDER:amazonlinux-2_clang-11x_cryptofuzz_x86_latest \ No newline at end of file diff --git a/tests/ci/codebuild/run_accp_cryptofuzz.yml b/tests/ci/codebuild/run_accp_cryptofuzz.yml new file mode 100644 index 00000000..78e071d5 --- /dev/null +++ b/tests/ci/codebuild/run_accp_cryptofuzz.yml @@ -0,0 +1,13 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 OR ISC + +version: 0.2 + +env: + variables: + GOPROXY: https://proxy.golang.org,direct + +phases: + build: + commands: + - "tests/ci/run_cryptofuzz.sh" diff --git a/tests/ci/common_fuzz.sh b/tests/ci/common_fuzz.sh index 3adb2c12..4f198f7b 100644 --- a/tests/ci/common_fuzz.sh +++ b/tests/ci/common_fuzz.sh @@ -23,20 +23,6 @@ SHARED_FAILURE_ROOT="${CORPUS_ROOT}/runs/${DATE_NOW}/${BUILD_ID}" LOCAL_RUN_ROOT="${BUILD_ROOT}/fuzz_run_root" rm -rf "$LOCAL_RUN_ROOT" -function put_metric_count { - put_metric --unit Count "$@" -} - -function put_metric { - # This call to publish the metric could fail but we don't want to fail the build +e turns off exit on error - set +e - aws cloudwatch put-metric-data \ - --namespace AWS-LC-Fuzz \ - "$@" || echo "Publishing metric failed, continuing with the rest of the build" - # Turn it back on for the rest of the build - set -e -} - function run_fuzz_test { SHARED_FUZZ_TEST_CORPUS="${CORPUS_ROOT}/shared_corpus/${FUZZ_NAME}/shared_corpus" LOCAL_FUZZ_TEST_ROOT="${LOCAL_RUN_ROOT}/${FUZZ_NAME}" @@ -54,7 +40,6 @@ function run_fuzz_test { # as the SharedCorpusFileCount, which it basically everything in SHARED_FUZZ_TEST_CORPUS was just copied to # LOCAL_SHARED_CORPUS ORIGINAL_CORPUS_FILE_COUNT=$(find "$LOCAL_SHARED_CORPUS" -type f | wc -l) - put_metric_count --metric-name SharedCorpusFileCount --value "$ORIGINAL_CORPUS_FILE_COUNT" --dimensions "FuzzTest=$FUZZ_NAME" # Perform the actual fuzzing! # Step 1 run each fuzz test for the determined time. This will use the existing shared corpus copied from EFS to @@ -81,6 +66,7 @@ function run_fuzz_test { time "${FUZZ_TEST_PATH}" -rss_limit_mb=${MEM_USAGE_LIMIT} -print_final_stats=1 -timeout="$FUZZ_TEST_TIMEOUT" -max_total_time="$TIME_FOR_EACH_FUZZ" \ -jobs="$NUM_CPU_THREADS" -workers="$NUM_CPU_THREADS" \ -artifact_prefix="$LOCAL_ARTIFACTS_FOLDER/" \ + ${FUZZ_TEST_ADDITIONAL_ARGS} \ "$LOCAL_RUN_CORPUS" "$LOCAL_SHARED_CORPUS" "$SRC_CORPUS" 2>&1 | tee "$SUMMARY_LOG" # This gets the status of the fuzz run which determines if we want to fail the build or not, otherwise we'd get the results of tee if [ "${PIPESTATUS[0]}" == 1 ]; then @@ -123,22 +109,10 @@ function run_fuzz_test { # Calculate interesting metrics and post results to CloudWatch, this checks the shared (EFS) corpus after the new test # run corpus has been merged in FINAL_SHARED_CORPUS_FILE_COUNT=$(find "$SHARED_FUZZ_TEST_CORPUS" -type f | wc -l) - put_metric_count --metric-name SharedCorpusFileCount --value "$FINAL_SHARED_CORPUS_FILE_COUNT" --dimensions "FuzzTest=$FUZZ_NAME" - RUN_CORPUS_FILE_COUNT=$(find "$LOCAL_RUN_CORPUS" -type f | wc -l) - put_metric_count --metric-name RunCorpusFileCount --value "$RUN_CORPUS_FILE_COUNT" --dimensions "FuzzTest=$FUZZ_NAME,Platform=$PLATFORM" - TEST_COUNT=$(grep -o "stat::number_of_executed_units: [0-9]*" "$SUMMARY_LOG" | awk '{test_count += $2} END {print test_count}') - put_metric_count --metric-name TestCount --value "$TEST_COUNT" --dimensions "FuzzTest=$FUZZ_NAME,Platform=$PLATFORM" - TESTS_PER_SECOND=$((TEST_COUNT/TIME_FOR_EACH_FUZZ)) - put_metric --metric-name TestRate --value "$TESTS_PER_SECOND" --unit Count/Second --dimensions "FuzzTest=$FUZZ_NAME,Platform=$PLATFORM" - FEATURE_COVERAGE=$(grep -o "ft: [0-9]*" "$SUMMARY_LOG" | awk '{print $2}' | sort -n | tail -1) - put_metric_count --metric-name FeatureCoverage --value "$FEATURE_COVERAGE" --dimensions "FuzzTest=$FUZZ_NAME,Platform=$PLATFORM" - BLOCK_COVERAGE=$(grep -o "cov: [0-9]*" "$SUMMARY_LOG" | awk '{print $2}' | sort -n | tail -1) - put_metric_count --metric-name BlockCoverage --value "$BLOCK_COVERAGE" --dimensions "FuzzTest=$FUZZ_NAME,Platform=$PLATFORM" - echo "${FUZZ_NAME} starting shared ${ORIGINAL_CORPUS_FILE_COUNT} final shared ${FINAL_SHARED_CORPUS_FILE_COUNT} new files ${RUN_CORPUS_FILE_COUNT} total test count ${TEST_COUNT} test rate ${TESTS_PER_SECOND} code coverage ${BLOCK_COVERAGE} feature coverage ${FEATURE_COVERAGE}" } diff --git a/tests/ci/common_posix_setup.sh b/tests/ci/common_posix_setup.sh index 57605037..cdf2462c 100644 --- a/tests/ci/common_posix_setup.sh +++ b/tests/ci/common_posix_setup.sh @@ -25,187 +25,8 @@ if [[ "${KERNEL_NAME}" == "Darwin" ]]; then else # Assume KERNEL_NAME is Linux. NUM_CPU_THREADS=$(grep -c ^processor /proc/cpuinfo) - if [[ $PLATFORM == "aarch64" ]]; then - CPU_PART=$(grep -Po -m 1 'CPU part.*:\s\K.*' /proc/cpuinfo) - NUM_CPU_PART=$(grep -c $CPU_PART /proc/cpuinfo) - # Set capabilities via the static flags for valgrind tests. - # This is because valgrind reports the instruction - # mrs %0, MIDR_EL1 - # which fetches the CPU part number, as illegal. - # For some reason, valgrind also reports SHA512 instructions illegal, - # so the SHA512 capability is not included below. - VALGRIND_STATIC_CAP_FLAGS="-DOPENSSL_STATIC_ARMCAP -DOPENSSL_STATIC_ARMCAP_NEON" - VALGRIND_STATIC_CAP_FLAGS+=" -DOPENSSL_STATIC_ARMCAP_AES -DOPENSSL_STATIC_ARMCAP_PMULL " - VALGRIND_STATIC_CAP_FLAGS+=" -DOPENSSL_STATIC_ARMCAP_SHA1 -DOPENSSL_STATIC_ARMCAP_SHA256 " - if [[ $NUM_CPU_PART == $NUM_CPU_THREADS ]] && [[ ${CPU_PART} =~ 0x[dD]40 ]]; then - VALGRIND_STATIC_CAP_FLAGS+=" -DOPENSSL_STATIC_ARMCAP_SHA3 -DOPENSSL_STATIC_ARMCAP_NEOVERSE_V1" - fi - fi -fi - -# Pick cmake3 if possible. We don't know of any OS that installs a cmake3 -# executable that is not at least version 3.0. -if [[ -x "$(command -v cmake3)" ]] ; then - CMAKE_COMMAND="cmake3" -else - CMAKE_COMMAND="cmake" fi -function run_build { - local cflags=("$@") - rm -rf "$BUILD_ROOT" - mkdir -p "$BUILD_ROOT" - cd "$BUILD_ROOT" || exit 1 - - if [[ "${AWSLC_32BIT}" == "1" ]]; then - cflags+=("-DCMAKE_TOOLCHAIN_FILE=${SRC_ROOT}/util/32-bit-toolchain.cmake") - fi - - if [[ -x "$(command -v ninja)" ]]; then - echo "Using Ninja build system (ninja)." - BUILD_COMMAND="ninja" - cflags+=(-GNinja) - elif [[ -x "$(command -v ninja-build)" ]]; then - echo "Using Ninja build system (ninja-build)." - BUILD_COMMAND="ninja-build" - cflags+=(-GNinja) - else - echo "Using Make." - BUILD_COMMAND="make -j${NUM_CPU_THREADS}" - fi - - ${CMAKE_COMMAND} "${cflags[@]}" "$SRC_ROOT" - $BUILD_COMMAND - cd "$SRC_ROOT" -} - -function run_cmake_custom_target { - $BUILD_COMMAND -C "$BUILD_ROOT" "$@" -} - -function build_and_test { - run_build "$@" - run_cmake_custom_target 'run_tests' -} - -function generate_symbols_file { - # read_symbols.go currently only support static libraries - if [ ! -f "$BUILD_ROOT"/crypto/libcrypto.a ]; then - echo "Static library not found: ${BUILD_ROOT}/crypto/libcrypto.a" - exit 1 - fi - - go run "$SRC_ROOT"/util/read_symbols.go -out "$BUILD_ROOT"/symbols_crypto.txt "$BUILD_ROOT"/crypto/libcrypto.a - go run "$SRC_ROOT"/util/read_symbols.go -out "$BUILD_ROOT"/symbols_ssl.txt "$BUILD_ROOT"/ssl/libssl.a - - # The $BUILD_ROOT gets deleted on each run. symbols.txt must be placed elsewhere. - cat "$BUILD_ROOT"/symbols_crypto.txt "$BUILD_ROOT"/symbols_ssl.txt > "$SRC_ROOT"/symbols.txt -} - - -function verify_symbols_prefixed { - go run "$SRC_ROOT"/util/read_symbols.go -out "$BUILD_ROOT"/symbols_final_crypto.txt "$BUILD_ROOT"/crypto/libcrypto.a - go run "$SRC_ROOT"/util/read_symbols.go -out "$BUILD_ROOT"/symbols_final_ssl.txt "$BUILD_ROOT"/ssl/libssl.a - # For grep's basic regular expression language the meta-characters (e.g. "?", - # "|", etc.) are interpreted as literal characters. To keep their - # meta-character semantics, they must be escaped with "\". - # Deciphering the pattern "^_\?\(bignum\|curve25519_x25519\)": - # * "^": anchor at start of line. - # * "_\?": might contain underscore. - # * "\(bignum\|curve25519_x25519\)": match string of either "bignum" or "curve25519_x25519". - # Recall that the option "-v" reverse the pattern matching. So, we are really - # filtering out lines that contain either "bignum" or "curve25519_x25519". - cat "$BUILD_ROOT"/symbols_final_crypto.txt "$BUILD_ROOT"/symbols_final_ssl.txt | grep -v -e '^_\?\(bignum\|curve25519_x25519\)' > "$SRC_ROOT"/symbols_final.txt - # Now filter out every line that has the unique prefix $CUSTOM_PREFIX. If we - # have any lines left, then some symbol(s) weren't prefixed, unexpectedly. - if [ $(grep -c -v ${CUSTOM_PREFIX} "$SRC_ROOT"/symbols_final.txt) -ne 0 ]; then - echo "Symbol(s) missing prefix!" - exit 1 - fi -} - - -function build_prefix_and_test { - CUSTOM_PREFIX=aws_lc_1_1_0 - run_build "$@" - generate_symbols_file - run_build "$@" "-DBORINGSSL_PREFIX=${CUSTOM_PREFIX}" "-DBORINGSSL_PREFIX_SYMBOLS=${SRC_ROOT}/symbols.txt" - verify_symbols_prefixed - run_cmake_custom_target 'run_tests' -} - -function fips_build_and_test { - run_build "$@" -DFIPS=1 - # Upon completion of the build process. The module’s status can be verified by 'tool/bssl isfips'. - # https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3678.pdf - # FIPS mode is enabled when 'defined(BORINGSSL_FIPS) && !defined(OPENSSL_ASAN)'. - # https://github.com/aws/aws-lc/blob/220e266d4e415cf0101388b89a2bd855e0e4e203/crypto/fipsmodule/is_fips.c#L22 - expect_fips_mode=1 - for build_flag in "$@" - do - if [[ "${build_flag}" == '-DASAN=1' ]]; then - expect_fips_mode=0 - break - fi - done - module_status=$("${BUILD_ROOT}/tool/bssl" isfips) - [[ "${expect_fips_mode}" == "${module_status}" ]] || { echo >&2 "FIPS Mode validation failed."; exit 1; } - # Run tests. - run_cmake_custom_target 'run_tests' - "${BUILD_ROOT}/util/fipstools/test_fips" -} - -function build_and_test_valgrind { - if [[ $PLATFORM == "aarch64" ]]; then - run_build "$@" -DCMAKE_C_FLAGS="$VALGRIND_STATIC_CAP_FLAGS" - run_cmake_custom_target 'run_tests_valgrind' - - # Disable all capabilities and run again - # (We don't use the env. variable OPENSSL_armcap because it is currently - # restricted to the case of runtime discovery of capabilities - # in cpu_aarch64_linux.c) - run_build "$@" -DCMAKE_C_FLAGS="-DOPENSSL_STATIC_ARMCAP" - run_cmake_custom_target 'run_tests_valgrind' - else - run_build "$@" - run_cmake_custom_target 'run_tests_valgrind' - fi -} - -function build_and_test_ssl_runner_valgrind { - export AWS_LC_GO_TEST_TIMEOUT="60m" - - if [[ $PLATFORM == "aarch64" ]]; then - run_build "$@" -DCMAKE_C_FLAGS="$VALGRIND_STATIC_CAP_FLAGS" - else - run_build "$@" - fi - run_cmake_custom_target 'run_ssl_runner_tests_valgrind' -} - -function build_and_test_with_sde { - run_build "$@" - run_cmake_custom_target 'run_tests_with_sde' -} - -function build_and_run_minimal_test { - run_build "$@" - run_cmake_custom_target 'run_minimal_tests' -} - -# Install local build of AWS-LC for integration testing. -function aws_lc_build() { - AWS_LC_DIR=${1} - BUILD_FOLDER=${2} - INSTALL_FOLDER=${3} - - echo "Building AWS-LC to ${BUILD_FOLDER} and installing to ${INSTALL_FOLDER} with CFlags "${@:4}"" - ${CMAKE_COMMAND} ${AWS_LC_DIR} -GNinja "-B${BUILD_FOLDER}" "-DCMAKE_INSTALL_PREFIX=${INSTALL_FOLDER}" "${@:4}" - ninja -C ${BUILD_FOLDER} install - ls -R ${INSTALL_FOLDER} - rm -rf ${BUILD_FOLDER:?}/* -} - function print_executable_information { EXE_NAME=${1} EXE_ARGUMENT=${2} diff --git a/tests/ci/docker_images/dependencies/build_cryptofuzz_modules.sh b/tests/ci/docker_images/dependencies/build_cryptofuzz_modules.sh index 802d8adc..9f6057ea 100755 --- a/tests/ci/docker_images/dependencies/build_cryptofuzz_modules.sh +++ b/tests/ci/docker_images/dependencies/build_cryptofuzz_modules.sh @@ -19,10 +19,17 @@ git rev-parse HEAD CRYPTOFUZZ_SRC=$(pwd) python3 gen_repository.py +# Setup Boost library +wget https://boostorg.jfrog.io/artifactory/main/release/1.83.0/source/boost_1_83_0.tar.gz +tar -xzf boost_1_83_0.tar.gz +BOOST_DIRECTORY=`realpath boost_1_83_0` +export CXXFLAGS="${CXXFLAGS} -I ${BOOST_DIRECTORY}" + mkdir "$MODULES_ROOT" cd "$MODULES_ROOT" # Setup the other crypto libraries for differential fuzzing + # Crypto++ https://github.com/guidovranken/cryptofuzz/blob/master/docs/cryptopp.md cd "$MODULES_ROOT" git clone --depth 1 https://github.com/weidai11/cryptopp.git @@ -43,14 +50,11 @@ env CRYPTOFUZZ_SEED_CORPUS `realpath cryptofuzz_seed_corpus` env CRYPTOFUZZ_DICT `realpath cryptofuzz-dict.txt` # Save final common flags +env LINK_FLAGS "" env CFLAGS "$CFLAGS" env CXXFLAGS "$CXXFLAGS" env CRYPTOFUZZ_SRC "$CRYPTOFUZZ_SRC" -# Cryptofuzz builds its modules into $CRYPTOFUZZ_SRC/modules that includes everything it needs, deleting the module source -# code saves a substantial amount of space in the docker image -rm -rf "$MODULES_ROOT" - # Prebuild the required libcpu_features to save time cd "$CRYPTOFUZZ_SRC" make third_party/cpu_features/build/libcpu_features.a diff --git a/tests/ci/docker_images/dependencies/cryptofuzz_data.zip b/tests/ci/docker_images/dependencies/cryptofuzz_data.zip index 2fd98997..2639c378 100644 Binary files a/tests/ci/docker_images/dependencies/cryptofuzz_data.zip and b/tests/ci/docker_images/dependencies/cryptofuzz_data.zip differ diff --git a/tests/ci/docker_images/linux-x86/amazonlinux-2_accp_base/Dockerfile b/tests/ci/docker_images/linux-x86/amazonlinux-2_accp_base/Dockerfile index fb9c587c..db546710 100644 --- a/tests/ci/docker_images/linux-x86/amazonlinux-2_accp_base/Dockerfile +++ b/tests/ci/docker_images/linux-x86/amazonlinux-2_accp_base/Dockerfile @@ -32,3 +32,4 @@ RUN wget http://downloads.sourceforge.net/ltp/lcov-1.14-1.noarch.rpm && \ yum localinstall -y lcov-1.14-1.noarch.rpm ENV GO111MODULE=on +ENV DEPENDENCIES_DIR=/home/dependencies \ No newline at end of file diff --git a/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x/Dockerfile b/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x/Dockerfile index c5744f36..2ab7170a 100644 --- a/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x/Dockerfile +++ b/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x/Dockerfile @@ -1,19 +1,18 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 OR ISC -FROM amazonlinux-2023:base - +FROM amazonlinux-2:accp_base SHELL ["/bin/bash", "-c"] -# clang 15.0.6 is the latest version versions `yum --showduplicates list clang` +# clang 11.1.0 is the latest version versions `yum --showduplicates list clang` RUN set -ex && \ - dnf -y upgrade --releasever=latest && dnf install -y \ + yum -y update && yum install -y \ clang && \ - dnf clean packages && \ - dnf clean metadata && \ - dnf clean all && \ + yum clean packages && \ + yum clean metadata && \ + yum clean all && \ rm -rf /tmp/* && \ - rm -rf /var/cache/dnf + rm -rf /var/cache/yum ENV CC=clang ENV CXX=clang++ diff --git a/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x_cryptofuzz/Dockerfile b/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x_cryptofuzz/Dockerfile index f3c6c599..a50851fe 100644 --- a/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x_cryptofuzz/Dockerfile +++ b/tests/ci/docker_images/linux-x86/amazonlinux-2_clang-11x_cryptofuzz/Dockerfile @@ -1,26 +1,36 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 OR ISC -FROM amazonlinux-2023:clang-15x +FROM amazonlinux-2:clang-11x SHELL ["/bin/bash", "-c"] RUN set -ex && \ - dnf -y upgrade --releasever=latest && dnf install -y \ + yum -y update && yum install -y \ libtool \ - boost-devel \ unzip \ llvm \ llvm-devel \ - lld && \ - dnf clean packages && \ - dnf clean metadata && \ - dnf clean all && \ + lld \ + compiler-rt \ + perl-core \ + java-17-amazon-corretto \ + java-17-amazon-corretto-devel && \ + yum clean packages && \ + yum clean metadata && \ + yum clean all && \ rm -rf /tmp/* && \ - rm -rf /var/cache/dnf + rm -rf /var/cache/yum + +ENV JAVA_HOME=/usr/lib/jvm/java-17-amazon-corretto.x86_64 ENV FUZZ_ROOT=${DEPENDENCIES_DIR} ENV MODULE_ROOT="${FUZZ_ROOT}/modules" -COPY build_cryptofuzz_modules.sh cryptofuzz_data.zip $FUZZ_ROOT/ -RUN set -ex && cd $FUZZ_ROOT && "./build_cryptofuzz_modules.sh" +# Cryptofuzz wants cmake3 so we make it AL2's default cmake via symlink +RUN ln -s `which cmake3` /usr/local/bin/cmake + +COPY tests/ci/docker_images/dependencies/build_cryptofuzz_modules.sh \ + tests/ci/docker_images/dependencies/cryptofuzz_data.zip \ + $FUZZ_ROOT/ +RUN set -ex && cd $FUZZ_ROOT && "./build_cryptofuzz_modules.sh" \ No newline at end of file diff --git a/tests/ci/docker_images/linux-x86/build_images.sh b/tests/ci/docker_images/linux-x86/build_images.sh index 94ed2b67..514618cd 100755 --- a/tests/ci/docker_images/linux-x86/build_images.sh +++ b/tests/ci/docker_images/linux-x86/build_images.sh @@ -16,6 +16,8 @@ docker build -t ubuntu-20.04:accp_base ubuntu-20.04_accp_base docker build -t ubuntu-20.04:gcc-7x_corretto -f ubuntu-20.04_gcc-7x_corretto/Dockerfile ../../../../ docker build -t amazonlinux-2:accp_base amazonlinux-2_accp_base docker build -t amazonlinux-2:gcc-7x_corretto -f amazonlinux-2_gcc-7x_corretto/Dockerfile ../../../../ +docker build -t amazonlinux-2:clang-11x -f amazonlinux-2_clang-11x/Dockerfile ../../../../ +docker build -t amazonlinux-2:clang-11x_cryptofuzz -f amazonlinux-2_clang-11x_cryptofuzz/Dockerfile ../../../../ ################################################# # Build legacy docker image that uses gcc 4.1.3 # diff --git a/tests/ci/docker_images/linux-x86/push_images.sh b/tests/ci/docker_images/linux-x86/push_images.sh index 158e8323..0a81e22b 100755 --- a/tests/ci/docker_images/linux-x86/push_images.sh +++ b/tests/ci/docker_images/linux-x86/push_images.sh @@ -18,3 +18,4 @@ $(aws ecr get-login --no-include-email) tag_and_push_img 'ubuntu-20.04:gcc-7x_corretto' "${ECS_REPO}:ubuntu-20.04_gcc-7x_corretto_x86" tag_and_push_img 'amazonlinux-2:gcc-7x_corretto' "${ECS_REPO}:amazonlinux-2_gcc-7x_corretto_x86" tag_and_push_img 'ubuntu-10.04:gcc-4.1x_corretto' "${ECS_REPO}:ubuntu-10.04_gcc-4.1x_corretto_x86" +tag_and_push_img 'amazonlinux-2:clang-11x_cryptofuzz' "${ECS_REPO}:amazonlinux-2_clang-11x_cryptofuzz_x86" \ No newline at end of file diff --git a/tests/ci/docker_images/linux-x86/ubuntu-10.04_gcc-4.1x_corretto/Dockerfile b/tests/ci/docker_images/linux-x86/ubuntu-10.04_gcc-4.1x_corretto/Dockerfile index c0381ce9..a4dc4dee 100644 --- a/tests/ci/docker_images/linux-x86/ubuntu-10.04_gcc-4.1x_corretto/Dockerfile +++ b/tests/ci/docker_images/linux-x86/ubuntu-10.04_gcc-4.1x_corretto/Dockerfile @@ -20,8 +20,7 @@ RUN sed -i -re 's/([a-z]{2}\.)?archive.ubuntu.com|security.ubuntu.com/old-releas perl \ python-pip \ java-common \ - alien \ - clang-format + alien RUN update-alternatives --install /usr/bin/cc gcc /usr/bin/gcc-4.1 70 --slave /usr/bin/c++ g++ /usr/bin/g++-4.1 --slave /usr/bin/gcov gcov /usr/bin/gcov-4.1 diff --git a/tests/ci/docker_images/linux-x86/ubuntu-20.04_accp_base/Dockerfile b/tests/ci/docker_images/linux-x86/ubuntu-20.04_accp_base/Dockerfile index 297496e0..2963558f 100644 --- a/tests/ci/docker_images/linux-x86/ubuntu-20.04_accp_base/Dockerfile +++ b/tests/ci/docker_images/linux-x86/ubuntu-20.04_accp_base/Dockerfile @@ -16,7 +16,6 @@ RUN apt-get install -y build-essential RUN apt-get install -y cmake RUN apt-get install -y lcov RUN apt-get install -y wget -RUN apt-get install -y clang-format RUN apt-get install -y python3-pip RUN pip3 install gcovr diff --git a/tests/ci/run_cryptofuzz.sh b/tests/ci/run_cryptofuzz.sh index 45e829ae..cf28d642 100755 --- a/tests/ci/run_cryptofuzz.sh +++ b/tests/ci/run_cryptofuzz.sh @@ -11,19 +11,32 @@ set -u rm -rf "$BUILD_ROOT" mkdir -p "$BUILD_ROOT" -cd "$BUILD_ROOT" -# Build AWS-LC based on https://github.com/guidovranken/cryptofuzz/blob/master/docs/openssl.md -${CMAKE_COMMAND} -DCMAKE_CXX_FLAGS="$CXXFLAGS" -DCMAKE_C_FLAGS="$CFLAGS" -DBORINGSSL_ALLOW_CXX_RUNTIME=1 \ - -GNinja -DBUILD_TESTING=OFF -DBUILD_LIBSSL=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo ../ -ninja -cd ../ +# Build ACCP, but skip the tests since that's covered by all the other CI +cd ${SRC_ROOT} +./gradlew -x check build +AWSLC_INSTALL_PATH=`realpath build/awslc/bin/` +export AWSLC_INCLUDE_PATH="${AWSLC_INSTALL_PATH}/include/" +export AWSLC_LIBRARY_PATH="${AWSLC_INSTALL_PATH}/lib64/" +export CXXFLAGS="$CXXFLAGS -I $AWSLC_INCLUDE_PATH" +export ACCP_JAR=`realpath build/lib/AmazonCorrettoCryptoProvider.jar` -# CRYPTOFUZZ_AWSLC will enable AES_256_XTS in upstream code. See `V610453347`. -# TODO: remove CRYPTOFUZZ_BORINGSSL when CRYPTOFUZZ_AWSLC is fully integrated. -export CXXFLAGS="$CXXFLAGS -DCRYPTOFUZZ_BORINGSSL -DCRYPTOFUZZ_AWSLC" -export OPENSSL_INCLUDE_PATH=`realpath include/` -export OPENSSL_LIBCRYPTO_A_PATH=`realpath ${BUILD_ROOT}/crypto/libcrypto.a` +# We run the Java module with ACCP as the JCE provider. +# This module uses OpenSSL symbols, so we provide those from AWS-LC to avoid symbol conflicts +# Java https://github.com/guidovranken/cryptofuzz/blob/master/docs/java.md +export JDK_PATH=${JAVA_HOME} +export LINK_FLAGS="${LINK_FLAGS} -L${JDK_PATH}/lib/server/ -ljvm -L${AWSLC_LIBRARY_PATH} -lcrypto" +export LINK_FLAGS="${LINK_FLAGS} -Wl,-rpath=${JDK_PATH}/lib/server/:${AWSLC_LIBRARY_PATH}" +export CXXFLAGS="$CXXFLAGS -DCRYPTOFUZZ_JAVA -DJAVA_WITH_ECDSA -DCRYPTOFUZZ_ACCP" +cd "${CRYPTOFUZZ_SRC}/modules/java/" +make -j$(nproc) + +# LSAN suppressions due to false positives +cd ${FUZZ_ROOT} +echo 'leak:libjvm.so' >> lsan.supp +echo 'leak:libz.so' >> lsan.supp +echo 'leak:libzip.so' >> lsan.supp +export LSAN_OPTIONS="suppressions=`realpath lsan.supp`" # For cryptofuzz development only, override CRYPTOFUZZ_SRC with CUSTOM_CRYPTOFUZZ_REPO_DIR. CUSTOM_CRYPTOFUZZ_REPO_DIR='' @@ -31,22 +44,15 @@ if [[ -z "${CUSTOM_CRYPTOFUZZ_REPO_DIR}" ]]; then echo "CUSTOM_CRYPTOFUZZ_REPO_DIR is empty." else export CRYPTOFUZZ_SRC="${CUSTOM_CRYPTOFUZZ_REPO_DIR}" - # Local development does not need differential fuzzing. - # Remove these libs related build flags. - export CXXFLAGS="${CXXFLAGS// -DCRYPTOFUZZ_BOTAN/}" - export CXXFLAGS="${CXXFLAGS// -DCRYPTOFUZZ_CRYPTOPP/}" cd "$CRYPTOFUZZ_SRC" # This step is to generate required header and cpp files. python3 gen_repository.py fi -# Build the common OpenSSL module with AWS-LC -cd "${CRYPTOFUZZ_SRC}/modules/openssl" -make "-j${NUM_CPU_THREADS}" - -export CFLAGS="${CFLAGS} -I $OPENSSL_INCLUDE_PATH" -export CXXFLAGS="${CXXFLAGS} -I $OPENSSL_INCLUDE_PATH" +# Required linker flag set via this variable export LIBFUZZER_LINK="-fsanitize=fuzzer" +# Explicitly disable OpenSSL module since it creates symbol conflicts +export CXXFLAGS="$CXXFLAGS -DCRYPTOFUZZ_NO_OPENSSL" # Build the overall cryptofuzz and generate_corpus binary cd "$CRYPTOFUZZ_SRC" @@ -54,7 +60,7 @@ rm -rf cryptofuzz rm -rf generate_corpus make "-j${NUM_CPU_THREADS}" cryptofuzz generate_corpus -# Common AWS-LC fuzzing setup, the cryptofuzz binary is in this folder so FUZZ_TEST_PATH=FUZZ_NAME +# Common ACCP fuzzing setup, the cryptofuzz binary is in this folder so FUZZ_TEST_PATH=FUZZ_NAME FUZZ_NAME="cryptofuzz" FUZZ_TEST_PATH="${CRYPTOFUZZ_SRC}/${FUZZ_NAME}" SRC_CORPUS="$CRYPTOFUZZ_SEED_CORPUS" @@ -67,12 +73,18 @@ SRC_CORPUS="$CRYPTOFUZZ_SEED_CORPUS" # 5 minutes for building AWS-LC and Cryptofuzz # 16 minutes (1000 seconds) of fuzzing # 24 minutes of cleanup and merging in new inputs -TIME_FOR_EACH_FUZZ=1000 +TIME_FOR_EACH_FUZZ=${TIME_FOR_EACH_FUZZ:=1000} # Some fuzz tests can take a while but still pass. This is a tradeoff: less false positive noise, but some inputs that take # a long time could lead to a denial of service avenue. We're mostly interested in correctness and memory safety at this # time so we're willing to take the fit on fuzz speed -FUZZ_TEST_TIMEOUT=30 +FUZZ_TEST_TIMEOUT=${FUZZ_TEST_TIMEOUT:=30} + +# Cryptofuzz lets us specify the operations and algorithms to fuzz +# We use this to narrow the fuzzing run to only what's supported by the Java/ACCP module rather than all of OpenSSL +FUZZ_TEST_ADDITIONAL_ARGS="--operations=Digest,HMAC,ECDSA_Verify" +FUZZ_TEST_ADDITIONAL_ARGS="${FUZZ_TEST_ADDITIONAL_ARGS} --digests=NULL,MD5,SHA1,SHA256,SHA384,SHA512" +FUZZ_TEST_ADDITIONAL_ARGS="${FUZZ_TEST_ADDITIONAL_ARGS} --curves=secp256r1,secp384r1" # Call the common fuzzing logic run_fuzz_test