diff --git a/base/glibc-compatibility/musl/posix_spawn.c b/base/glibc-compatibility/musl/posix_spawn.c index a66e64e01a20..fa0309eeff88 100644 --- a/base/glibc-compatibility/musl/posix_spawn.c +++ b/base/glibc-compatibility/musl/posix_spawn.c @@ -1,5 +1,17 @@ -/// Very limited implementation. Half of code from Musl was cut. -/// This is Ok, because for now, this function is used only from clang driver. +/// Full posix_spawn implementation based on upstream musl. +/// https://git.musl-libc.org/cgit/musl/tree/src/process/posix_spawn.c +/// +/// Adaptations from upstream: +/// - Uses glibc sysroot field names (__ss/__sd instead of __mask/__def) +/// since resolves to the glibc sysroot header in this build. +/// - Takes exec function as a parameter (__posix_spawnx) because glibc's +/// posix_spawnattr_t has no __fn field for posix_spawnp dispatch. +/// - Omits LOCK(__abort_lock) / UNLOCK(__abort_lock) (musl-internal lock +/// guarding against abort() races; not available outside musl). +/// - Omits __get_handler_set / __libc_sigaction signal disposition reset +/// (musl internals not available; signals are blocked for the child's +/// brief pre-exec window, so parent handlers cannot fire). +/// - Uses clone() instead of musl-internal __clone(). #define _GNU_SOURCE #include @@ -9,12 +21,24 @@ #include #include #include -#include #include -#include #include +#include #include "syscall.h" +#define FDOP_CLOSE 1 +#define FDOP_DUP2 2 +#define FDOP_OPEN 3 +#define FDOP_CHDIR 4 +#define FDOP_FCHDIR 5 + +struct fdop { + struct fdop *next, *prev; + int cmd, fd, srcfd, oflag; + mode_t mode; + char path[]; +}; + struct args { int p[2]; sigset_t oldmask; @@ -25,17 +49,109 @@ struct args { char *const *argv, *const *envp; }; -void __get_handler_set(sigset_t *); +static int __sys_dup2(int old, int new) +{ +#ifdef SYS_dup2 + return __syscall(SYS_dup2, old, new); +#else + return __syscall(SYS_dup3, old, new, 0); +#endif +} static int child(void *args_vp) { - int ret; + int i, ret; + struct sigaction sa = {0}; struct args *args = args_vp; int p = args->p[1]; + const posix_spawn_file_actions_t *fa = args->fa; const posix_spawnattr_t *restrict attr = args->attr; close(args->p[0]); + if (attr->__flags & POSIX_SPAWN_SETSIGDEF) { + for (i=1; i<_NSIG; i++) { + if (sigismember(&attr->__sd, i)) { + sa.sa_handler = SIG_DFL; + __syscall(SYS_rt_sigaction, i, &sa, 0, _NSIG/8); + } + } + } + + if (attr->__flags & POSIX_SPAWN_SETSID) + if ((ret=__syscall(SYS_setsid)) < 0) + goto fail; + + if (attr->__flags & POSIX_SPAWN_SETPGROUP) + if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp))) + goto fail; + + if (attr->__flags & POSIX_SPAWN_RESETIDS) + if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) || + (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) ) + goto fail; + + if (fa && fa->__actions) { + struct fdop *op; + int fd; + for (op = fa->__actions; op->next; op = op->next); + for (; op; op = op->prev) { + /* It's possible that a file operation would clobber + * the pipe fd used for synchronizing with the + * parent. To avoid that, we dup the pipe onto + * an unoccupied fd. */ + if (op->fd == p) { + ret = __syscall(SYS_dup, p); + if (ret < 0) goto fail; + __syscall(SYS_close, p); + p = ret; + } + switch(op->cmd) { + case FDOP_CLOSE: + __syscall(SYS_close, op->fd); + break; + case FDOP_DUP2: + fd = op->srcfd; + if (fd == p) { + ret = -EBADF; + goto fail; + } + if (fd != op->fd) { + if ((ret=__sys_dup2(fd, op->fd))<0) + goto fail; + } else { + ret = __syscall(SYS_fcntl, fd, F_GETFD); + ret = __syscall(SYS_fcntl, fd, F_SETFD, + ret & ~FD_CLOEXEC); + if (ret<0) + goto fail; + } + break; + case FDOP_OPEN: +#ifdef SYS_open + fd = __syscall(SYS_open, op->path, op->oflag, op->mode); +#else + fd = __syscall(SYS_openat, AT_FDCWD, op->path, op->oflag, op->mode); +#endif + if ((ret=fd) < 0) goto fail; + if (fd != op->fd) { + if ((ret=__sys_dup2(fd, op->fd))<0) + goto fail; + __syscall(SYS_close, fd); + } + break; + case FDOP_CHDIR: + ret = __syscall(SYS_chdir, op->path); + if (ret<0) goto fail; + break; + case FDOP_FCHDIR: + ret = __syscall(SYS_fchdir, op->fd); + if (ret<0) goto fail; + break; + } + } + } + /* Close-on-exec flag may have been lost if we moved the pipe * to a different fd. We don't use F_DUPFD_CLOEXEC above because * it would fail on older kernels and atomicity is not needed -- @@ -48,9 +164,14 @@ static int child(void *args_vp) args->exec(args->path, args->argv, args->envp); ret = -errno; +fail: /* Since sizeof errno < PIPE_BUF, the write is atomic. */ ret = -ret; - if (ret) while (__syscall(SYS_write, p, &ret, sizeof ret) < 0); + if (ret) { + int r; + do r = __syscall(SYS_write, p, &ret, sizeof ret); + while (r<0 && r!=-EPIPE); + } _exit(127); } @@ -62,13 +183,10 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, char *const argv[restrict], char *const envp[restrict]) { pid_t pid; - char stack[1024]; + char stack[1024+PATH_MAX]; int ec=0, cs; struct args args; - if (pipe2(args.p, O_CLOEXEC)) - return errno; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); args.path = path; @@ -78,6 +196,15 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, args.argv = argv; args.envp = envp; + sigset_t allsigs; + sigfillset(&allsigs); + pthread_sigmask(SIG_BLOCK, &allsigs, &args.oldmask); + + if (pipe2(args.p, O_CLOEXEC)) { + ec = errno; + goto fail; + } + pid = clone(child, stack+sizeof stack, CLONE_VM|CLONE_VFORK|SIGCHLD, &args); close(args.p[1]); @@ -93,6 +220,8 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path, if (!ec && res) *res = pid; +fail: + pthread_sigmask(SIG_SETMASK, &args.oldmask, 0); pthread_setcancelstate(cs, 0); return ec; diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index 59cf435fdf82..aeb8cdd21631 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -62,6 +62,14 @@ else() message(STATUS "ClickHouse keeper-client mode: OFF") endif() +if (FIPS_CLICKHOUSE AND DEFINED AWSLC_SRC_DIR) + set(ENABLE_CLICKHOUSE_SSL_SHIM 1) + if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(ENABLE_CLICKHOUSE_SSL_HANDSHAKER 1) + set(ENABLE_CLICKHOUSE_ACVP_SERVER 1) + endif() +endif() + configure_file (config_tools.h.in ${CONFIG_INCLUDE_PATH}/config_tools.h) macro(clickhouse_target_link_split_lib target name) @@ -127,6 +135,16 @@ if (ENABLE_CLICKHOUSE_KEEPER) add_subdirectory (keeper) endif() +if (ENABLE_CLICKHOUSE_SSL_SHIM) + add_subdirectory (ssl-shim) +endif() +if (ENABLE_CLICKHOUSE_SSL_HANDSHAKER) + add_subdirectory (ssl-handshaker) +endif() +if (ENABLE_CLICKHOUSE_ACVP_SERVER) + add_subdirectory (acvp-server) +endif() + if (ENABLE_CLICKHOUSE_SELF_EXTRACTING AND NOT ENABLE_DUMMY_LAUNCHERS) add_subdirectory (self-extracting) endif () @@ -225,6 +243,16 @@ if (ENABLE_CLICKHOUSE_KEEPER_CLIENT) list(APPEND CLICKHOUSE_BUNDLE clickhouse-keeper-client) endif () +if (ENABLE_CLICKHOUSE_SSL_SHIM) + clickhouse_program_install(clickhouse-ssl-shim ssl-shim) +endif() +if (ENABLE_CLICKHOUSE_SSL_HANDSHAKER) + clickhouse_program_install(clickhouse-ssl-handshaker ssl-handshaker) +endif() +if (ENABLE_CLICKHOUSE_ACVP_SERVER) + clickhouse_program_install(clickhouse-acvp-server acvp-server) +endif() + add_custom_target (clickhouse-bundle ALL DEPENDS ${CLICKHOUSE_BUNDLE}) if (USE_BINARY_HASH) diff --git a/programs/acvp-server/AcvpServer.cpp b/programs/acvp-server/AcvpServer.cpp new file mode 100644 index 000000000000..95209e62a0fc --- /dev/null +++ b/programs/acvp-server/AcvpServer.cpp @@ -0,0 +1,6 @@ +extern int acvp_modulewrapper_main(int argc, char ** argv); + +int mainEntryClickHouseAcvpServer(int argc, char ** argv) +{ + return acvp_modulewrapper_main(argc, argv); +} diff --git a/programs/acvp-server/CMakeLists.txt b/programs/acvp-server/CMakeLists.txt new file mode 100644 index 000000000000..54d53c5af306 --- /dev/null +++ b/programs/acvp-server/CMakeLists.txt @@ -0,0 +1,96 @@ +if(NOT FIPS_CLICKHOUSE OR NOT DEFINED AWSLC_SRC_DIR) + return() +endif() + +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") + return() +endif() + +set(AWSLC_ACVP_MODULEWRAPPER_DIR "${AWSLC_SRC_DIR}/util/fipstools/acvp/modulewrapper") +set(AWSLC_LIBCRYPTO "${CMAKE_BINARY_DIR}/awslc-build/output/libcrypto.a") + +set(ACVP_OBJ_DIR "${CMAKE_CURRENT_BINARY_DIR}/awslc_acvp_server_objs") + +set(AWSLC_ACVP_SERVER_CXX_SRCS + ${AWSLC_ACVP_MODULEWRAPPER_DIR}/main.cc + ${AWSLC_ACVP_MODULEWRAPPER_DIR}/modulewrapper.cc +) + +set(AWSLC_ACVP_SERVER_INCLUDE_FLAGS + -I${AWSLC_ACVP_MODULEWRAPPER_DIR} + -I${AWSLC_SRC_DIR}/include + -I${AWSLC_SRC_DIR} +) + +set(AWSLC_ACVP_SERVER_OBJS) +foreach(src ${AWSLC_ACVP_SERVER_CXX_SRCS}) + get_filename_component(base "${src}" NAME_WE) + get_filename_component(dir "${src}" DIRECTORY) + string(MD5 dir_hash "${dir}") + string(SUBSTRING "${dir_hash}" 0 8 dir_tag) + set(obj "${ACVP_OBJ_DIR}/${base}_${dir_tag}.o") + + set(extra_defs "") + if("${base}" STREQUAL "main") + set(extra_defs -Dmain=acvp_modulewrapper_main) + endif() + + add_custom_command( + OUTPUT "${obj}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${ACVP_OBJ_DIR}" + COMMAND /usr/bin/c++ + -std=c++17 -fPIC -g -O2 + ${AWSLC_ACVP_SERVER_INCLUDE_FLAGS} + ${extra_defs} + -w + -c "${src}" + -o "${obj}" + DEPENDS "${src}" build-awslc + COMMENT "Building aws-lc acvp-server object ${base}.cc (system C++ ABI)" + ) + list(APPEND AWSLC_ACVP_SERVER_OBJS "${obj}") +endforeach() + +set(GLIBC_COMPAT_ACVP_OBJ "${ACVP_OBJ_DIR}/glibc_compat.o") +add_custom_command( + OUTPUT "${GLIBC_COMPAT_ACVP_OBJ}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${ACVP_OBJ_DIR}" + COMMAND /usr/bin/cc -fPIC -O2 -w + -c "${CMAKE_CURRENT_SOURCE_DIR}/../ssl-common/glibc_compat.c" + -o "${GLIBC_COMPAT_ACVP_OBJ}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ssl-common/glibc_compat.c" + COMMENT "Building glibc C23 compat shim (acvp-server)" +) +list(APPEND AWSLC_ACVP_SERVER_OBJS "${GLIBC_COMPAT_ACVP_OBJ}") + +set(AWSLC_ACVP_SERVER_LIB "${ACVP_OBJ_DIR}/libawslc_acvp_server.a") +add_custom_command( + OUTPUT "${AWSLC_ACVP_SERVER_LIB}" + COMMAND ${CMAKE_AR} rcs "${AWSLC_ACVP_SERVER_LIB}" ${AWSLC_ACVP_SERVER_OBJS} + DEPENDS ${AWSLC_ACVP_SERVER_OBJS} + COMMENT "Archiving libawslc_acvp_server.a" +) +add_custom_target(awslc_acvp_server_lib DEPENDS "${AWSLC_ACVP_SERVER_LIB}") + +set(CLICKHOUSE_ACVP_SERVER_SOURCES AcvpServer.cpp) +find_file(LIBSTDCXX_STATIC_ACVP libstdc++.a + PATHS /usr/lib/gcc/x86_64-linux-gnu + PATH_SUFFIXES 13 12 11 + NO_DEFAULT_PATH +) +if(NOT LIBSTDCXX_STATIC_ACVP) + message(FATAL_ERROR "Could not find static libstdc++.a needed for acvp-server") +endif() + +set(CLICKHOUSE_ACVP_SERVER_LINK + PRIVATE + "${AWSLC_ACVP_SERVER_LIB}" + "${AWSLC_LIBCRYPTO}" + "${LIBSTDCXX_STATIC_ACVP}" +) +set(CLICKHOUSE_ACVP_SERVER_INCLUDE PRIVATE ${AWSLC_SRC_DIR}/include) + +clickhouse_program_add(acvp-server) +add_dependencies(clickhouse-acvp-server-lib awslc_acvp_server_lib build-awslc) +target_compile_options(clickhouse-acvp-server-lib PRIVATE -Wno-everything) +target_link_options(clickhouse-acvp-server-lib INTERFACE "LINKER:--allow-multiple-definition") diff --git a/programs/config_tools.h.in b/programs/config_tools.h.in index 11689cf346f9..c9e87a938f3c 100644 --- a/programs/config_tools.h.in +++ b/programs/config_tools.h.in @@ -5,3 +5,6 @@ #cmakedefine01 ENABLE_CLICKHOUSE_KEEPER #cmakedefine01 ENABLE_CLICKHOUSE_KEEPER_CLIENT #cmakedefine01 ENABLE_CLICKHOUSE_KEEPER_CONVERTER +#cmakedefine01 ENABLE_CLICKHOUSE_SSL_SHIM +#cmakedefine01 ENABLE_CLICKHOUSE_SSL_HANDSHAKER +#cmakedefine01 ENABLE_CLICKHOUSE_ACVP_SERVER diff --git a/programs/main.cpp b/programs/main.cpp index 4240778f768f..8db9ca3c50cf 100644 --- a/programs/main.cpp +++ b/programs/main.cpp @@ -64,6 +64,16 @@ int mainEntryClickHouseKeeperBench(int argc, char ** argv); int mainEntryClickHouseKeeperDataDumper(int argc, char ** argv); #endif +#if ENABLE_CLICKHOUSE_SSL_SHIM +int mainEntryClickHouseSslShim(int argc, char ** argv); +#endif +#if ENABLE_CLICKHOUSE_SSL_HANDSHAKER +int mainEntryClickHouseSslHandshaker(int argc, char ** argv); +#endif +#if ENABLE_CLICKHOUSE_ACVP_SERVER +int mainEntryClickHouseAcvpServer(int argc, char ** argv); +#endif + // install int mainEntryClickHouseInstall(int argc, char ** argv); int mainEntryClickHouseStart(int argc, char ** argv); @@ -115,6 +125,15 @@ std::pair clickhouse_applications[] = #endif #if USE_NURAFT {"keeper-data-dumper", mainEntryClickHouseKeeperDataDumper}, +#endif +#if ENABLE_CLICKHOUSE_SSL_SHIM + {"ssl-shim", mainEntryClickHouseSslShim}, +#endif +#if ENABLE_CLICKHOUSE_SSL_HANDSHAKER + {"ssl-handshaker", mainEntryClickHouseSslHandshaker}, +#endif +#if ENABLE_CLICKHOUSE_ACVP_SERVER + {"acvp-server", mainEntryClickHouseAcvpServer}, #endif // install {"install", mainEntryClickHouseInstall}, diff --git a/programs/ssl-common/glibc_compat.c b/programs/ssl-common/glibc_compat.c new file mode 100644 index 000000000000..25348621262f --- /dev/null +++ b/programs/ssl-common/glibc_compat.c @@ -0,0 +1,15 @@ +#include + +/* glibc 2.32+ symbol used by libstdc++; sysroot may have older libc. */ +__attribute__((weak)) +char __libc_single_threaded = 0; + +__attribute__((weak)) +unsigned long long __isoc23_strtoull(const char *nptr, char **endptr, int base) { + return strtoull(nptr, endptr, base); +} + +__attribute__((weak)) +long long __isoc23_strtoll(const char *nptr, char **endptr, int base) { + return strtoll(nptr, endptr, base); +} diff --git a/programs/ssl-handshaker/CMakeLists.txt b/programs/ssl-handshaker/CMakeLists.txt new file mode 100644 index 000000000000..8a969bc55f7a --- /dev/null +++ b/programs/ssl-handshaker/CMakeLists.txt @@ -0,0 +1,105 @@ +if(NOT FIPS_CLICKHOUSE OR NOT DEFINED AWSLC_SRC_DIR) + return() +endif() + +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") + return() +endif() + +set(AWSLC_SSL_TEST_DIR "${AWSLC_SRC_DIR}/ssl/test") +set(AWSLC_LIBSSL "${CMAKE_BINARY_DIR}/awslc-build/output/libssl.a") +set(AWSLC_LIBCRYPTO "${CMAKE_BINARY_DIR}/awslc-build/output/libcrypto.a") + +set(HSHAKER_OBJ_DIR "${CMAKE_CURRENT_BINARY_DIR}/awslc_handshaker_objs") + +set(AWSLC_HSHAKER_CXX_SRCS + ${AWSLC_SSL_TEST_DIR}/async_bio.cc + ${AWSLC_SSL_TEST_DIR}/handshake_util.cc + ${AWSLC_SSL_TEST_DIR}/handshaker.cc + ${AWSLC_SSL_TEST_DIR}/mock_quic_transport.cc + ${AWSLC_SSL_TEST_DIR}/packeted_bio.cc + ${AWSLC_SSL_TEST_DIR}/settings_writer.cc + ${AWSLC_SSL_TEST_DIR}/test_config.cc + ${AWSLC_SSL_TEST_DIR}/test_state.cc + ${AWSLC_SRC_DIR}/crypto/test/test_util.cc +) + +set(AWSLC_HSHAKER_INCLUDE_FLAGS + -I${AWSLC_SRC_DIR}/include + -I${AWSLC_SRC_DIR} + -I${AWSLC_SSL_TEST_DIR} +) + +set(AWSLC_HSHAKER_OBJS) +foreach(src ${AWSLC_HSHAKER_CXX_SRCS}) + get_filename_component(base "${src}" NAME_WE) + get_filename_component(dir "${src}" DIRECTORY) + string(MD5 dir_hash "${dir}") + string(SUBSTRING "${dir_hash}" 0 8 dir_tag) + set(obj "${HSHAKER_OBJ_DIR}/${base}_${dir_tag}.o") + + set(extra_defs "") + if("${base}" STREQUAL "handshaker") + set(extra_defs -Dmain=handshaker_main) + endif() + + add_custom_command( + OUTPUT "${obj}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${HSHAKER_OBJ_DIR}" + COMMAND /usr/bin/c++ + -std=c++17 -fPIC -g -O2 + ${AWSLC_HSHAKER_INCLUDE_FLAGS} + ${extra_defs} + -w + -c "${src}" + -o "${obj}" + DEPENDS "${src}" build-awslc + COMMENT "Building aws-lc handshaker object ${base}.cc (system C++ ABI)" + ) + list(APPEND AWSLC_HSHAKER_OBJS "${obj}") +endforeach() + +set(GLIBC_COMPAT_HS_OBJ "${HSHAKER_OBJ_DIR}/glibc_compat.o") +add_custom_command( + OUTPUT "${GLIBC_COMPAT_HS_OBJ}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${HSHAKER_OBJ_DIR}" + COMMAND /usr/bin/cc -fPIC -O2 -w + -c "${CMAKE_CURRENT_SOURCE_DIR}/../ssl-common/glibc_compat.c" + -o "${GLIBC_COMPAT_HS_OBJ}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ssl-common/glibc_compat.c" + COMMENT "Building glibc C23 compat shim (handshaker)" +) +list(APPEND AWSLC_HSHAKER_OBJS "${GLIBC_COMPAT_HS_OBJ}") + +set(AWSLC_HSHAKER_LIB "${HSHAKER_OBJ_DIR}/libawslc_handshaker.a") +add_custom_command( + OUTPUT "${AWSLC_HSHAKER_LIB}" + COMMAND ${CMAKE_AR} rcs "${AWSLC_HSHAKER_LIB}" ${AWSLC_HSHAKER_OBJS} + DEPENDS ${AWSLC_HSHAKER_OBJS} + COMMENT "Archiving libawslc_handshaker.a" +) +add_custom_target(awslc_handshaker_lib DEPENDS "${AWSLC_HSHAKER_LIB}") + +set(CLICKHOUSE_SSL_HANDSHAKER_SOURCES SslHandshaker.cpp) +find_file(LIBSTDCXX_STATIC_HS libstdc++.a + PATHS /usr/lib/gcc/x86_64-linux-gnu + PATH_SUFFIXES 13 12 11 + NO_DEFAULT_PATH +) +if(NOT LIBSTDCXX_STATIC_HS) + message(FATAL_ERROR "Could not find static libstdc++.a needed for ssl-handshaker") +endif() + +set(CLICKHOUSE_SSL_HANDSHAKER_LINK + PRIVATE + "${AWSLC_HSHAKER_LIB}" + "${AWSLC_LIBSSL}" + "${AWSLC_LIBCRYPTO}" + "${LIBSTDCXX_STATIC_HS}" +) +set(CLICKHOUSE_SSL_HANDSHAKER_INCLUDE PRIVATE ${AWSLC_SRC_DIR}/include) + +clickhouse_program_add(ssl-handshaker) +add_dependencies(clickhouse-ssl-handshaker-lib awslc_handshaker_lib build-awslc) +target_compile_options(clickhouse-ssl-handshaker-lib PRIVATE -Wno-everything) +target_link_options(clickhouse-ssl-handshaker-lib INTERFACE "LINKER:--allow-multiple-definition") diff --git a/programs/ssl-handshaker/SslHandshaker.cpp b/programs/ssl-handshaker/SslHandshaker.cpp new file mode 100644 index 000000000000..a86e927a7d47 --- /dev/null +++ b/programs/ssl-handshaker/SslHandshaker.cpp @@ -0,0 +1,6 @@ +extern int handshaker_main(int argc, char ** argv); + +int mainEntryClickHouseSslHandshaker(int argc, char ** argv) +{ + return handshaker_main(argc, argv); +} diff --git a/programs/ssl-shim/CMakeLists.txt b/programs/ssl-shim/CMakeLists.txt new file mode 100644 index 000000000000..57d1cec51934 --- /dev/null +++ b/programs/ssl-shim/CMakeLists.txt @@ -0,0 +1,120 @@ +if(NOT FIPS_CLICKHOUSE OR NOT DEFINED AWSLC_SRC_DIR) + return() +endif() + +set(AWSLC_SSL_TEST_DIR "${AWSLC_SRC_DIR}/ssl/test") +set(AWSLC_LIBSSL "${CMAKE_BINARY_DIR}/awslc-build/output/libssl.a") +set(AWSLC_LIBCRYPTO "${CMAKE_BINARY_DIR}/awslc-build/output/libcrypto.a") + +set(SHIM_OBJ_DIR "${CMAKE_CURRENT_BINARY_DIR}/awslc_shim_objs") + +set(AWSLC_SHIM_CXX_SRCS + ${AWSLC_SSL_TEST_DIR}/async_bio.cc + ${AWSLC_SSL_TEST_DIR}/bssl_shim.cc + ${AWSLC_SSL_TEST_DIR}/handshake_util.cc + ${AWSLC_SSL_TEST_DIR}/mock_quic_transport.cc + ${AWSLC_SSL_TEST_DIR}/packeted_bio.cc + ${AWSLC_SSL_TEST_DIR}/settings_writer.cc + ${AWSLC_SSL_TEST_DIR}/ssl_transfer.cc + ${AWSLC_SSL_TEST_DIR}/test_config.cc + ${AWSLC_SSL_TEST_DIR}/test_state.cc + ${AWSLC_SRC_DIR}/crypto/test/test_util.cc +) + +set(AWSLC_SHIM_INCLUDE_FLAGS + -I${AWSLC_SRC_DIR}/include + -I${AWSLC_SRC_DIR} + -I${AWSLC_SSL_TEST_DIR} +) + +# Build each aws-lc shim source file with the system compiler (matching +# the libstdc++ ABI of the Docker-built libssl.a / libcrypto.a). +# This avoids the libc++ ↔ libstdc++ C++ ABI mismatch for internal +# types like bssl::UniquePtr. +set(AWSLC_SHIM_OBJS) +foreach(src ${AWSLC_SHIM_CXX_SRCS}) + get_filename_component(base "${src}" NAME_WE) + get_filename_component(dir "${src}" DIRECTORY) + # Disambiguate files with same basename from different directories + string(MD5 dir_hash "${dir}") + string(SUBSTRING "${dir_hash}" 0 8 dir_tag) + set(obj "${SHIM_OBJ_DIR}/${base}_${dir_tag}.o") + + set(extra_defs "") + if("${base}" STREQUAL "bssl_shim") + set(extra_defs -Dmain=bssl_shim_main) + endif() + + add_custom_command( + OUTPUT "${obj}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${SHIM_OBJ_DIR}" + COMMAND /usr/bin/c++ + -std=c++17 -fPIC -g -O2 + ${AWSLC_SHIM_INCLUDE_FLAGS} + ${extra_defs} + -w + -c "${src}" + -o "${obj}" + DEPENDS "${src}" build-awslc + COMMENT "Building aws-lc shim object ${base}.cc (system C++ ABI)" + ) + list(APPEND AWSLC_SHIM_OBJS "${obj}") +endforeach() + +# Compile the glibc C23 compatibility shim (provides __isoc23_strtoll etc. +# which newer GCC/glibc emit but the ClickHouse sysroot's libc lacks). +set(GLIBC_COMPAT_OBJ "${SHIM_OBJ_DIR}/glibc_compat.o") +add_custom_command( + OUTPUT "${GLIBC_COMPAT_OBJ}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${SHIM_OBJ_DIR}" + COMMAND /usr/bin/cc -fPIC -O2 -w + -c "${CMAKE_CURRENT_SOURCE_DIR}/../ssl-common/glibc_compat.c" + -o "${GLIBC_COMPAT_OBJ}" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../ssl-common/glibc_compat.c" + COMMENT "Building glibc C23 compat shim" +) +list(APPEND AWSLC_SHIM_OBJS "${GLIBC_COMPAT_OBJ}") + +# Bundle all system-compiled objects into a static library +set(AWSLC_SHIM_LIB "${SHIM_OBJ_DIR}/libawslc_shim.a") +add_custom_command( + OUTPUT "${AWSLC_SHIM_LIB}" + COMMAND ${CMAKE_AR} rcs "${AWSLC_SHIM_LIB}" ${AWSLC_SHIM_OBJS} + DEPENDS ${AWSLC_SHIM_OBJS} + COMMENT "Archiving libawslc_shim.a" +) +add_custom_target(awslc_shim_lib DEPENDS "${AWSLC_SHIM_LIB}") + +# The CH-side entry point: only this file uses the ClickHouse toolchain. +# It contains a plain C-linkage function so there is no C++ ABI concern. +set(CLICKHOUSE_SSL_SHIM_SOURCES SslShim.cpp) +# The system-compiled shim objects use libstdc++ (matching the Docker-built +# libssl.a ABI). Link the full static libstdc++ to satisfy those symbols. +# The --allow-multiple-definition flag handles the few symbols that overlap +# between libstdc++ and ClickHouse's libc++/libcxxabi (e.g. std::exception). +find_file(LIBSTDCXX_STATIC libstdc++.a + PATHS /usr/lib/gcc/x86_64-linux-gnu + PATH_SUFFIXES 13 12 11 + NO_DEFAULT_PATH +) +if(NOT LIBSTDCXX_STATIC) + message(FATAL_ERROR "Could not find static libstdc++.a needed for ssl-shim") +endif() + +set(CLICKHOUSE_SSL_SHIM_LINK + PRIVATE + "${AWSLC_SHIM_LIB}" + "${AWSLC_LIBSSL}" + "${AWSLC_LIBCRYPTO}" + "${LIBSTDCXX_STATIC}" +) +set(CLICKHOUSE_SSL_SHIM_INCLUDE PRIVATE ${AWSLC_SRC_DIR}/include) + +clickhouse_program_add(ssl-shim) +add_dependencies(clickhouse-ssl-shim-lib awslc_shim_lib build-awslc) +target_compile_options(clickhouse-ssl-shim-lib PRIVATE -Wno-everything) +# The system-compiled shim objects use libstdc++ (matching the Docker-built +# libssl.a ABI), which creates a few duplicate symbols with ClickHouse's +# libc++/libcxxabi (e.g. std::exception). Propagate via INTERFACE so the +# flag only enters the link when this target is actually consumed. +target_link_options(clickhouse-ssl-shim-lib INTERFACE "LINKER:--allow-multiple-definition") diff --git a/programs/ssl-shim/SslShim.cpp b/programs/ssl-shim/SslShim.cpp new file mode 100644 index 000000000000..a96e97c3a8ad --- /dev/null +++ b/programs/ssl-shim/SslShim.cpp @@ -0,0 +1,6 @@ +extern int bssl_shim_main(int argc, char ** argv); + +int mainEntryClickHouseSslShim(int argc, char ** argv) +{ + return bssl_shim_main(argc, argv); +}