From 7ea1fa99541b1c410bab39bdbc5ce555eef25ece Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 00:42:18 +0100 Subject: [PATCH] Validate instance construction and retain the global log path safely --- src/utun_instance.c | 119 ++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 65 deletions(-) diff --git a/src/utun_instance.c b/src/utun_instance.c index c2c92d6e..f1dfba7d 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -51,10 +51,6 @@ #include #include #include -#ifndef _WIN32 -#include -#endif -#include #include #include "../lib/platform_compat.h" #include "../lib/mem.h" @@ -64,12 +60,11 @@ // Forward declarations -static uint32_t get_dest_ip(const uint8_t *packet, size_t len); static int mkdir_recursive(const char* path); static void instance_destroy(struct UTUN_INSTANCE* instance, int owns_config); -// Global instance for signal handlers -static struct UTUN_INSTANCE *g_instance = NULL; +// Путь глобального logger должен переживать config/instance, поскольку debug API заимствует строку. +static char g_config_log_path[256]; // Global flag to control TUN initialization (disabled by default) static int g_tun_init_enabled = 0; @@ -138,8 +133,11 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u /* Always verify node_id matches pubkey, fix if mismatched */ { uint8_t pub_bin[SC_PUBKEY_SIZE]; - sc_compute_public_key_from_private(instance->my_keys.private_key, pub_bin); + if (sc_compute_public_key_from_private(instance->my_keys.private_key, pub_bin) != SC_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "cannot compute instance X25519 public key"); return -1; + } uint64_t derived = sc_derive_node_id_from_pubkey(pub_bin); + if (!derived) { DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "instance identity derived zero node_id"); return -1; } DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "node_id check: config=%016llx derived=%016llx match=%d", (unsigned long long)instance->node_id, (unsigned long long)derived, (instance->node_id == derived)); @@ -158,7 +156,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u } { uint8_t ed_priv_hash[SHA512_DIGEST_LENGTH]; - SHA512(instance->my_keys.private_key, SC_PRIVKEY_SIZE, ed_priv_hash); + if (!SHA512(instance->my_keys.private_key, SC_PRIVKEY_SIZE, ed_priv_hash)) { + DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "cannot derive instance Ed25519 seed"); return -1; + } memcpy(instance->my_ed25519_privkey, ed_priv_hash, SC_PRIVKEY_SIZE); } DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "Ed25519 pubkey derived successfully"); @@ -173,7 +173,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u // Initialize connection queue instance->connections = queue_new(ua, 256, 0, 8, "connections"); if (!instance->connections) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create connections queue"); return -1; } - instance->tcp_connections = queue_new(ua, sizeof(struct tcp_conn_entry), sizeof(uint64_t), 8, "tcpconn"); + instance->tcp_connections = queue_new(ua, 256, offsetof(struct tcp_conn_entry, node_id), sizeof(uint64_t), "tcpconn"); if (!instance->tcp_connections) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create tcp_connections queue"); return -1; } struct CFG_NETWORK *net = config->networks; while (net) { @@ -184,15 +184,15 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u } struct NETWORK_ENTRY *ne = (struct NETWORK_ENTRY*)entry->data; ne->id = net->id & 0x00FFFFFFFFFFFFFFULL; - for (int i = 0; i < SC_PUBKEY_SIZE; i++) { - unsigned int b; sscanf(net->pubkey_hex + i * 2, "%2x", &b); ne->pubkey[i] = (uint8_t)b; - } - for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { - unsigned int b; sscanf(net->signing_key_hex + i * 2, "%2x", &b); ne->signing_key[i] = (uint8_t)b; + if (sc_hex_to_binary(net->pubkey_hex, ne->pubkey, sizeof(ne->pubkey)) != SC_OK || + sc_hex_to_binary(net->signing_key_hex, ne->signing_key, sizeof(ne->signing_key)) != SC_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "invalid keys for network %s", net->name); queue_entry_free(entry); return -1; } strncpy(ne->name, net->name, sizeof(ne->name) - 1); ne->name[sizeof(ne->name) - 1] = '\0'; - queue_data_put_with_index(instance->networks, entry); + if (queue_data_put_with_index(instance->networks, entry) < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "cannot index configured network %s", net->name); return -1; + } DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "Network added: [%s] id=%012llx", ne->name, (unsigned long long)ne->id); net = net->next; } @@ -217,7 +217,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Socket initialization failed: result=%d", socket_result); return -1; } - if (config->global.db_path[0]) mkdir_recursive(config->global.db_path); + if (config->global.db_path[0] && mkdir_recursive(config->global.db_path) < 0) return -1; if (g_topo_group_enabled) { instance->topo_groups = topo_groups_init(instance); if (!instance->topo_groups) { @@ -322,6 +322,9 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u // Create and initialize root instance from config file struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config_file) { + if (!ua || !config_file || !*config_file) { + DEBUG_ERROR(DEBUG_CATEGORY_SYS, "instance create requires uasync and a config path"); return NULL; + } // Ensure keys and node_id exist in config (generates them if missing) if (config_ensure_keys_and_node_id(config_file) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file); @@ -335,38 +338,8 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config return NULL; } - // Open log file only if not using global debug system output - if (config->global.log_file[0]) { - debug_set_output_file(config->global.log_file); - } - - // Apply debug level from config - if (config->global.debug_level[0]) { - debug_apply_global_level(config->global.debug_level); - } - - // Apply per-category debug levels from [debug] section - for (int i = 0; i < config->global.debug_levels.count; i++) { - debug_apply_category_config( - config->global.debug_levels.category[i], - config->global.debug_levels.level[i] - ); - } - - // Allocate instance - struct UTUN_INSTANCE *instance = u_calloc(1, sizeof(struct UTUN_INSTANCE)); - if (!instance) { - free_config(config); - return NULL; - } - instance->etcp_connect_timeout_tb = 20000; - - // Initialize using common function - if (instance_init_common(instance, ua, config) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_SYS, "Core creation failed; releasing all initialized resources"); - instance_destroy(instance, 1); - return NULL; - } + struct UTUN_INSTANCE* instance = utun_instance_create_from_config(ua, config); + if (!instance) { free_config(config); return NULL; } // Log instance info if (instance->name[0] != '\0') { @@ -382,10 +355,14 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config // Create instance from existing config structure (config ownership transfers to instance) struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct utun_config* config) { - if (!config) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "NULL config"); + if (!ua || !config) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "instance create requires uasync and config"); return NULL; } + if (config->global.log_file[0]) { + snprintf(g_config_log_path, sizeof(g_config_log_path), "%s", config->global.log_file); + debug_set_output_file(g_config_log_path); + } if (config->global.debug_level[0]) debug_apply_global_level(config->global.debug_level); @@ -412,15 +389,23 @@ struct UTUN_INSTANCE* utun_instance_create_from_config(struct UASYNC* ua, struct // Create instance from config text string (writes to temp file, parses, cleans up) struct UTUN_INSTANCE* utun_instance_create_from_str(struct UASYNC* ua, const char* config_text) { - if (!config_text) return NULL; + if (!ua || !config_text) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "instance create requires uasync and config text"); return NULL; } char tmp_path[] = "/tmp/utun_cfg_XXXXXX"; int fd = mkstemp(tmp_path); - if (fd < 0) return NULL; + if (fd < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "cannot create temporary config: %s", strerror(errno)); return NULL; } size_t len = strlen(config_text); - if (write(fd, config_text, len) != (ssize_t)len) { close(fd); unlink(tmp_path); return NULL; } - close(fd); + size_t written = 0; + int failed = 0; + while (written < len) { + ssize_t n = write(fd, config_text + written, len - written); + if (n < 0 && errno == EINTR) continue; + if (n <= 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "temporary config write failed at %zu: %s", written, strerror(errno)); failed = 1; break; } + written += (size_t)n; + } + if (close(fd)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "temporary config close failed: %s", strerror(errno)); failed = 1; } + if (failed) { if (unlink(tmp_path)) DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "temporary config cleanup failed: %s", strerror(errno)); return NULL; } struct UTUN_INSTANCE* inst = utun_instance_create(ua, tmp_path); - unlink(tmp_path); + if (unlink(tmp_path)) DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "temporary config cleanup failed: %s", strerror(errno)); return inst; } @@ -623,11 +608,6 @@ static void instance_destroy(struct UTUN_INSTANCE* instance, int owns_config) { // This allows sharing uasync between multiple instances instance->ua = NULL; - // Clear global instance - if (g_instance == instance) { - g_instance = NULL; - } - // Free the instance memory DEBUG_INFO(DEBUG_CATEGORY_SYS, "[INSTANCE_DESTROY] Freeing instance memory"); @@ -679,11 +659,20 @@ void utun_instance_stop(struct UTUN_INSTANCE *instance) { static int mkdir_recursive(const char *path) { char tmp[512]; int len = snprintf(tmp, sizeof(tmp), "%s", path); - if (len <= 0 || (size_t)len >= sizeof(tmp)) return -1; - for (char *p = tmp + 1; *p; p++) { - if (*p == '/') { *p = '\0'; utun_mkdir(tmp, 0755); *p = '/'; } + if (len <= 0 || (size_t)len >= sizeof(tmp)) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "invalid database directory length=%d", len); return -1; } + for (char *p = tmp + 1;; p++) { + if (*p && *p != '/') continue; + if (*p == '/' && p == tmp + 2 && tmp[1] == ':') continue; // Windows drive root + char saved = *p; *p = '\0'; + if (utun_mkdir(tmp, 0755) < 0) { + int err = errno; struct stat st; + if (err != EEXIST || stat(tmp, &st) < 0 || !S_ISDIR(st.st_mode)) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "cannot create database directory %s: %s", tmp, strerror(err)); return -1; + } + } + *p = saved; if (!saved) break; } - return utun_mkdir(tmp, 0755); + return 0; } int utun_core_start(struct UTUN_INSTANCE *instance) {