diff --git a/.github/workflows/ci_ubuntu.yml b/.github/workflows/ci_ubuntu.yml new file mode 100644 index 00000000000..d390ed6749a --- /dev/null +++ b/.github/workflows/ci_ubuntu.yml @@ -0,0 +1,98 @@ +name: Ubuntu +on: + pull_request: + branches: [main] + merge_group: + types: [checks_requested] + branches: [main] + +# Builds should match https://github.com/aws/s2n-tls/blob/main/docs/BUILD.md#building-s2n-tls +# If any of these builds need to be modified, BUILD.md also needs to be modified. +jobs: + default: + runs-on: ubuntu-latest + steps: + - name: Install dependencies + run: | + sudo apt update + sudo apt install cmake + sudo apt install libssl-dev + - uses: actions/checkout@v4 + + - name: Build s2n-tls + run: | + cmake . -Bbuild \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=./s2n-tls-install + cmake --build build -j $(nproc) + CTEST_PARALLEL_LEVEL=$(nproc) ctest --test-dir build + cmake --install build + + - name: Rebuild with seccomp + run: | + rm -rf build + sudo apt install libseccomp-dev + cmake . -Bbuild \ + -DCMAKE_BUILD_TYPE=Release \ + -DSECCOMP=1 \ + -DCMAKE_INSTALL_PREFIX=./s2n-tls-install + cmake --build build -j $(nproc) + CTEST_PARALLEL_LEVEL=$(nproc) ctest --test-dir build + + awslc: + runs-on: ubuntu-latest + steps: + - name: Install aws-lc dependencies + run: | + sudo apt update + sudo apt install cmake clang golang + - uses: actions/checkout@v4 + with: + repository: aws/aws-lc + path: awslc + - name: Build awslc + # See https://github.com/aws/aws-lc/blob/main/BUILDING.md#building + working-directory: awslc + run: | + cmake -B build + make -C build + cmake --install install + + - name: Install s2n-tls dependencies + run: | + sudo apt update + sudo apt install cmake + - uses: actions/checkout@v4 + path: s2ntls + - name: Build s2n-tls + working-directory: s2ntls + run: | + cmake . -Bbuild \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH=../awslc/install \ + -DCMAKE_INSTALL_PREFIX=./s2n-tls-install + cmake --build build -j $(nproc) + CTEST_PARALLEL_LEVEL=$(nproc) ctest --test-dir build + cmake --install build + - name: Check libcrypto is aws-lc + working-directory: s2ntls/build/bin + run: s2nc localhost 8000 | grep "AWS-LC" + + - name: Install seccomp + run: | + sudo apt install libseccomp-dev + - uses: actions/checkout@v4 + path: seccomp + - name: Build s2n-tls with seccomp + working-directory: seccomp + run: | + cmake . -Bbuild \ + -DCMAKE_BUILD_TYPE=Release \ + -DSECCOMP=1 \ + -DCMAKE_PREFIX_PATH=../awslc/install \ + -DCMAKE_INSTALL_PREFIX=./s2n-tls-install + cmake --build build -j $(nproc) + CTEST_PARALLEL_LEVEL=$(nproc) ctest --test-dir build + - name: Check libcrypto is aws-lc + working-directory: seccomp/build/bin + run: s2nc localhost 8000 | grep "AWS-LC" diff --git a/CMakeLists.txt b/CMakeLists.txt index c89bae8a817..fa01a3c7ee9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ option(S2N_INSTALL_S2NC_S2ND "Install the binaries s2nc and s2nd" OFF) option(S2N_USE_CRYPTO_SHARED_LIBS "For S2N to use shared libs in Findcrypto" OFF) option(TSAN "Enable ThreadSanitizer to test thread safety" OFF) option(ASAN "Enable AddressSanitizer to test memory safety" OFF) +option(SECCOMP "Link with seccomp and run seccomp tests" OFF) # Turn BUILD_TESTING=ON by default include(CTest) @@ -452,6 +453,11 @@ if (BUILD_TESTING) target_include_directories(testss2n PUBLIC tests) target_compile_options(testss2n PRIVATE -std=gnu99) target_link_libraries(testss2n PUBLIC ${PROJECT_NAME}) + if (SECCOMP) + message(STATUS "Linking tests with seccomp") + target_link_libraries(testss2n PRIVATE seccomp) + target_compile_definitions(testss2n PRIVATE SECCOMP) + endif() if (S2N_INTERN_LIBCRYPTO) # if libcrypto was interned, rewrite libcrypto symbols so use of internal functions will link correctly diff --git a/tests/testlib/s2n_seccomp.c b/tests/testlib/s2n_seccomp.c new file mode 100644 index 00000000000..80df4471476 --- /dev/null +++ b/tests/testlib/s2n_seccomp.c @@ -0,0 +1,48 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include "testlib/s2n_testlib.h" +#include "utils/s2n_safety.h" + +#ifdef SECCOMP + +#include + +DEFINE_POINTER_CLEANUP_FUNC(scmp_filter_ctx, seccomp_release); + +S2N_RESULT s2n_seccomp_init() +{ + /* Using SCMP_ACT_TRAP instead of SCMP_ACT_KILL makes this test easier + * to debug. GDB will report exactly which syscalls triggered the signal. + */ + DEFER_CLEANUP(scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP), + seccomp_release_pointer); + RESULT_ENSURE_REF(ctx); + + RESULT_GUARD_POSIX(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0)); + RESULT_GUARD_POSIX(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0)); + RESULT_GUARD_POSIX(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0)); + RESULT_GUARD_POSIX(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0)); + RESULT_GUARD_POSIX(seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 0)); + + RESULT_GUARD_POSIX(seccomp_load(ctx)); + return S2N_RESULT_OK; +} +#else +S2N_RESULT s2n_seccomp_init() +{ + return S2N_RESULT_OK; +} +#endif diff --git a/tests/testlib/s2n_testlib.h b/tests/testlib/s2n_testlib.h index 60effca24de..b1a8394c0de 100644 --- a/tests/testlib/s2n_testlib.h +++ b/tests/testlib/s2n_testlib.h @@ -298,3 +298,5 @@ S2N_RESULT s2n_resumption_test_ticket_key_setup(struct s2n_config *config); #define S2N_CHECKED_BLOB_FROM_HEX(name, check, hex) \ DEFER_CLEANUP(struct s2n_blob name = { 0 }, s2n_free); \ check(s2n_blob_alloc_from_hex_with_whitespace(&name, (const char *) hex)); + +S2N_RESULT s2n_seccomp_init(); diff --git a/tests/unit/s2n_seccomp_handshake_test.c b/tests/unit/s2n_seccomp_handshake_test.c new file mode 100644 index 00000000000..847e3009bfb --- /dev/null +++ b/tests/unit/s2n_seccomp_handshake_test.c @@ -0,0 +1,70 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include +#include +#include + +#include "api/s2n.h" +#include "s2n_test.h" +#include "testlib/s2n_testlib.h" + +int main(int argc, char **argv) +{ + BEGIN_TEST(); + + /* We don't use s2n_test_cert_chain_and_key_new because we want to explicitly + * only do the PEM file read before enabling seccomp. + */ + char cert_chain_pem[S2N_MAX_TEST_PEM_SIZE] = { 0 }; + char private_key_pem[S2N_MAX_TEST_PEM_SIZE] = { 0 }; + EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_ECDSA_TEST_CERT_CHAIN, cert_chain_pem, S2N_MAX_TEST_PEM_SIZE)); + EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_ECDSA_TEST_PRIVATE_KEY, private_key_pem, S2N_MAX_TEST_PEM_SIZE)); + + /* Really start the test: no unexpected syscalls beyond this point */ + EXPECT_OK(s2n_seccomp_init()); + + DEFER_CLEANUP(struct s2n_cert_chain_and_key *chain_and_key = s2n_cert_chain_and_key_new(), + s2n_cert_chain_and_key_ptr_free); + EXPECT_SUCCESS(s2n_cert_chain_and_key_load_pem(chain_and_key, cert_chain_pem, private_key_pem)); + + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new_minimal(), s2n_config_ptr_free); + EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key)); + EXPECT_SUCCESS(s2n_config_set_unsafe_for_testing(config)); + + const char* security_policies[] = { "default", "default_tls13" }; + + for (size_t i = 0; i < s2n_array_len(security_policies); i++) { + DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT), + s2n_connection_ptr_free); + EXPECT_NOT_NULL(client); + EXPECT_SUCCESS(s2n_connection_set_config(client, config)); + EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client, security_policies[i])); + + DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER), + s2n_connection_ptr_free); + EXPECT_NOT_NULL(server); + EXPECT_SUCCESS(s2n_connection_set_config(server, config)); + EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server, security_policies[i])); + + DEFER_CLEANUP(struct s2n_test_io_stuffer_pair io_pair = { 0 }, s2n_io_stuffer_pair_free); + EXPECT_OK(s2n_io_stuffer_pair_init(&io_pair)); + EXPECT_OK(s2n_connections_set_io_stuffer_pair(client, server, &io_pair)); + EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server, client)); + } + + return 0; +} + diff --git a/utils/s2n_init.c b/utils/s2n_init.c index 3c561106ea8..9e9f91314b3 100644 --- a/utils/s2n_init.c +++ b/utils/s2n_init.c @@ -87,6 +87,10 @@ int s2n_init(void) s2n_stack_traces_enabled_set(true); } +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) + CRYPTO_pre_sandbox_init(); +#endif + initialized = true; return S2N_SUCCESS;