summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.ci/woodpecker/01-build.yaml111
-rw-r--r--.ci/woodpecker/10-build.yaml100
-rw-r--r--.ci/woodpecker/20-sanitizer.yaml40
-rw-r--r--cmake/config/irmd.cmake4
-rw-r--r--include/ouroboros/crypt.h5
-rw-r--r--include/ouroboros/irm.h6
-rw-r--r--include/test/test.h6
-rw-r--r--src/ipcpd/local/main.c15
-rw-r--r--src/ipcpd/unicast/dir/dht.c4
-rw-r--r--src/ipcpd/unicast/dt.c2
-rw-r--r--src/ipcpd/unicast/fa.c4
-rw-r--r--src/ipcpd/unicast/routing/graph.c44
-rw-r--r--src/irmd/config.h.in1
-rw-r--r--src/irmd/main.c303
-rw-r--r--src/irmd/oap.c130
-rw-r--r--src/irmd/oap/auth.c4
-rw-r--r--src/irmd/oap/cli.c5
-rw-r--r--src/irmd/oap/srv.c2
-rw-r--r--src/irmd/oap/tests/oap_test.c72
-rw-r--r--src/irmd/oap/tests/oap_test_ml_dsa.c1
-rw-r--r--src/irmd/reg/flow.c35
-rw-r--r--src/irmd/reg/flow.h14
-rw-r--r--src/irmd/reg/reg.c209
-rw-r--r--src/irmd/reg/reg.h13
-rw-r--r--src/irmd/reg/tests/flow_test.c55
-rw-r--r--src/irmd/reg/tests/reg_test.c189
-rw-r--r--src/lib/crypt.c7
-rw-r--r--src/lib/crypt/openssl.c44
-rw-r--r--src/lib/crypt/openssl.h2
-rw-r--r--src/lib/irm.c2
-rw-r--r--src/lib/protobuf.c6
-rw-r--r--src/lib/ssm/pool.c6
-rw-r--r--src/lib/ssm/tests/pool_sharding_test.c5
-rw-r--r--src/lib/tests/auth_test.c55
-rw-r--r--src/lib/tests/kex_test.c14
-rw-r--r--src/lib/tests/kex_test_ml_kem.c18
-rw-r--r--src/tools/oping/oping.c15
-rw-r--r--src/tools/oping/oping_client.c122
-rw-r--r--src/tools/oping/oping_server.c68
39 files changed, 1175 insertions, 563 deletions
diff --git a/.ci/woodpecker/01-build.yaml b/.ci/woodpecker/01-build.yaml
deleted file mode 100644
index f8109c94..00000000
--- a/.ci/woodpecker/01-build.yaml
+++ /dev/null
@@ -1,111 +0,0 @@
-matrix:
- IMAGE:
- - dstaesse/debian:o7s
- - dstaesse/ubuntu:o7s
- FLAGS:
- - ''
- - -m32
- COMPILER:
- - clang
- - gcc
- BUILD_TYPE:
- - Debug
- - Release
- DISABLE_FUSE:
- - TRUE
- - FALSE
- DISABLE_OPENSSL:
- - TRUE
- - FALSE
- DISABLE_LIBGCRYPT:
- - TRUE
- - FALSE
- SANITIZER:
- - DebugASan
- - DebugUSan
- - DebugLSan
-
-steps:
- - name: build
- image: ${IMAGE}
- pull: true
- when:
- branch: [testing, be]
- event: [push, pull_request]
- commands:
- - apt-get update -y
- - apt-get install bash clang -y
- - apt-get install git protobuf-c-compiler cmake -y
- - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
- - apt-get install libprotobuf-c-dev -y || true
- - mkdir build
- - cd build
- - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DDISABLE_FUSE=${DISABLE_FUSE} \
- -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT}
- - make CFLAGS="${FLAGS}" -s -j2
- - env CTEST_OUTPUT_ON_FAILURE=1 make CFLAGS="${FLAGS}" -s check
- - cd ..
- - rm -rf build
-
- - name: sanitizers
- image: ${IMAGE}
- pull: true
- when:
- branch: [testing, be]
- event: [push, pull_request]
- commands:
- - apt-get update -y
- - apt-get install bash clang -y
- - apt-get install git protobuf-c-compiler cmake -y
- - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
- - apt-get install libprotobuf-c-dev -y || true
- - mkdir build
- - cd build
- - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${SANITIZER} -DDISABLE_FUSE=${DISABLE_FUSE} \
- -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT} \
- - make -s -j2
- - env CTEST_OUTPUT_ON_FAILURE=1 make -s check
- - cd ..
- - rm -rf build
-
- - name: build (manual)
- image: ${IMAGE}
- pull: true
- when:
- event: manual
- commands:
- - apt-get update -y
- - apt-get install bash clang -y
- - apt-get install git protobuf-c-compiler cmake -y
- - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
- - apt-get install libprotobuf-c-dev -y || true
- - mkdir build
- - cd build
- - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DDISABLE_FUSE=${DISABLE_FUSE} \
- -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT}
- - make CFLAGS="${FLAGS}" -s -j2
- - env CTEST_OUTPUT_ON_FAILURE=1 make CFLAGS="${FLAGS}" -s check
- - cd ..
- - rm -rf build
-
- - name: sanitizers (manual)
- image: ${IMAGE}
- pull: true
- when:
- event: manual
- commands:
- - apt-get update -y
- - apt-get install bash clang -y
- - apt-get install git protobuf-c-compiler cmake -y
- - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
- - apt-get install libprotobuf-c-dev -y || true
- - mkdir build
- - cd build
- - CC=${COMPILER} cmake .. -DCMAKE_BUILD_TYPE=${SANITIZER} -DDISABLE_FUSE=${DISABLE_FUSE} \
- -DDISABLE_OPENSSL=${DISABLE_OPENSSL} -DDISABLE_LIBGCRYPT=${DISABLE_LIBGCRYPT} \
- - make -s -j2
- - env CTEST_OUTPUT_ON_FAILURE=1 make -s check
- - cd ..
- - rm -rf build
-
-
diff --git a/.ci/woodpecker/10-build.yaml b/.ci/woodpecker/10-build.yaml
new file mode 100644
index 00000000..0a82c469
--- /dev/null
+++ b/.ci/woodpecker/10-build.yaml
@@ -0,0 +1,100 @@
+depends_on:
+ - 00-check-version
+
+matrix:
+ IMAGE:
+ - dstaesse/debian:o7s
+ - dstaesse/ubuntu:o7s
+ COMPILER:
+ - clang
+ - gcc
+
+steps:
+ - name: build
+ image: ${IMAGE}
+ pull: true
+ when:
+ - branch: be
+ event: [push, pull_request]
+ - event: manual
+ commands:
+ - apt-get update -y
+ - apt-get install bash clang -y
+ - apt-get install git protobuf-c-compiler cmake -y
+ - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
+ - apt-get install libprotobuf-c-dev -y || true
+ - |
+ set -e
+
+ run_build() {
+ mkdir build && cd build
+ CC=${COMPILER} cmake .. "$@"
+ make CFLAGS="${CFLAGS_EXTRA}" -s -j2
+ env CTEST_OUTPUT_ON_FAILURE=1 \
+ make CFLAGS="${CFLAGS_EXTRA}" -s check
+ cd .. && rm -rf build
+ }
+
+ for build_type in Release Debug; do
+ for flags in '' -m32; do
+ echo "--- ${COMPILER} $build_type $flags ---"
+ CFLAGS_EXTRA="$flags"
+ run_build \
+ -DCMAKE_BUILD_TYPE=$build_type
+ done
+ done
+
+ CFLAGS_EXTRA=""
+
+ for flow_stats in TRUE FALSE; do
+ echo "--- IPCP_FLOW_STATS=$flow_stats ---"
+ run_build \
+ -DIPCP_FLOW_STATS=$flow_stats
+ done
+
+ for disable_fuse in TRUE FALSE; do
+ echo "--- DISABLE_FUSE=$disable_fuse ---"
+ run_build \
+ -DDISABLE_FUSE=$disable_fuse
+ done
+
+ for disable_cf in TRUE FALSE; do
+ for build_type in Release Debug; do
+ echo "--- DISABLE_CONFIGFILE=$disable_cf $build_type ---"
+ run_build \
+ -DCMAKE_BUILD_TYPE=$build_type \
+ -DDISABLE_CONFIGFILE=$disable_cf
+ done
+ done
+
+ for disable_ddns in TRUE FALSE; do
+ for build_type in Release Debug; do
+ echo "--- DISABLE_DDNS=$disable_ddns $build_type ---"
+ run_build \
+ -DCMAKE_BUILD_TYPE=$build_type \
+ -DDISABLE_DDNS=$disable_ddns
+ done
+ done
+
+ for disable_ssl in TRUE FALSE; do
+ for disable_gc in TRUE FALSE; do
+ for build_type in Release Debug; do
+ echo "--- OPENSSL=$disable_ssl GCRYPT=$disable_gc $build_type ---"
+ run_build \
+ -DCMAKE_BUILD_TYPE=$build_type \
+ -DDISABLE_OPENSSL=$disable_ssl \
+ -DDISABLE_LIBGCRYPT=$disable_gc
+ done
+ done
+ done
+
+ for rxm_heap in TRUE FALSE; do
+ for rxm_block in TRUE FALSE; do
+ echo "--- HEAP=$rxm_heap BLOCKING=$rxm_block ---"
+ run_build \
+ -DRXM_BUFFER_ON_HEAP=$rxm_heap \
+ -DRXM_BLOCKING=$rxm_block
+ done
+ done
+
+
diff --git a/.ci/woodpecker/20-sanitizer.yaml b/.ci/woodpecker/20-sanitizer.yaml
new file mode 100644
index 00000000..b3d9f6af
--- /dev/null
+++ b/.ci/woodpecker/20-sanitizer.yaml
@@ -0,0 +1,40 @@
+depends_on:
+ - 00-check-version
+
+matrix:
+ IMAGE:
+ - dstaesse/debian:o7s
+ - dstaesse/ubuntu:o7s
+ COMPILER:
+ - clang
+ - gcc
+
+steps:
+ - name: sanitizers
+ image: ${IMAGE}
+ pull: true
+ when:
+ - branch: be
+ event: [push, pull_request]
+ - event: manual
+ commands:
+ - apt-get update -y
+ - apt-get install bash clang -y
+ - apt-get install git protobuf-c-compiler cmake -y
+ - apt-get install libgcrypt20-dev libssl-dev libfuse-dev dnsutils cmake-curses-gui -y
+ - apt-get install libprotobuf-c-dev -y || true
+ - |
+ set -e
+
+ for sanitizer in DebugASan DebugUSan DebugLSan; do
+ echo "--- ${COMPILER} $sanitizer ---"
+ mkdir build && cd build
+ CC=${COMPILER} cmake .. \
+ -DCMAKE_BUILD_TYPE=$sanitizer
+ make -s -j2
+ env CTEST_OUTPUT_ON_FAILURE=1 \
+ make -s check
+ cd .. && rm -rf build
+ done
+
+
diff --git a/cmake/config/irmd.cmake b/cmake/config/irmd.cmake
index 9795e4a4..b86a40c5 100644
--- a/cmake/config/irmd.cmake
+++ b/cmake/config/irmd.cmake
@@ -29,6 +29,10 @@ set(IRMD_MIN_THREADS 8 CACHE STRING
set(IRMD_ADD_THREADS 8 CACHE STRING
"Number of extra threads to start when the IRMD faces thread starvation")
+# Direct IPC
+set(DISABLE_DIRECT_IPC FALSE CACHE BOOL
+ "Disable direct inter-process communication between local applications")
+
# Process management
set(IRMD_PKILL_TIMEOUT 30 CACHE STRING
"Number of seconds to wait before sending SIGKILL to subprocesses on exit")
diff --git a/include/ouroboros/crypt.h b/include/ouroboros/crypt.h
index 806d39ab..5e082bb9 100644
--- a/include/ouroboros/crypt.h
+++ b/include/ouroboros/crypt.h
@@ -33,7 +33,6 @@
#define MAX_HASH_SIZE 64 /* SHA-512/BLAKE2b max */
#define KEX_ALGO_BUFSZ 32
#define KEX_CIPHER_BUFSZ 32
-#define MSGBUFSZ 2048
/*
* On OSX the OpenSSL NIDs are automatically loaded with evp.h.
@@ -95,6 +94,8 @@
#define X448MLKEM1024_PKSZ 1624 /* 56 + 1568 */
#define X448MLKEM1024_SKSZ 3224 /* 56 + 3168 */
+#define CRYPT_KEY_BUFSZ 4096 /* Safe buffer for key material */
+
#define KEM_MODE_SERVER_ENCAP 0 /* Server encapsulates (default) */
#define KEM_MODE_CLIENT_ENCAP 1 /* Client encapsulates */
#define IS_KEX_ALGO_SET(cfg) ((cfg)->x.nid != NID_undef)
@@ -358,6 +359,8 @@ int crypt_check_crt_name(void * crt,
int crypt_get_crt_name(void * crt,
char * name);
+void crypt_cleanup(void);
+
/* Secure memory allocation for sensitive data (keys, secrets) */
int crypt_secure_malloc_init(size_t max);
diff --git a/include/ouroboros/irm.h b/include/ouroboros/irm.h
index d5e4f1ab..7cb71c21 100644
--- a/include/ouroboros/irm.h
+++ b/include/ouroboros/irm.h
@@ -53,13 +53,13 @@ int irm_bootstrap_ipcp(pid_t pid,
const struct ipcp_config * conf);
int irm_connect_ipcp(pid_t pid,
- const char * component,
const char * dst,
+ const char * component,
qosspec_t qs);
int irm_disconnect_ipcp(pid_t pid,
- const char * component,
- const char * dst);
+ const char * dst,
+ const char * component);
int irm_bind_program(const char * prog,
const char * name,
diff --git a/include/test/test.h b/include/test/test.h
index 99681384..a76fe62a 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -30,6 +30,9 @@
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/resource.h>
+#ifdef __linux__
+#include <sys/prctl.h>
+#endif
#define TEST_RC_SUCCESS 0
#define TEST_RC_SKIP 1
@@ -86,6 +89,9 @@ static int __attribute__((unused)) test_assert_fail(int(* testfunc)(void))
#ifdef DISABLE_TESTS_CORE_DUMPS
struct rlimit rl = { .rlim_cur = 0, .rlim_max = 0 };
setrlimit(RLIMIT_CORE, &rl);
+#ifdef __linux__
+ prctl(PR_SET_DUMPABLE, 0);
+#endif
#endif
return testfunc(); /* should abort */
}
diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c
index 377a7df3..2c867317 100644
--- a/src/ipcpd/local/main.c
+++ b/src/ipcpd/local/main.c
@@ -236,15 +236,6 @@ static int local_ipcp_flow_alloc_resp(int fd,
return -1;
}
- if (response < 0) {
- pthread_rwlock_wrlock(&local_data.lock);
- if (local_data.in_out[fd] != -1)
- local_data.in_out[local_data.in_out[fd]] = fd;
- local_data.in_out[fd] = -1;
- pthread_rwlock_unlock(&local_data.lock);
- return 0;
- }
-
pthread_rwlock_rdlock(&local_data.lock);
out_fd = local_data.in_out[fd];
@@ -263,6 +254,12 @@ static int local_ipcp_flow_alloc_resp(int fd,
return -1;
}
+ if (response < 0) {
+ ipcp_flow_alloc_reply(out_fd, response, mpl, data);
+ log_info("Flow allocation rejected, fds (%d, %d).", out_fd, fd);
+ return 0;
+ }
+
fset_add(local_data.flows, fd);
if (ipcp_flow_alloc_reply(out_fd, response, mpl, data) < 0) {
diff --git a/src/ipcpd/unicast/dir/dht.c b/src/ipcpd/unicast/dir/dht.c
index bc8fb820..8eeea800 100644
--- a/src/ipcpd/unicast/dir/dht.c
+++ b/src/ipcpd/unicast/dir/dht.c
@@ -2798,8 +2798,6 @@ static void do_dht_kv_store(const dht_store_msg_t * store)
uint8_t * key;
time_t exp;
- (void) key; /* Only in logs, not used with DISABLE_TEST_LOGGING */
-
assert(store != NULL);
val.data = store->val.data;
@@ -2807,7 +2805,7 @@ static void do_dht_kv_store(const dht_store_msg_t * store)
key = store->key.data;
exp = store->exp;
- if (dht_kv_store(store->key.data, val, store->exp) < 0) {
+ if (dht_kv_store(key, val, store->exp) < 0) {
log_err(KV_FMT " Failed to store.", KV_VAL(key, val));
return;
}
diff --git a/src/ipcpd/unicast/dt.c b/src/ipcpd/unicast/dt.c
index 7ce09bde..252477f4 100644
--- a/src/ipcpd/unicast/dt.c
+++ b/src/ipcpd/unicast/dt.c
@@ -820,9 +820,9 @@ int dt_write_packet(uint64_t dst_addr,
assert(spb);
assert(dst_addr != dt.addr);
+#ifdef IPCP_FLOW_STATS
len = ssm_pk_buff_len(spb);
-#ifdef IPCP_FLOW_STATS
if (eid < PROG_RES_FDS) {
pthread_mutex_lock(&dt.stat[eid].lock);
diff --git a/src/ipcpd/unicast/fa.c b/src/ipcpd/unicast/fa.c
index ddf78e22..c157d71c 100644
--- a/src/ipcpd/unicast/fa.c
+++ b/src/ipcpd/unicast/fa.c
@@ -58,12 +58,12 @@
#define CLOCK_REALTIME_COARSE CLOCK_REALTIME
#endif
-#define TIMEOUT 10 * MILLION /* nanoseconds */
+#define TIMEOUT 10 * MILLION /* nanoseconds */
+#define MSGBUFSZ 32768
#define FLOW_REQ 0
#define FLOW_REPLY 1
#define FLOW_UPDATE 2
-#define MSGBUFSZ 2048
#define STAT_FILE_LEN 0
diff --git a/src/ipcpd/unicast/routing/graph.c b/src/ipcpd/unicast/routing/graph.c
index 13939915..0226c762 100644
--- a/src/ipcpd/unicast/routing/graph.c
+++ b/src/ipcpd/unicast/routing/graph.c
@@ -160,11 +160,22 @@ static struct vertex * add_vertex(struct graph * graph,
return vertex;
}
+static void free_edges(struct list_head * edges)
+{
+ struct list_head * p;
+ struct list_head * h;
+
+ list_for_each_safe(p, h, edges) {
+ struct edge * e = list_entry(p, struct edge, next);
+ list_del(&e->next);
+ free(e);
+ }
+}
+
static void del_vertex(struct graph * graph,
struct vertex * vertex)
{
struct list_head * p;
- struct list_head * h;
assert(graph != NULL);
assert(vertex != NULL);
@@ -178,10 +189,7 @@ static void del_vertex(struct graph * graph,
v->index--;
}
- list_for_each_safe(p, h, &vertex->edges) {
- struct edge * e = list_entry(p, struct edge, next);
- del_edge(e);
- }
+ free_edges(&vertex->edges);
free(vertex);
}
@@ -687,7 +695,6 @@ static int graph_routing_table_ecmp(struct graph * graph,
{
struct vertex ** nhops;
struct list_head * p;
- struct list_head * h;
size_t i;
struct vertex * v;
struct vertex * src_v;
@@ -727,16 +734,15 @@ static int graph_routing_table_ecmp(struct graph * graph,
free(nhops);
- llist_for_each(h, &graph->vertices) {
- v = list_entry(h, struct vertex, next);
- if (tmp_dist[v->index] + 1 == (*dist)[v->index]) {
+ for (i = 0; i < graph->vertices.len; ++i) {
+ if (tmp_dist[i] + 1 == (*dist)[i]) {
n = malloc(sizeof(*n));
if (n == NULL) {
free(tmp_dist);
goto fail_src_v;
}
n->nhop = e->nb->addr;
- list_add_tail(&n->next, &forwarding[v->index]);
+ list_add_tail(&n->next, &forwarding[i]);
}
}
@@ -747,36 +753,32 @@ static int graph_routing_table_ecmp(struct graph * graph,
i = 0;
llist_for_each(p, &graph->vertices) {
v = list_entry(p, struct vertex, next);
- if (v->addr == s_addr) {
+ if (v->addr == s_addr || list_is_empty(&forwarding[i])) {
++i;
continue;
}
t = malloc(sizeof(*t));
if (t == NULL)
- goto fail_t;
+ goto fail_malloc;
t->dst = v->addr;
list_head_init(&t->nhops);
- if (&forwarding[i] != forwarding[i].nxt) {
- t->nhops.nxt = forwarding[i].nxt;
- t->nhops.prv = forwarding[i].prv;
- forwarding[i].prv->nxt = &t->nhops;
- forwarding[i].nxt->prv = &t->nhops;
- }
+ t->nhops.nxt = forwarding[i].nxt;
+ t->nhops.prv = forwarding[i].prv;
+ forwarding[i].prv->nxt = &t->nhops;
+ forwarding[i].nxt->prv = &t->nhops;
list_add(&t->next, table);
++i;
}
- free(*dist);
- *dist = NULL;
free(forwarding);
return 0;
- fail_t:
+ fail_malloc:
free_routing_table(table);
fail_src_v:
free(*dist);
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index 2888ce37..df0cd718 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -74,6 +74,7 @@
#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
+#cmakedefine DISABLE_DIRECT_IPC
#cmakedefine IRMD_KILL_ALL_PROCESSES
#cmakedefine HAVE_LIBGCRYPT
#cmakedefine HAVE_OPENSSL
diff --git a/src/irmd/main.c b/src/irmd/main.c
index c7a5715b..a85a9bf0 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -86,6 +86,7 @@
#define TIMESYNC_SLACK 100 /* ms */
#define OAP_SEEN_TIMER 20 /* s */
#define DEALLOC_TIME 300 /* s */
+#define DIRECT_MPL 1 /* s */
enum irm_state {
IRMD_NULL = 0,
@@ -914,21 +915,29 @@ static int flow_accept(struct flow_info * flow,
goto fail_oap;
}
- if (ipcp_flow_alloc_resp(flow, 0, resp_hdr) < 0) {
+ if (reg_flow_is_direct(flow->id)) {
+ if (reg_respond_flow_direct(flow->id, &resp_hdr) < 0) {
+ log_err("Failed to respond to direct flow.");
+ goto fail_resp;
+ }
+ log_info("Flow %d accepted (direct) by %d for %s.",
+ flow->id, flow->n_pid, name);
+ } else if (ipcp_flow_alloc_resp(flow, 0, resp_hdr) < 0) {
log_err("Failed to respond to flow allocation.");
goto fail_resp;
+ } else {
+ log_info("Flow %d accepted by %d for %s (uid %d).",
+ flow->id, flow->n_pid, name, flow->uid);
}
- log_info("Flow %d accepted by %d for %s (uid %d).",
- flow->id, flow->n_pid, name, flow->uid);
-
freebuf(req_hdr);
freebuf(resp_hdr);
return 0;
fail_oap:
- ipcp_flow_alloc_resp(flow, err, resp_hdr);
+ if (!reg_flow_is_direct(flow->id))
+ ipcp_flow_alloc_resp(flow, err, resp_hdr);
fail_wait:
reg_destroy_flow(flow->id);
fail_flow:
@@ -1028,7 +1037,7 @@ static int get_ipcp_by_dst(const char * dst,
pid_t * pid,
buffer_t * hash)
{
- ipcp_list_msg_t ** ipcps;
+ ipcp_list_msg_t ** ipcps = NULL;
int n;
int i;
int err = -EIPCP;
@@ -1081,6 +1090,171 @@ static int get_ipcp_by_dst(const char * dst,
return err;
}
+static int wait_for_accept(const char * name)
+{
+ struct timespec timeo = TIMESPEC_INIT_MS(IRMD_REQ_ARR_TIMEOUT);
+ struct timespec abstime;
+ char ** exec;
+ int ret;
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+ ts_add(&abstime, &timeo, &abstime);
+
+ ret = reg_wait_flow_accepting(name, &abstime);
+ if (ret == -ETIMEDOUT) {
+ if (reg_get_exec(name, &exec) < 0) {
+ log_dbg("No program bound for %s.", name);
+ goto fail;
+ }
+
+ if (spawn_program(exec) < 0) {
+ log_err("Failed to start %s for %s.", exec[0], name);
+ goto fail_spawn;
+ }
+
+ log_info("Starting %s for %s.", exec[0], name);
+
+ ts_add(&abstime, &timeo, &abstime);
+
+ ret = reg_wait_flow_accepting(name, &abstime);
+ if (ret == -ETIMEDOUT)
+ goto fail_spawn;
+
+ argvfree(exec);
+ }
+
+ return ret;
+
+ fail_spawn:
+ argvfree(exec);
+ fail:
+ return -1;
+}
+
+static int flow_req_arr(struct flow_info * flow,
+ const uint8_t * hash,
+ buffer_t * data)
+{
+ struct ipcp_info info;
+ struct layer_info layer;
+ enum hash_algo algo;
+ int ret;
+ char name[NAME_SIZE + 1];
+
+ info.pid = flow->n_1_pid;
+
+ log_dbg("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
+ info.pid, HASH_VAL32(hash));
+
+ if (reg_get_ipcp(&info, &layer) < 0) {
+ log_err("No IPCP with pid %d.", info.pid);
+ ret = -EIPCP;
+ goto fail;
+ }
+
+ algo = (enum hash_algo) layer.dir_hash_algo;
+
+ if (reg_get_name_for_hash(name, algo, hash) < 0) {
+ log_warn("No name for " HASH_FMT32 ".", HASH_VAL32(hash));
+ ret = -ENAME;
+ goto fail;
+ }
+
+ log_info("Flow request arrived for %s.", name);
+
+ ret = wait_for_accept(name);
+ if (ret < 0) {
+ log_err("No active process for %s.", name);
+ goto fail;
+ }
+
+ flow->id = ret;
+ flow->state = FLOW_ALLOCATED;
+
+ ret = reg_respond_accept(flow, data);
+ if (ret < 0) {
+ log_err("Failed to respond to flow %d.", flow->id);
+ goto fail;
+ }
+
+ return 0;
+ fail:
+ return ret;
+}
+
+#ifndef DISABLE_DIRECT_IPC
+static int flow_alloc_direct(const char * dst,
+ struct flow_info * flow,
+ buffer_t * data,
+ struct timespec * abstime,
+ struct crypt_sk * sk,
+ struct name_info * info)
+{
+ struct flow_info acc; /* server side flow */
+ buffer_t req_hdr = BUF_INIT;
+ buffer_t resp_hdr = BUF_INIT;
+ void * ctx;
+ int err;
+
+ acc.id = wait_for_accept(dst);
+ if (acc.id < 0) {
+ log_dbg("No accepting process for %s.", dst);
+ return -EAGAIN;
+ }
+
+ if (oap_cli_prepare(&ctx, info, &req_hdr, *data) < 0) {
+ log_err("Failed to prepare OAP for %s.", dst);
+ return -EBADF;
+ }
+
+ acc.n_1_pid = flow->n_pid;
+ acc.mpl = DIRECT_MPL;
+ acc.qs = flow->qs;
+ acc.state = FLOW_ALLOCATED;
+
+ err = reg_prepare_flow_direct(&acc, &req_hdr, flow->uid);
+ if (err == -EPERM) {
+ log_dbg("UID mismatch, falling back.");
+ oap_ctx_free(ctx);
+ freebuf(req_hdr);
+ return -EPERM;
+ }
+
+ if (err < 0) {
+ log_err("Failed to prepare direct flow.");
+ oap_ctx_free(ctx);
+ freebuf(req_hdr);
+ return -EBADF;
+ }
+
+ err = reg_wait_flow_direct(acc.id, &resp_hdr, abstime);
+ if (err < 0) {
+ log_err("Timeout waiting for OAP response.");
+ oap_ctx_free(ctx);
+ return -ETIMEDOUT;
+ }
+
+ err = oap_cli_complete(ctx, info, resp_hdr, data, sk);
+ if (err < 0) {
+ log_err("OAP completion failed for %s.", dst);
+ freebuf(resp_hdr);
+ return err;
+ }
+
+ flow->id = acc.id;
+ flow->n_1_pid = acc.n_pid;
+ flow->mpl = DIRECT_MPL;
+ flow->state = FLOW_ALLOCATED;
+
+ log_info("Flow %d allocated (direct) for %d to %s.",
+ flow->id, flow->n_pid, dst);
+
+ freebuf(resp_hdr);
+
+ return 0;
+}
+#endif /* DISABLE_DIRECT_IPC */
+
static int flow_alloc(const char * dst,
struct flow_info * flow,
buffer_t * data,
@@ -1104,17 +1278,25 @@ static int flow_alloc(const char * dst,
goto fail_flow;
}
+ flow->uid = reg_get_proc_uid(flow->n_pid);
+
+ log_info("Allocating flow for %d to %s (uid %d).",
+ flow->n_pid, dst, flow->uid);
+
+#ifndef DISABLE_DIRECT_IPC
+ err = flow_alloc_direct(dst, flow, data, abstime, sk, &info);
+ if (err == 0)
+ return 0;
+
+ if (err != -EPERM && err != -EAGAIN)
+ goto fail_flow;
+#endif
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
goto fail_flow;
}
- flow->uid = reg_get_proc_uid(flow->n_pid);
-
- log_info("Allocating flow for %d to %s (uid %d).",
- flow->n_pid, dst, flow->uid);
-
if (get_ipcp_by_dst(dst, &flow->n_1_pid, &hash) < 0) {
log_err("Failed to find IPCP for %s.", dst);
err = -EIPCP;
@@ -1188,98 +1370,6 @@ static int flow_alloc(const char * dst,
return err;
}
-static int wait_for_accept(const char * name)
-{
- struct timespec timeo = TIMESPEC_INIT_MS(IRMD_REQ_ARR_TIMEOUT);
- struct timespec abstime;
- char ** exec;
- int ret;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
- ts_add(&abstime, &timeo, &abstime);
-
- ret = reg_wait_flow_accepting(name, &abstime);
- if (ret == -ETIMEDOUT) {
- if (reg_get_exec(name, &exec) < 0) {
- log_dbg("No program bound for %s.", name);
- goto fail;
- }
-
- if (spawn_program(exec) < 0) {
- log_err("Failed to start %s for %s.", exec[0], name);
- goto fail_spawn;
- }
-
- log_info("Starting %s for %s.", exec[0], name);
-
- ts_add(&abstime, &timeo, &abstime);
-
- ret = reg_wait_flow_accepting(name, &abstime);
- if (ret == -ETIMEDOUT)
- goto fail_spawn;
-
- argvfree(exec);
- }
-
- return ret;
-
- fail_spawn:
- argvfree(exec);
- fail:
- return -1;
-}
-
-static int flow_req_arr(struct flow_info * flow,
- const uint8_t * hash,
- buffer_t * data)
-{
- struct ipcp_info info;
- struct layer_info layer;
- enum hash_algo algo;
- int ret;
- char name[NAME_SIZE + 1];
-
- info.pid = flow->n_1_pid;
-
- log_dbg("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
- info.pid, HASH_VAL32(hash));
-
- if (reg_get_ipcp(&info, &layer) < 0) {
- log_err("No IPCP with pid %d.", info.pid);
- ret = -EIPCP;
- goto fail;
- }
-
- algo = (enum hash_algo) layer.dir_hash_algo;
-
- if (reg_get_name_for_hash(name, algo, hash) < 0) {
- log_warn("No name for " HASH_FMT32 ".", HASH_VAL32(hash));
- ret = -ENAME;
- goto fail;
- }
-
- log_info("Flow request arrived for %s.", name);
-
- ret = wait_for_accept(name);
- if (ret < 0) {
- log_err("No active process for %s.", name);
- goto fail;
- }
-
- flow->id = ret;
- flow->state = FLOW_ALLOCATED;
-
- ret = reg_respond_accept(flow, data);
- if (ret < 0) {
- log_err("Failed to respond to flow %d.", flow->id);
- goto fail;
- }
-
- return 0;
- fail:
- return ret;
-}
-
static int flow_alloc_reply(struct flow_info * flow,
int response,
buffer_t * data)
@@ -1303,6 +1393,12 @@ static int flow_dealloc(struct flow_info * flow,
reg_dealloc_flow(flow);
+ if (reg_flow_is_direct(flow->id)) {
+ if (flow->state == FLOW_DEALLOCATED)
+ reg_destroy_flow(flow->id);
+ return 0;
+ }
+
if (ipcp_flow_dealloc(flow->n_1_pid, flow->id, ts->tv_sec) < 0) {
log_err("Failed to request dealloc from %d.", flow->n_1_pid);
return -EIPCP;
@@ -2320,6 +2416,7 @@ int main(int argc,
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
crypt_secure_malloc_fini();
+ crypt_cleanup();
reg_clear();
diff --git a/src/irmd/oap.c b/src/irmd/oap.c
deleted file mode 100644
index 1831f533..00000000
--- a/src/irmd/oap.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Ouroboros - Copyright (C) 2016 - 2026
- *
- * OAP - Shared credential and configuration loading
- *
- * Dimitri Staessens <dimitri@ouroboros.rocks>
- * Sander Vrijders <sander@ouroboros.rocks>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., http://www.fsf.org/about/contact/.
- */
-
-#if defined(__linux__) || defined(__CYGWIN__)
- #define _DEFAULT_SOURCE
-#else
- #define _POSIX_C_SOURCE 200809L
-#endif
-
-#define OUROBOROS_PREFIX "irmd/oap"
-
-#include <ouroboros/crypt.h>
-#include <ouroboros/errno.h>
-#include <ouroboros/logs.h>
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/*
- * Shared credential and configuration loading helpers
- */
-
-#ifndef OAP_TEST_MODE
-
-static bool file_exists(const char * path)
-{
- struct stat s;
-
- if (stat(path, &s) < 0 && errno == ENOENT) {
- log_dbg("File %s does not exist.", path);
- return false;
- }
-
- return true;
-}
-
-int load_credentials(const char * name,
- const struct name_sec_paths * paths,
- void ** pkp,
- void ** crt)
-{
- assert(paths != NULL);
- assert(pkp != NULL);
- assert(crt != NULL);
-
- *pkp = NULL;
- *crt = NULL;
-
- if (!file_exists(paths->crt) || !file_exists(paths->key)) {
- log_info("No authentication certificates for %s.", name);
- return 0;
- }
-
- if (crypt_load_crt_file(paths->crt, crt) < 0) {
- log_err("Failed to load %s for %s.", paths->crt, name);
- goto fail_crt;
- }
-
- if (crypt_load_privkey_file(paths->key, pkp) < 0) {
- log_err("Failed to load %s for %s.", paths->key, name);
- goto fail_key;
- }
-
- log_info("Loaded authentication certificates for %s.", name);
-
- return 0;
-
- fail_key:
- crypt_free_crt(*crt);
- *crt = NULL;
- fail_crt:
- return -EAUTH;
-}
-
-int load_kex_config(const char * name,
- const char * path,
- struct sec_config * cfg)
-{
- assert(name != NULL);
- assert(cfg != NULL);
-
- memset(cfg, 0, sizeof(*cfg));
-
- /* Load encryption config */
- if (!file_exists(path))
- log_dbg("No encryption %s for %s.", path, name);
-
- if (load_sec_config_file(cfg, path) < 0) {
- log_warn("Failed to load %s for %s.", path, name);
- return -1;
- }
-
- if (!IS_KEX_ALGO_SET(cfg)) {
- log_info("Key exchange not configured for %s.", name);
- return 0;
- }
-
- if (cfg->c.nid == NID_undef || crypt_nid_to_str(cfg->c.nid) == NULL) {
- log_err("Invalid cipher NID %d for %s.", cfg->c.nid, name);
- return -ECRYPT;
- }
-
- log_info("Encryption enabled for %s.", name);
-
- return 0;
-}
-
-#endif /* OAP_TEST_MODE */
diff --git a/src/irmd/oap/auth.c b/src/irmd/oap/auth.c
index a11ab158..4b86f055 100644
--- a/src/irmd/oap/auth.c
+++ b/src/irmd/oap/auth.c
@@ -183,7 +183,7 @@ int oap_auth_peer(char * name,
const struct oap_hdr * peer_hdr)
{
void * crt;
- void * pk;
+ void * pk = NULL;
buffer_t sign; /* Signed region */
uint8_t * id = peer_hdr->id.data;
@@ -244,8 +244,8 @@ int oap_auth_peer(char * name,
return 0;
fail_check_sig:
- crypt_free_key(pk);
fail_crt:
+ crypt_free_key(pk);
crypt_free_crt(crt);
fail_check:
return -EAUTH;
diff --git a/src/irmd/oap/cli.c b/src/irmd/oap/cli.c
index 507f3f81..7a202da7 100644
--- a/src/irmd/oap/cli.c
+++ b/src/irmd/oap/cli.c
@@ -50,7 +50,7 @@
struct oap_cli_ctx {
uint8_t __id[OAP_ID_SIZE];
buffer_t id;
- uint8_t kex_buf[MSGBUFSZ];
+ uint8_t kex_buf[CRYPT_KEY_BUFSZ];
uint8_t req_hash[MAX_HASH_SIZE];
size_t req_hash_len;
int req_md_nid;
@@ -311,6 +311,9 @@ int oap_cli_prepare(void ** ctx,
*req_buf = s->local_hdr.hdr;
clrbuf(s->local_hdr.hdr);
+ /* oap_hdr_encode repoints id into hdr; restore to __id */
+ s->local_hdr.id = s->id;
+
crypt_free_crt(crt);
crypt_free_key(pkp);
diff --git a/src/irmd/oap/srv.c b/src/irmd/oap/srv.c
index 36391e50..afc54acc 100644
--- a/src/irmd/oap/srv.c
+++ b/src/irmd/oap/srv.c
@@ -384,7 +384,7 @@ int oap_srv_process(const struct name_info * info,
struct oap_hdr peer_hdr;
struct oap_hdr local_hdr;
struct sec_config kcfg;
- uint8_t kex_buf[MSGBUFSZ];
+ uint8_t kex_buf[CRYPT_KEY_BUFSZ];
uint8_t hash_buf[MAX_HASH_SIZE];
buffer_t req_hash = BUF_INIT;
ssize_t hash_ret;
diff --git a/src/irmd/oap/tests/oap_test.c b/src/irmd/oap/tests/oap_test.c
index 2f0f0b4d..a324b586 100644
--- a/src/irmd/oap/tests/oap_test.c
+++ b/src/irmd/oap/tests/oap_test.c
@@ -1071,6 +1071,74 @@ static int test_oap_replay_packet(void)
return TEST_RC_FAIL;
}
+/* Server rejects client certificate when root CA is missing from store */
+static int test_oap_missing_root_ca(void)
+{
+ struct oap_test_ctx ctx;
+ void * im_ca = NULL;
+
+ test_default_cfg();
+
+ TEST_START();
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ strcpy(ctx.srv.info.name, "test-1.unittest.o7s");
+ strcpy(ctx.cli.info.name, "test-1.unittest.o7s");
+
+ if (oap_auth_init() < 0) {
+ printf("Failed to init OAP.\n");
+ goto fail;
+ }
+
+ /* Load intermediate CA but intentionally omit the root CA */
+ if (crypt_load_crt_str(im_ca_crt_ec, &im_ca) < 0) {
+ printf("Failed to load intermediate CA cert.\n");
+ goto fail_fini;
+ }
+
+ ctx.im_ca = im_ca;
+
+ if (oap_auth_add_ca_crt(im_ca) < 0) {
+ printf("Failed to add intermediate CA cert to store.\n");
+ goto fail_fini;
+ }
+
+ if (oap_cli_prepare_ctx(&ctx) < 0) {
+ printf("Client prepare failed.\n");
+ goto fail_fini;
+ }
+
+ /* Server processes and signs response - succeeds without root CA */
+ if (oap_srv_process_ctx(&ctx) < 0) {
+ printf("Server process failed.\n");
+ goto fail_teardown;
+ }
+
+ /* Client verifies server certificate against trust store:
+ * should reject because root CA is not in the store */
+ if (oap_cli_complete_ctx(&ctx) == 0) {
+ printf("Client should reject without root CA.\n");
+ goto fail_teardown;
+ }
+
+ oap_test_teardown(&ctx);
+
+ TEST_SUCCESS();
+ return TEST_RC_SUCCESS;
+
+ fail_teardown:
+ oap_test_teardown(&ctx);
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+ fail_fini:
+ crypt_free_crt(im_ca);
+ oap_auth_fini();
+ fail:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
/* Test that client rejects server with wrong certificate name */
static int test_oap_server_name_mismatch(void)
{
@@ -1149,6 +1217,7 @@ int oap_test(int argc,
ret |= test_oap_outdated_packet();
ret |= test_oap_future_packet();
ret |= test_oap_replay_packet();
+ ret |= test_oap_missing_root_ca();
ret |= test_oap_server_name_mismatch();
#else
(void) test_oap_roundtrip_auth_only;
@@ -1173,9 +1242,12 @@ int oap_test(int argc,
(void) test_oap_outdated_packet;
(void) test_oap_future_packet;
(void) test_oap_replay_packet;
+ (void) test_oap_missing_root_ca;
(void) test_oap_server_name_mismatch;
ret = TEST_RC_SKIP;
#endif
+ crypt_cleanup();
+
return ret;
}
diff --git a/src/irmd/oap/tests/oap_test_ml_dsa.c b/src/irmd/oap/tests/oap_test_ml_dsa.c
index f9e6bdb2..81b307ab 100644
--- a/src/irmd/oap/tests/oap_test_ml_dsa.c
+++ b/src/irmd/oap/tests/oap_test_ml_dsa.c
@@ -442,6 +442,7 @@ int oap_test_ml_dsa(int argc,
ret = TEST_RC_SKIP;
#endif
+ crypt_cleanup();
return ret;
}
diff --git a/src/irmd/reg/flow.c b/src/irmd/reg/flow.c
index 15497d35..93c3e128 100644
--- a/src/irmd/reg/flow.c
+++ b/src/irmd/reg/flow.c
@@ -80,7 +80,7 @@ void reg_flow_destroy(struct reg_flow * flow)
switch(flow->info.state) {
case FLOW_ACCEPT_PENDING:
- clrbuf(flow->data);
+ clrbuf(flow->req_data);
/* FALLTHRU */
default:
destroy_rbuffs(flow);
@@ -89,8 +89,10 @@ void reg_flow_destroy(struct reg_flow * flow)
assert(flow->n_rb == NULL);
assert(flow->n_1_rb == NULL);
- assert(flow->data.data == NULL);
- assert(flow->data.len == 0);
+ assert(flow->req_data.data == NULL);
+ assert(flow->req_data.len == 0);
+ assert(flow->rsp_data.data == NULL);
+ assert(flow->rsp_data.len == 0);
assert(list_is_empty(&flow->next));
@@ -186,30 +188,3 @@ int reg_flow_update(struct reg_flow * flow,
fail:
return -ENOMEM;
}
-
-void reg_flow_set_data(struct reg_flow * flow,
- const buffer_t * buf)
-{
- assert(flow != NULL);
- assert(buf != NULL);
- assert(flow->data.data == NULL);
- assert(flow->data.len == 0);
-
- flow->data = *buf;
-}
-
-void reg_flow_get_data(struct reg_flow * flow,
- buffer_t * buf)
-{
- assert(flow != NULL);
- assert(buf != NULL);
-
- *buf = flow->data;
-
- clrbuf(flow->data);
-}
-
-void reg_flow_free_data(struct reg_flow * flow)
-{
- freebuf(flow->data);
-}
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
index d0078e1b..9a4046d3 100644
--- a/src/irmd/reg/flow.h
+++ b/src/irmd/reg/flow.h
@@ -31,6 +31,7 @@
#include <ouroboros/ssm_rbuff.h>
#include <ouroboros/utils.h>
+#include <stdbool.h>
#include <sys/types.h>
#include <time.h>
@@ -40,11 +41,14 @@ struct reg_flow {
struct flow_info info;
int response;
- buffer_t data;
+ buffer_t req_data;
+ buffer_t rsp_data;
struct timespec t0;
char name[NAME_SIZE + 1];
+ bool direct;
+
struct ssm_rbuff * n_rb;
struct ssm_rbuff * n_1_rb;
};
@@ -56,12 +60,4 @@ void reg_flow_destroy(struct reg_flow * flow);
int reg_flow_update(struct reg_flow * flow,
struct flow_info * info);
-void reg_flow_set_data(struct reg_flow * flow,
- const buffer_t * buf);
-
-void reg_flow_get_data(struct reg_flow * flow,
- buffer_t * buf);
-
-void reg_flow_free_data(struct reg_flow * flow);
-
#endif /* OUROBOROS_IRMD_REG_FLOW_H */
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index 64aa1513..0025f695 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -1785,7 +1785,8 @@ int reg_wait_flow_allocated(struct flow_info * info,
}
if (flow != NULL) {
- reg_flow_get_data(flow, pbuf);
+ *pbuf = flow->rsp_data;
+ clrbuf(flow->rsp_data);
*info = flow->info;
}
@@ -1820,8 +1821,8 @@ int reg_respond_alloc(struct flow_info * info,
}
assert(flow->info.state == FLOW_ALLOC_PENDING);
- assert(flow->data.len == 0);
- assert(flow->data.data == NULL);
+ assert(flow->rsp_data.len == 0);
+ assert(flow->rsp_data.data == NULL);
info->n_pid = flow->info.n_pid;
info->n_1_pid = flow->info.n_pid;
@@ -1833,8 +1834,10 @@ int reg_respond_alloc(struct flow_info * info,
flow->response = response;
- if (info->state == FLOW_ALLOCATED)
- reg_flow_set_data(flow, pbuf);
+ if (info->state == FLOW_ALLOCATED) {
+ flow->rsp_data = *pbuf;
+ clrbuf(*pbuf);
+ }
pthread_cond_broadcast(&reg.cond);
@@ -1944,7 +1947,8 @@ int reg_wait_flow_accepted(struct flow_info * info,
pthread_cleanup_pop(true); /* __cleanup_wait_accept */
if (flow != NULL) {
- reg_flow_get_data(flow, pbuf);
+ *pbuf = flow->req_data;
+ clrbuf(flow->req_data);
*info = flow->info;
}
@@ -2004,8 +2008,63 @@ int reg_respond_accept(struct flow_info * info,
info->n_pid = flow->info.n_pid;
- reg_flow_set_data(flow, pbuf);
- clrbuf(pbuf);
+ flow->req_data = *pbuf;
+ clrbuf(*pbuf);
+
+ if (reg_flow_update(flow, info) < 0) {
+ log_err("Failed to create flow structs.");
+ goto fail_flow;
+ }
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+
+ fail_flow:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_prepare_flow_direct(struct flow_info * info,
+ buffer_t * pbuf,
+ uid_t alloc_uid)
+{
+ struct reg_flow * flow;
+ struct reg_proc * proc;
+ uid_t accept_uid = 0;
+
+ assert(info != NULL);
+ assert(info->state == FLOW_ALLOCATED);
+ assert(info->n_1_pid != 0);
+ assert(pbuf != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(info->id);
+ if (flow == NULL) {
+ log_err("Flow not found: %d.", info->id);
+ goto fail_flow;
+ }
+
+ assert(flow->info.state == FLOW_ACCEPT_PENDING);
+
+ info->n_pid = flow->info.n_pid;
+
+ proc = __reg_get_proc(info->n_pid);
+ if (proc != NULL && !is_ouroboros_member_uid(proc->info.uid))
+ accept_uid = proc->info.uid;
+
+ if (alloc_uid != accept_uid) {
+ pthread_mutex_unlock(&reg.mtx);
+ return -EPERM;
+ }
+
+ flow->direct = true;
+
+ flow->req_data = *pbuf;
+ clrbuf(*pbuf);
if (reg_flow_update(flow, info) < 0) {
log_err("Failed to create flow structs.");
@@ -2023,6 +2082,109 @@ int reg_respond_accept(struct flow_info * info,
return -1;
}
+bool reg_flow_is_direct(int flow_id)
+{
+ struct reg_flow * flow;
+ bool ret;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+
+ ret = flow != NULL && flow->direct;
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return ret;
+}
+
+int reg_respond_flow_direct(int flow_id,
+ buffer_t * pbuf)
+{
+ struct reg_flow * flow;
+
+ assert(pbuf != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+ if (flow == NULL) {
+ log_err("Flow %d not found.", flow_id);
+ goto fail;
+ }
+
+ assert(flow->direct);
+ assert(flow->rsp_data.data == NULL);
+
+ flow->rsp_data = *pbuf;
+ clrbuf(*pbuf);
+
+ pthread_cond_broadcast(&reg.cond);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return 0;
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+int reg_wait_flow_direct(int flow_id,
+ buffer_t * pbuf,
+ const struct timespec * abstime)
+{
+ struct reg_flow * flow;
+ int ret = -1;
+
+ assert(pbuf != NULL);
+
+ pthread_mutex_lock(&reg.mtx);
+
+ flow = __reg_get_flow(flow_id);
+ if (flow == NULL)
+ goto fail;
+
+ assert(flow->direct);
+
+ pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
+
+ while (flow != NULL && flow->rsp_data.data == NULL) {
+ ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
+ if (ret == -ETIMEDOUT)
+ break;
+ flow = __reg_get_flow(flow_id);
+ }
+
+ if (flow != NULL && flow->rsp_data.data != NULL) {
+ *pbuf = flow->rsp_data;
+ clrbuf(flow->rsp_data);
+ ret = 0;
+ }
+
+ pthread_cleanup_pop(true);
+
+ return ret;
+ fail:
+ pthread_mutex_unlock(&reg.mtx);
+ return -1;
+}
+
+static int direct_flow_dealloc(struct reg_flow * flow,
+ pid_t pid)
+{
+ if (!flow->direct)
+ return -1;
+
+ if (pid == flow->info.n_pid && flow->info.n_pid != -1)
+ flow->info.n_pid = -1;
+ else if (pid == flow->info.n_1_pid && flow->info.n_1_pid != -1)
+ flow->info.n_1_pid = -1;
+ else
+ return -1;
+
+ return 0;
+}
+
void reg_dealloc_flow(struct flow_info * info)
{
struct reg_flow * flow;
@@ -2036,13 +2198,32 @@ void reg_dealloc_flow(struct flow_info * info)
flow = __reg_get_flow(info->id);
assert(flow != NULL);
- assert(flow->data.data == NULL);
- assert(flow->data.len == 0);
+ assert(flow->req_data.data == NULL);
+ assert(flow->req_data.len == 0);
+ assert(flow->rsp_data.data == NULL);
+ assert(flow->rsp_data.len == 0);
+
+ info->n_1_pid = flow->info.n_1_pid;
+
+ if (flow->info.state == FLOW_DEALLOC_PENDING) {
+ if (direct_flow_dealloc(flow, info->n_pid) < 0) {
+ info->state = FLOW_DEALLOC_PENDING;
+ pthread_mutex_unlock(&reg.mtx);
+ return;
+ }
+ flow->info.state = FLOW_DEALLOCATED;
+ info->state = FLOW_DEALLOCATED;
+ reg_flow_update(flow, info);
+ pthread_mutex_unlock(&reg.mtx);
+ return;
+ }
+
assert(flow->info.state == FLOW_ALLOCATED);
flow->info.state = FLOW_DEALLOC_PENDING;
info->state = FLOW_DEALLOC_PENDING;
- info->n_1_pid = flow->info.n_1_pid;
+
+ direct_flow_dealloc(flow, info->n_pid);
memset(flow->name, 0, sizeof(flow->name));
@@ -2064,8 +2245,10 @@ void reg_dealloc_flow_resp(struct flow_info * info)
flow = __reg_get_flow(info->id);
assert(flow != NULL);
- assert(flow->data.data == NULL);
- assert(flow->data.len == 0);
+ assert(flow->req_data.data == NULL);
+ assert(flow->req_data.len == 0);
+ assert(flow->rsp_data.data == NULL);
+ assert(flow->rsp_data.len == 0);
assert(flow->info.state == FLOW_DEALLOC_PENDING);
flow->info.state = FLOW_DEALLOCATED;
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index bda57711..6b576471 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -150,6 +150,19 @@ int reg_wait_flow_accepting(const char * name,
int reg_respond_accept(struct flow_info * info,
buffer_t * pbuf);
+int reg_prepare_flow_direct(struct flow_info * info,
+ buffer_t * pbuf,
+ uid_t alloc_uid);
+
+int reg_respond_flow_direct(int flow_id,
+ buffer_t * pbuf);
+
+int reg_wait_flow_direct(int flow_id,
+ buffer_t * pbuf,
+ const struct timespec * abstime);
+
+bool reg_flow_is_direct(int flow_id);
+
void reg_dealloc_flow(struct flow_info * info);
void reg_dealloc_flow_resp(struct flow_info * info);
diff --git a/src/irmd/reg/tests/flow_test.c b/src/irmd/reg/tests/flow_test.c
index bfdbceb5..7e1c1360 100644
--- a/src/irmd/reg/tests/flow_test.c
+++ b/src/irmd/reg/tests/flow_test.c
@@ -24,10 +24,6 @@
#include <test/test.h>
-#include <string.h>
-
-#define TEST_DATA "testpiggybackdata"
-
static int test_reg_flow_create_destroy(void)
{
struct reg_flow * f;
@@ -219,56 +215,6 @@ static int test_reg_flow_assert_fails(void)
return ret;
}
-static int test_flow_data(void)
-{
- struct reg_flow * f;
-
- struct flow_info info = {
- .id = 1,
- .n_pid = 1,
- .qs = qos_raw,
- .state = FLOW_INIT
- };
-
- char * data;
- buffer_t buf;
- buffer_t rcv = {0, NULL};
-
- TEST_START();
-
- data = strdup(TEST_DATA);
- if (data == NULL) {
- printf("Failed to strdup data.\n");
- goto fail;
- }
-
- buf.data = (uint8_t *) data;
- buf.len = strlen(data);
-
- f = reg_flow_create(&info);
- if (f == NULL) {
- printf("Failed to create flow.\n");
- goto fail;
- }
-
- reg_flow_set_data(f, &buf);
-
- reg_flow_get_data(f, &rcv);
-
- freebuf(buf);
- clrbuf(rcv);
-
- reg_flow_destroy(f);
-
- TEST_SUCCESS();
-
- return TEST_RC_SUCCESS;
- fail:
- free(data);
- TEST_FAIL();
- return TEST_RC_FAIL;
-}
-
int flow_test(int argc,
char ** argv)
{
@@ -280,7 +226,6 @@ int flow_test(int argc,
ret |= test_reg_flow_create_destroy();
ret |= test_reg_flow_update();
ret |= test_reg_flow_assert_fails();
- ret |= test_flow_data();
return ret;
}
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
index 4d7e30ef..f4b0188b 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -197,6 +197,8 @@ static void * test_flow_respond_alloc(void * o)
reg_respond_alloc(info, &pbuf, response);
+ freebuf(pbuf);
+
return (void *) 0;
fail:
return (void *) -1;
@@ -216,6 +218,8 @@ static void * test_flow_respond_accept(void * o)
reg_respond_accept(info, &pbuf);
+ freebuf(pbuf);
+
return (void *) 0;
fail:
return (void *) -1;
@@ -485,6 +489,188 @@ static int test_reg_allocate_flow_fail(void)
return TEST_RC_FAIL;
}
+struct direct_alloc_info {
+ struct flow_info info;
+ buffer_t rsp;
+ struct timespec abstime;
+};
+
+static void * test_flow_alloc_direct(void * o)
+{
+ struct direct_alloc_info * dai;
+ buffer_t req;
+
+ dai = (struct direct_alloc_info *) o;
+
+ req.data = (uint8_t *) strdup(TEST_DATA);
+ if (req.data == NULL) {
+ printf("Failed to strdup req data.\n");
+ goto fail;
+ }
+ req.len = strlen(TEST_DATA) + 1;
+
+ if (reg_prepare_flow_direct(&dai->info, &req, 0) < 0) {
+ printf("Failed to prepare direct flow.\n");
+ freebuf(req);
+ goto fail;
+ }
+
+ if (reg_wait_flow_direct(dai->info.id, &dai->rsp, &dai->abstime) < 0) {
+ printf("Failed to wait direct flow.\n");
+ goto fail;
+ }
+
+ return (void *) 0;
+ fail:
+ return (void *) -1;
+}
+
+static int test_reg_direct_flow_success(void)
+{
+ pthread_t thr;
+ struct timespec abstime;
+ struct timespec timeo = TIMESPEC_INIT_S(1);
+ buffer_t rbuf = BUF_INIT;
+ buffer_t rsp;
+ struct direct_alloc_info dai;
+ void * thr_ret;
+
+ struct flow_info info = {
+ .n_pid = TEST_PID,
+ .qs = qos_raw
+ };
+
+ TEST_START();
+
+ clock_gettime(PTHREAD_COND_CLOCK, &abstime);
+
+ ts_add(&abstime, &timeo, &abstime);
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ if (reg_create_flow(&info) < 0) {
+ printf("Failed to add flow.\n");
+ goto fail;
+ }
+
+ if (reg_prepare_flow_accept(&info) < 0) {
+ printf("Failed to prepare for accept.\n");
+ goto fail;
+ }
+
+ dai.info.id = info.id;
+ dai.info.n_1_pid = TEST_N_1_PID;
+ dai.info.mpl = TEST_MPL;
+ dai.info.qs = qos_data;
+ dai.info.state = FLOW_ALLOCATED;
+ dai.rsp.len = 0;
+ dai.rsp.data = NULL;
+ dai.abstime = abstime;
+
+ pthread_create(&thr, NULL, test_flow_alloc_direct, &dai);
+
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0) {
+ printf("Flow accept failed.\n");
+ pthread_join(thr, NULL);
+ reg_destroy_flow(info.id);
+ reg_fini();
+ goto fail;
+ }
+
+ if (info.state != FLOW_ALLOCATED) {
+ printf("Flow not in allocated state.\n");
+ goto fail;
+ }
+
+ if (rbuf.data == NULL) {
+ printf("req_data not received.\n");
+ goto fail;
+ }
+
+ if (strcmp((char *) rbuf.data, TEST_DATA) != 0) {
+ printf("req_data content mismatch.\n");
+ goto fail;
+ }
+
+ freebuf(rbuf);
+
+ if (!reg_flow_is_direct(info.id)) {
+ printf("Flow not marked direct.\n");
+ goto fail;
+ }
+
+ rsp.data = (uint8_t *) strdup(TEST_DATA2);
+ if (rsp.data == NULL) {
+ printf("Failed to strdup rsp data.\n");
+ goto fail;
+ }
+ rsp.len = strlen(TEST_DATA2) + 1;
+
+ if (reg_respond_flow_direct(info.id, &rsp) < 0) {
+ printf("Failed to respond direct.\n");
+ freebuf(rsp);
+ goto fail;
+ }
+
+ pthread_join(thr, &thr_ret);
+
+ if (thr_ret != (void *) 0) {
+ printf("Allocator thread failed.\n");
+ goto fail;
+ }
+
+ if (dai.rsp.data == NULL) {
+ printf("rsp_data not received.\n");
+ goto fail;
+ }
+
+ if (strcmp((char *) dai.rsp.data, TEST_DATA2) != 0) {
+ printf("rsp_data content mismatch.\n");
+ goto fail;
+ }
+
+ freebuf(dai.rsp);
+
+ reg_dealloc_flow(&info);
+
+ if (info.state != FLOW_DEALLOC_PENDING) {
+ printf("Flow not in dealloc pending.\n");
+ goto fail;
+ }
+
+ info.n_pid = TEST_PID;
+
+ reg_dealloc_flow(&info);
+
+ if (info.state != FLOW_DEALLOC_PENDING) {
+ printf("Same endpoint dealloc changed state.\n");
+ goto fail;
+ }
+
+ info.n_pid = TEST_N_1_PID;
+
+ reg_dealloc_flow(&info);
+
+ if (info.state != FLOW_DEALLOCATED) {
+ printf("Flow not deallocated.\n");
+ goto fail;
+ }
+
+ reg_destroy_flow(info.id);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
static int test_reg_flow(void) {
int rc = 0;
@@ -493,6 +679,7 @@ static int test_reg_flow(void) {
rc |= test_reg_accept_flow_success();
rc |= test_reg_accept_flow_success_no_crypt();
rc |= test_reg_allocate_flow_fail();
+ rc |= test_reg_direct_flow_success();
return rc;
}
@@ -1304,7 +1491,7 @@ static int test_wait_accepting_fail_name(void)
static void * test_call_flow_accept(void * o)
{
struct timespec abstime;
- struct timespec timeo = TIMESPEC_INIT_MS(10);
+ struct timespec timeo = TIMESPEC_INIT_MS(30);
buffer_t pbuf = BUF_INIT;
struct proc_info pinfo = TEST_PROC_INFO;
diff --git a/src/lib/crypt.c b/src/lib/crypt.c
index cd3421dd..71197f6e 100644
--- a/src/lib/crypt.c
+++ b/src/lib/crypt.c
@@ -1094,6 +1094,13 @@ void crypt_secure_malloc_fini(void)
#endif
}
+void crypt_cleanup(void)
+{
+#ifdef HAVE_OPENSSL
+ openssl_cleanup();
+#endif
+}
+
void * crypt_secure_malloc(size_t size)
{
#ifdef HAVE_OPENSSL
diff --git a/src/lib/crypt/openssl.c b/src/lib/crypt/openssl.c
index 573bc0b3..5916e3cb 100644
--- a/src/lib/crypt/openssl.c
+++ b/src/lib/crypt/openssl.c
@@ -629,7 +629,7 @@ ssize_t openssl_pkp_create(const char * algo,
return (ssize_t) raw.len;
} else { /* DER encode standard algorithms */
- pos = pk; /* i2d_PUBKEY increments the pointer, don't use pk! */
+ pos = pk; /* i2d_PUBKEY increments the ptr, don't use pk! */
len = i2d_PUBKEY(*pkp, &pos);
if (len < 0)
goto fail_pubkey;
@@ -666,7 +666,7 @@ static ssize_t __openssl_kem_encap(EVP_PKEY * pub,
/* Get required lengths */
ret = EVP_PKEY_encapsulate(ctx, NULL, &ct_len, NULL, &secret_len);
- if (ret != 1 || ct_len > MSGBUFSZ)
+ if (ret != 1 || ct_len > CRYPT_KEY_BUFSZ)
goto fail_encap;
/* Allocate buffer for secret */
@@ -1283,24 +1283,14 @@ int openssl_load_privkey_file(const char * path,
{
FILE * fp;
EVP_PKEY * pkey;
- unsigned long err;
- char errbuf[256];
fp = fopen(path, "r");
- if (fp == NULL) {
- fprintf(stderr, "Failed to open %s\n", path);
+ if (fp == NULL)
goto fail_file;
- }
pkey = PEM_read_PrivateKey(fp, NULL, NULL, "");
- if (pkey == NULL) {
- err = ERR_get_error();
- ERR_error_string_n(err, errbuf, sizeof(errbuf));
- fprintf(stderr,
- "OpenSSL error loading privkey from %s: %s\n",
- path, errbuf);
+ if (pkey == NULL)
goto fail_key;
- }
fclose(fp);
@@ -1442,7 +1432,7 @@ int openssl_load_pubkey_raw_file(const char * path,
buffer_t * buf)
{
FILE * fp;
- uint8_t tmp_buf[MSGBUFSZ];
+ uint8_t tmp_buf[CRYPT_KEY_BUFSZ];
size_t bytes_read;
const char * algo;
@@ -1453,7 +1443,7 @@ int openssl_load_pubkey_raw_file(const char * path,
if (fp == NULL)
goto fail_file;
- bytes_read = fread(tmp_buf, 1, MSGBUFSZ, fp);
+ bytes_read = fread(tmp_buf, 1, CRYPT_KEY_BUFSZ, fp);
if (bytes_read == 0)
goto fail_read;
@@ -1658,25 +1648,33 @@ int openssl_crt_str(const void * crt,
int openssl_crt_der(const void * crt,
buffer_t * buf)
{
- int len;
+ uint8_t * p;
+ int len;
assert(crt != NULL);
assert(buf != NULL);
- len = i2d_X509((X509 *) crt, &buf->data);
+ /* Get the size by encoding to NULL */
+ len = i2d_X509((X509 *) crt, NULL);
if (len < 0)
- goto fail_der;
+ goto fail_len;
+ buf->data = malloc((size_t) len);
+ if (buf->data == NULL)
+ goto fail_malloc;
+
+ p = buf->data; /* i2d_X509 increments p */
+ i2d_X509((X509 *) crt, &p);
buf->len = (size_t) len;
return 0;
- fail_der:
+ fail_malloc:
+ fail_len:
clrbuf(*buf);
return -1;
}
-
void * openssl_auth_create_store(void)
{
return X509_STORE_new();
@@ -1878,3 +1876,7 @@ void openssl_secure_clear(void * ptr,
{
OPENSSL_cleanse(ptr, size);
}
+void openssl_cleanup(void)
+{
+ OPENSSL_cleanup();
+}
diff --git a/src/lib/crypt/openssl.h b/src/lib/crypt/openssl.h
index b95d1b0b..af285232 100644
--- a/src/lib/crypt/openssl.h
+++ b/src/lib/crypt/openssl.h
@@ -169,4 +169,6 @@ void openssl_secure_free(void * ptr,
void openssl_secure_clear(void * ptr,
size_t size);
+void openssl_cleanup(void);
+
#endif /* OUROBOROS_LIB_CRYPT_OPENSSL_H */
diff --git a/src/lib/irm.c b/src/lib/irm.c
index 594014f7..c62701aa 100644
--- a/src/lib/irm.c
+++ b/src/lib/irm.c
@@ -614,7 +614,7 @@ ssize_t irm_list_names(struct name_info ** names)
return 0;
}
- *names = malloc(nr * sizeof(**names));
+ *names = calloc(nr, sizeof(**names));
if (*names == NULL) {
irm_msg__free_unpacked(recv_msg, NULL);
return -ENOMEM;
diff --git a/src/lib/protobuf.c b/src/lib/protobuf.c
index 6c80cfc2..28b3aab2 100644
--- a/src/lib/protobuf.c
+++ b/src/lib/protobuf.c
@@ -137,7 +137,7 @@ name_info_msg_t * name_info_s_to_msg(const struct name_info * info)
goto fail_msg;
msg->ckey = strdup(info->c.key);
- if (msg->skey == NULL)
+ if (msg->ckey == NULL)
goto fail_msg;
msg->ccrt = strdup(info->c.crt);
@@ -161,6 +161,8 @@ struct name_info name_info_msg_to_s(const name_info_msg_t * msg)
assert(msg != NULL);
assert(strlen(msg->name) <= NAME_SIZE);
+ memset(&s, 0, sizeof(s));
+
strcpy(s.name, msg->name);
strcpy(s.s.key, msg->skey);
strcpy(s.s.crt, msg->scrt);
@@ -550,7 +552,7 @@ struct udp4_config udp4_config_msg_to_s(const udp4_config_msg_t * msg)
return s;
}
-#define IN6_LEN sizeof(struct in6_addr)
+#define IN6_LEN (size_t) sizeof(struct in6_addr)
udp6_config_msg_t * udp6_config_s_to_msg(const struct udp6_config * s)
{
udp6_config_msg_t * msg;
diff --git a/src/lib/ssm/pool.c b/src/lib/ssm/pool.c
index 97313e7d..f17a6e65 100644
--- a/src/lib/ssm/pool.c
+++ b/src/lib/ssm/pool.c
@@ -107,6 +107,8 @@ static const struct ssm_size_class_cfg ssm_pup_cfg[SSM_POOL_MAX_CLASSES] = {
: SSM_PUP_FILE_SIZE)
#define GET_POOL_CFG(uid) (IS_GSPP(uid) ? ssm_gspp_cfg : ssm_pup_cfg)
+#define NEEDS_CHOWN(uid, gid) ((uid) != geteuid() || (gid) != getegid())
+
struct ssm_pool {
uint8_t * shm_base; /* start of blocks */
struct _ssm_pool_hdr * hdr; /* shared memory header */
@@ -506,14 +508,12 @@ void ssm_pool_destroy(struct ssm_pool * pool)
if (getpid() != pool->hdr->pid && kill(pool->hdr->pid, 0) == 0) {
ssm_pool_close(pool);
- free(pool);
return;
}
fn = pool_filename(pool->uid);
if (fn == NULL) {
ssm_pool_close(pool);
- free(pool);
return;
}
@@ -550,7 +550,7 @@ static struct ssm_pool * __pool_create(const char * name,
if (flags & O_CREAT) {
if (ftruncate(fd, (off_t) file_size) < 0)
goto fail_truncate;
- if (uid != geteuid() && fchown(fd, uid, gid) < 0)
+ if (NEEDS_CHOWN(uid, gid) && fchown(fd, uid, gid) < 0)
goto fail_truncate;
}
diff --git a/src/lib/ssm/tests/pool_sharding_test.c b/src/lib/ssm/tests/pool_sharding_test.c
index 4ecd2b9c..c53105e3 100644
--- a/src/lib/ssm/tests/pool_sharding_test.c
+++ b/src/lib/ssm/tests/pool_sharding_test.c
@@ -242,6 +242,8 @@ static int test_fallback_stealing(void)
ptrs = malloc(total_blocks * sizeof(uint8_t *));
if (spbs == NULL || ptrs == NULL) {
printf("Failed to allocate test arrays.\n");
+ free(spbs);
+ free(ptrs);
goto fail_pool;
}
@@ -326,6 +328,9 @@ static int test_multiprocess_sharding(void)
TEST_START();
+ for (i = 0; i < SSM_POOL_SHARDS; i++)
+ children[i] = -1;
+
pool = ssm_pool_create(getuid(), getgid());
if (pool == NULL) {
printf("Failed to create pool.\n");
diff --git a/src/lib/tests/auth_test.c b/src/lib/tests/auth_test.c
index 1a5a87af..0f3ef715 100644
--- a/src/lib/tests/auth_test.c
+++ b/src/lib/tests/auth_test.c
@@ -347,6 +347,59 @@ static int test_verify_crt(void)
return TEST_RC_FAIL;
}
+static int test_verify_crt_missing_root_ca(void)
+{
+ struct auth_ctx * auth;
+ void * _signed_server_crt;
+ void * _im_ca_crt;
+
+ TEST_START();
+
+ auth = auth_create_ctx();
+ if (auth == NULL) {
+ printf("Failed to create auth context.\n");
+ goto fail_create_ctx;
+ }
+
+ if (crypt_load_crt_str(signed_server_crt_ec, &_signed_server_crt) < 0) {
+ printf("Failed to load signed crt from string.\n");
+ goto fail_load_signed;
+ }
+
+ if (crypt_load_crt_str(im_ca_crt_ec, &_im_ca_crt) < 0) {
+ printf("Failed to load intermediate crt from string.\n");
+ goto fail_load_im_ca;
+ }
+
+ /* Add only the intermediate CA - root CA is missing */
+ if (auth_add_crt_to_store(auth, _im_ca_crt) < 0) {
+ printf("Failed to add intermediate ca crt to auth store.\n");
+ goto fail_add;
+ }
+
+ if (auth_verify_crt(auth, _signed_server_crt) == 0) {
+ printf("Verification should fail without root CA.\n");
+ goto fail_add;
+ }
+
+ crypt_free_crt(_im_ca_crt);
+ crypt_free_crt(_signed_server_crt);
+ auth_destroy_ctx(auth);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail_add:
+ crypt_free_crt(_im_ca_crt);
+ fail_load_im_ca:
+ crypt_free_crt(_signed_server_crt);
+ fail_load_signed:
+ auth_destroy_ctx(auth);
+ fail_create_ctx:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
int test_auth_sign(void)
{
uint8_t buf[TEST_MSG_SIZE];
@@ -526,6 +579,7 @@ int auth_test(int argc,
ret |= test_crypt_check_pubkey_crt();
ret |= test_store_add();
ret |= test_verify_crt();
+ ret |= test_verify_crt_missing_root_ca();
ret |= test_auth_sign();
ret |= test_auth_bad_signature();
ret |= test_crt_str();
@@ -538,6 +592,7 @@ int auth_test(int argc,
(void) test_crypt_check_pubkey_crt;
(void) test_store_add;
(void) test_verify_crt;
+ (void) test_verify_crt_missing_root_ca;
(void) test_auth_sign;
(void) test_auth_bad_signature;
(void) test_crt_str;
diff --git a/src/lib/tests/kex_test.c b/src/lib/tests/kex_test.c
index ced760fe..6a4f802e 100644
--- a/src/lib/tests/kex_test.c
+++ b/src/lib/tests/kex_test.c
@@ -106,7 +106,7 @@ static int test_kex_dh_pkp_create_destroy(void)
{
struct sec_config kex;
void * pkp;
- uint8_t buf[MSGBUFSZ];
+ uint8_t buf[CRYPT_KEY_BUFSZ];
TEST_START();
@@ -134,7 +134,7 @@ static int test_kex_get_algo_from_pk(const char * algo)
void * pkp;
buffer_t pk;
ssize_t len;
- uint8_t buf[MSGBUFSZ];
+ uint8_t buf[CRYPT_KEY_BUFSZ];
char extracted_algo[256];
TEST_START("(%s)", algo);
@@ -204,8 +204,8 @@ static int test_kex_dhe_derive(const char * algo)
buffer_t pk1;
buffer_t pk2;
ssize_t len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
+ uint8_t buf1[CRYPT_KEY_BUFSZ];
+ uint8_t buf2[CRYPT_KEY_BUFSZ];
uint8_t s1[SYMMKEYSZ];
uint8_t s2[SYMMKEYSZ];
@@ -317,7 +317,7 @@ static int test_kex_dhe_corrupted_pubkey(const char * algo)
void * pkp;
buffer_t pk;
ssize_t len;
- uint8_t buf[MSGBUFSZ];
+ uint8_t buf[CRYPT_KEY_BUFSZ];
uint8_t s[SYMMKEYSZ];
TEST_START("(%s)", algo);
@@ -363,8 +363,8 @@ static int test_kex_dhe_wrong_algo(void)
void * pkp2;
buffer_t pk2;
ssize_t len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
+ uint8_t buf1[CRYPT_KEY_BUFSZ];
+ uint8_t buf2[CRYPT_KEY_BUFSZ];
uint8_t s[SYMMKEYSZ];
const char * algo1 = "X25519";
const char * algo2 = "X448";
diff --git a/src/lib/tests/kex_test_ml_kem.c b/src/lib/tests/kex_test_ml_kem.c
index 3bb9ae7c..7761c3dc 100644
--- a/src/lib/tests/kex_test_ml_kem.c
+++ b/src/lib/tests/kex_test_ml_kem.c
@@ -197,8 +197,8 @@ static int test_kex_kem(const char * algo)
buffer_t ct;
ssize_t len;
ssize_t ct_len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
+ uint8_t buf1[CRYPT_KEY_BUFSZ];
+ uint8_t buf2[CRYPT_KEY_BUFSZ];
uint8_t s1[SYMMKEYSZ];
uint8_t s2[SYMMKEYSZ];
int kdf;
@@ -262,8 +262,8 @@ static int test_kex_kem_corrupted_ciphertext(const char * algo)
buffer_t ct;
ssize_t len;
ssize_t ct_len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
+ uint8_t buf1[CRYPT_KEY_BUFSZ];
+ uint8_t buf2[CRYPT_KEY_BUFSZ];
uint8_t s1[SYMMKEYSZ];
uint8_t s2[SYMMKEYSZ];
int kdf;
@@ -334,9 +334,9 @@ static int test_kex_kem_wrong_keypair(const char * algo)
buffer_t ct;
ssize_t len;
ssize_t ct_len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
- uint8_t buf3[MSGBUFSZ];
+ uint8_t buf1[CRYPT_KEY_BUFSZ];
+ uint8_t buf2[CRYPT_KEY_BUFSZ];
+ uint8_t buf3[CRYPT_KEY_BUFSZ];
uint8_t s1[SYMMKEYSZ];
uint8_t s2[SYMMKEYSZ];
@@ -402,8 +402,8 @@ static int test_kex_kem_truncated_ciphertext(const char * algo)
buffer_t ct;
ssize_t len;
ssize_t ct_len;
- uint8_t buf1[MSGBUFSZ];
- uint8_t buf2[MSGBUFSZ];
+ uint8_t buf1[CRYPT_KEY_BUFSZ];
+ uint8_t buf2[CRYPT_KEY_BUFSZ];
uint8_t s1[SYMMKEYSZ];
uint8_t s2[SYMMKEYSZ];
diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c
index 86796552..763c0d62 100644
--- a/src/tools/oping/oping.c
+++ b/src/tools/oping/oping.c
@@ -72,17 +72,19 @@
"and reports the Round Trip Time (RTT)\n" \
"\n" \
" -l, --listen Run in server mode\n" \
+" --poll Server uses polling (lower latency)\n" \
+" --busy Server uses busy-poll (single flow)\n" \
"\n" \
" -c, --count Number of packets\n" \
" -d, --duration Duration of the test (default 1s)\n" \
" -f, --flood Send back-to-back without waiting\n" \
+" -F, --flood-busy Flood with busy-polling (lower latency)\n" \
" -i, --interval Interval (default 1000ms)\n" \
" -n, --server-name Name of the oping server\n" \
-" -q, --qos QoS (raw, best, video, voice, data)\n" \
+" -q, --qos QoS (raw, best, video, voice, data)\n" \
" -s, --size Payload size (B, default 64)\n" \
" -Q, --quiet Only print final statistics\n" \
" -D, --timeofday Print time of day before each line\n" \
-" --poll Server uses polling (lower latency)\n" \
"\n" \
" --help Display this help text and exit\n" \
@@ -93,6 +95,7 @@ struct {
int size;
bool timestamp;
bool flood;
+ bool flood_busy;
qosspec_t qs;
/* stats */
@@ -118,6 +121,7 @@ struct {
bool quiet;
bool poll;
+ bool busy;
pthread_t cleaner_pt;
pthread_t accept_pt;
@@ -177,10 +181,12 @@ int main(int argc,
client.count = INT_MAX;
client.timestamp = false;
client.flood = false;
+ client.flood_busy = false;
client.qs = qos_raw;
client.quiet = false;
server.quiet = false;
server.poll = false;
+ server.busy = false;
while (argc > 0) {
if ((strcmp(*argv, "-i") == 0 ||
@@ -221,6 +227,9 @@ int main(int argc,
} else if (strcmp(*argv, "-f") == 0 ||
strcmp(*argv, "--flood") == 0) {
client.flood = true;
+ } else if (strcmp(*argv, "-F") == 0 ||
+ strcmp(*argv, "--flood-busy") == 0) {
+ client.flood_busy = true;
} else if (strcmp(*argv, "-D") == 0 ||
strcmp(*argv, "--timeofday") == 0) {
client.timestamp = true;
@@ -230,6 +239,8 @@ int main(int argc,
server.quiet = true;
} else if (strcmp(*argv, "--poll") == 0) {
server.poll = true;
+ } else if (strcmp(*argv, "--busy") == 0) {
+ server.busy = true;
} else {
goto fail;
}
diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c
index 18dd3078..23807f65 100644
--- a/src/tools/oping/oping_client.c
+++ b/src/tools/oping/oping_client.c
@@ -67,6 +67,26 @@ static void update_rtt_stats(double ms)
client.rtt_m2 += d * (ms - client.rtt_avg);
}
+static double rtt_val(double ms)
+{
+ return ms < 0.1 ? ms * 1000 : ms;
+}
+
+static const char * rtt_unit(double ms)
+{
+ return ms < 0.1 ? "µs" : "ms";
+}
+
+static void print_rtt(int len, int seq,
+ double ms, const char * suf)
+{
+ printf("%d bytes from %s: seq=%d "
+ "time=%.3f %s%s\n",
+ len, client.s_apn, seq,
+ rtt_val(ms), rtt_unit(ms),
+ suf != NULL ? suf : "");
+}
+
void * reader(void * o)
{
struct timespec timeout = {client.interval / 1000 + 2, 0};
@@ -127,12 +147,9 @@ void * reader(void * o)
(size_t) rtc.tv_nsec / 1000);
}
- printf("%d bytes from %s: seq=%d time=%.3f ms%s\n",
- msg_len,
- client.s_apn,
- ntohl(msg->id),
- ms,
- id < exp_id ? " [out-of-order]" : "");
+ print_rtt(msg_len, ntohl(msg->id), ms,
+ id < exp_id ?
+ " [out-of-order]" : NULL);
}
update_rtt_stats(ms);
@@ -223,16 +240,87 @@ static void print_stats(struct timespec * tic,
printf("time: %.3f ms\n", ts_diff_us(toc, tic) / 1000.0);
if (client.rcvd > 0) {
+ double a = client.rtt_avg;
+ double f = a < 0.1 ? 1000 : 1;
printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/",
- client.rtt_min,
- client.rtt_avg,
- client.rtt_max);
+ client.rtt_min * f, client.rtt_avg * f,
+ client.rtt_max * f);
if (client.rcvd > 1)
- printf("%.3f ms\n",
- sqrt(client.rtt_m2 / (client.rcvd - 1)));
+ printf("%.3f %s\n",
+ sqrt(client.rtt_m2 /
+ (client.rcvd - 1)) * f,
+ rtt_unit(a));
else
- printf("NaN ms\n");
+ printf("NaN %s\n", rtt_unit(a));
+ }
+}
+
+static int flood_busy_ping(int fd)
+{
+ char buf[OPING_BUF_SIZE];
+ struct oping_msg * msg = (struct oping_msg *) buf;
+ struct timespec sent;
+ struct timespec rcvd;
+ double ms;
+ int n;
+
+ memset(buf, 0, client.size);
+
+ fccntl(fd, FLOWSFLAGS,
+ FLOWFRDWR | FLOWFRNOPART | FLOWFRNOBLOCK);
+
+ if (!client.quiet)
+ printf("Pinging %s with %d bytes"
+ " of data (%u packets,"
+ " busy-poll):\n\n",
+ client.s_apn, client.size,
+ client.count);
+
+ while (!stop && client.sent < client.count) {
+ clock_gettime(CLOCK_MONOTONIC, &sent);
+
+ msg->type = htonl(ECHO_REQUEST);
+ msg->id = htonl(client.sent);
+ msg->tv_sec = sent.tv_sec;
+ msg->tv_nsec = sent.tv_nsec;
+
+ if (flow_write(fd, buf,
+ client.size) < 0) {
+ printf("Failed to send "
+ "packet.\n");
+ break;
+ }
+
+ ++client.sent;
+
+ do {
+ n = flow_read(fd, buf,
+ OPING_BUF_SIZE);
+ } while (n == -EAGAIN && !stop);
+
+ if (n < 0)
+ break;
+
+ clock_gettime(CLOCK_MONOTONIC, &rcvd);
+
+ if (ntohl(msg->type) != ECHO_REPLY)
+ continue;
+
+ ++client.rcvd;
+
+ sent.tv_sec = msg->tv_sec;
+ sent.tv_nsec = msg->tv_nsec;
+ ms = ts_diff_us(&rcvd, &sent) / 1000.0;
+
+ update_rtt_stats(ms);
+
+ if (!client.quiet)
+ print_rtt(client.size,
+ ntohl(msg->id), ms,
+ NULL);
}
+
+ return 0;
}
static int flood_ping(int fd)
@@ -283,9 +371,9 @@ static int flood_ping(int fd)
update_rtt_stats(ms);
if (!client.quiet)
- printf("%d bytes from %s: seq=%d time=%.3f ms\n",
- client.size, client.s_apn,
- ntohl(msg->id), ms);
+ print_rtt(client.size,
+ ntohl(msg->id), ms,
+ NULL);
}
return 0;
@@ -337,7 +425,9 @@ static int client_main(void)
clock_gettime(CLOCK_REALTIME, &tic);
- if (client.flood)
+ if (client.flood_busy)
+ flood_busy_ping(fd);
+ else if (client.flood)
flood_ping(fd);
else
threaded_ping(fd);
diff --git a/src/tools/oping/oping_server.c b/src/tools/oping/oping_server.c
index 1670ebf3..33af28c4 100644
--- a/src/tools/oping/oping_server.c
+++ b/src/tools/oping/oping_server.c
@@ -138,7 +138,10 @@ void * accept_thread(void * o)
(void) o;
- printf("Ouroboros ping server started.\n");
+ printf("Ouroboros ping server started.");
+ if (server.busy)
+ printf(" [busy-poll]");
+ printf("\n");
while (true) {
fd = flow_accept(&qs, NULL);
@@ -158,12 +161,56 @@ void * accept_thread(void * o)
pthread_mutex_unlock(&server.lock);
fccntl(fd, FLOWSFLAGS,
- FLOWFRNOBLOCK | FLOWFRDWR | FLOWFRNOPART);
+ FLOWFRNOBLOCK | FLOWFRDWR
+ | FLOWFRNOPART);
}
return (void *) 0;
}
+void * busy_thread(void * o)
+{
+ char buf[OPING_BUF_SIZE];
+ struct oping_msg * msg = (struct oping_msg *) buf;
+ int fd;
+ int msg_len;
+
+ (void) o;
+
+ /* Accept a single flow. */
+ fd = flow_accept(NULL, NULL);
+ if (fd < 0) {
+ printf("Failed to accept flow.\n");
+ return (void *) -1;
+ }
+
+ printf("New flow %d (busy-poll).\n", fd);
+
+ fccntl(fd, FLOWSFLAGS,
+ FLOWFRNOBLOCK | FLOWFRDWR
+ | FLOWFRNOPART);
+
+ while (true) {
+ msg_len = flow_read(fd, buf,
+ OPING_BUF_SIZE);
+ if (msg_len == -EAGAIN)
+ continue;
+ if (msg_len < 0)
+ break;
+
+ if (ntohl(msg->type) != ECHO_REQUEST)
+ continue;
+
+ msg->type = htonl(ECHO_REPLY);
+
+ flow_write(fd, buf, msg_len);
+ }
+
+ flow_dealloc(fd);
+
+ return (void *) 0;
+}
+
int server_main(void)
{
struct sigaction sig_act;
@@ -191,12 +238,21 @@ int server_main(void)
}
pthread_create(&server.cleaner_pt, NULL, cleaner_thread, NULL);
- pthread_create(&server.accept_pt, NULL, accept_thread, NULL);
- pthread_create(&server.server_pt, NULL, server_thread, NULL);
- pthread_join(server.accept_pt, NULL);
+ if (server.busy) {
+ pthread_create(&server.server_pt, NULL,
+ busy_thread, NULL);
+ pthread_join(server.server_pt, NULL);
+ pthread_cancel(server.cleaner_pt);
+ } else {
+ pthread_create(&server.accept_pt, NULL,
+ accept_thread, NULL);
+ pthread_create(&server.server_pt, NULL,
+ server_thread, NULL);
+ pthread_join(server.accept_pt, NULL);
+ pthread_cancel(server.server_pt);
+ }
- pthread_cancel(server.server_pt);
pthread_cancel(server.cleaner_pt);
fset_destroy(server.flows);