Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 140 additions & 11 deletions base/glibc-compatibility/musl/posix_spawn.c
Original file line number Diff line number Diff line change
@@ -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 <spawn.h> 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 <spawn.h>
Expand All @@ -9,12 +21,24 @@
#include <fcntl.h>
#include <sys/wait.h>
#include <syscall.h>
#include <sys/signal.h>
#include <pthread.h>
#include <spawn.h>
#include <errno.h>
#include <limits.h>
#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;
Expand All @@ -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 --
Expand All @@ -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);
}

Expand All @@ -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;
Expand All @@ -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]);
Expand All @@ -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;
Expand Down
28 changes: 28 additions & 0 deletions programs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 ()
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions programs/acvp-server/AcvpServer.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
96 changes: 96 additions & 0 deletions programs/acvp-server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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")
3 changes: 3 additions & 0 deletions programs/config_tools.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading
Loading