Fix wssshc SIGINT crashes and multiple tunnel closure issues

- Fix double-free corruption in cleanup_tunnel by removing SSL freeing
- Add global shutdown flag for proper thread synchronization
- Improve SIGINT handling with better thread cleanup timing
- Send tunnel_close acknowledgment when receiving tunnel_close from server
- Prevent threads from accessing freed tunnel structures
- Ensure proper resource management during shutdown
parent 6d1bf50b
...@@ -41,6 +41,9 @@ int active_tunnels_count = 0; ...@@ -41,6 +41,9 @@ int active_tunnels_count = 0;
int active_tunnels_capacity = 0; int active_tunnels_capacity = 0;
pthread_mutex_t tunnel_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t tunnel_mutex = PTHREAD_MUTEX_INITIALIZER;
// Global shutdown flag for threads
volatile int global_shutdown = 0;
frame_buffer_t *frame_buffer_init() { frame_buffer_t *frame_buffer_init() {
frame_buffer_t *fb = malloc(sizeof(frame_buffer_t)); frame_buffer_t *fb = malloc(sizeof(frame_buffer_t));
if (!fb) return NULL; if (!fb) return NULL;
...@@ -257,6 +260,9 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug, const ch ...@@ -257,6 +260,9 @@ void handle_tunnel_request(SSL *ssl, const char *request_id, int debug, const ch
void cleanup_tunnel(int debug) { void cleanup_tunnel(int debug) {
pthread_mutex_lock(&tunnel_mutex); pthread_mutex_lock(&tunnel_mutex);
// Set global shutdown flag to signal all threads to stop
global_shutdown = 1;
// First, mark all tunnels as inactive to signal threads to stop // First, mark all tunnels as inactive to signal threads to stop
for (int i = 0; i < active_tunnels_count; i++) { for (int i = 0; i < active_tunnels_count; i++) {
if (active_tunnels[i]) { if (active_tunnels[i]) {
...@@ -264,12 +270,12 @@ void cleanup_tunnel(int debug) { ...@@ -264,12 +270,12 @@ void cleanup_tunnel(int debug) {
} }
} }
// Give threads a moment to stop using SSL connections // Give threads a moment to stop using resources
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
usleep(100000); // 100ms usleep(200000); // 200ms - increased timeout for better thread cleanup
pthread_mutex_lock(&tunnel_mutex); pthread_mutex_lock(&tunnel_mutex);
// Now safely clean up // Now safely clean up - don't free SSL contexts as they're managed at connection level
for (int i = 0; i < active_tunnels_count; i++) { for (int i = 0; i < active_tunnels_count; i++) {
if (active_tunnels[i]) { if (active_tunnels[i]) {
if (active_tunnels[i]->sock >= 0) { if (active_tunnels[i]->sock >= 0) {
...@@ -284,10 +290,10 @@ void cleanup_tunnel(int debug) { ...@@ -284,10 +290,10 @@ void cleanup_tunnel(int debug) {
close(active_tunnels[i]->local_sock); close(active_tunnels[i]->local_sock);
active_tunnels[i]->local_sock = -1; active_tunnels[i]->local_sock = -1;
} }
if (active_tunnels[i]->ssl) { // Don't free SSL here - it's managed at the connection level
SSL_free(active_tunnels[i]->ssl); // Just set the pointer to NULL to prevent use-after-free
active_tunnels[i]->ssl = NULL; active_tunnels[i]->ssl = NULL;
}
if (active_tunnels[i]->outgoing_buffer) { if (active_tunnels[i]->outgoing_buffer) {
frame_buffer_free(active_tunnels[i]->outgoing_buffer); frame_buffer_free(active_tunnels[i]->outgoing_buffer);
} }
...@@ -787,7 +793,7 @@ void send_tunnel_close(SSL *ssl, const char *request_id, int debug) { ...@@ -787,7 +793,7 @@ void send_tunnel_close(SSL *ssl, const char *request_id, int debug) {
} }
} }
void handle_tunnel_close(SSL *ssl __attribute__((unused)), const char *request_id, int debug) { void handle_tunnel_close(SSL *ssl, const char *request_id, int debug) {
pthread_mutex_lock(&tunnel_mutex); pthread_mutex_lock(&tunnel_mutex);
tunnel_t *tunnel = find_tunnel_by_request_id(request_id); tunnel_t *tunnel = find_tunnel_by_request_id(request_id);
if (tunnel) { if (tunnel) {
...@@ -797,6 +803,8 @@ void handle_tunnel_close(SSL *ssl __attribute__((unused)), const char *request_i ...@@ -797,6 +803,8 @@ void handle_tunnel_close(SSL *ssl __attribute__((unused)), const char *request_i
printf("[DEBUG - Tunnel] Tunnel %s closed\n", request_id); printf("[DEBUG - Tunnel] Tunnel %s closed\n", request_id);
fflush(stdout); fflush(stdout);
} }
// Send tunnel_close back to server to acknowledge
send_tunnel_close(ssl, request_id, debug);
} }
pthread_mutex_unlock(&tunnel_mutex); pthread_mutex_unlock(&tunnel_mutex);
} }
......
...@@ -57,6 +57,7 @@ extern int active_tunnels_count; ...@@ -57,6 +57,7 @@ extern int active_tunnels_count;
extern int active_tunnels_capacity; extern int active_tunnels_capacity;
extern pthread_mutex_t tunnel_mutex; extern pthread_mutex_t tunnel_mutex;
extern pthread_mutex_t ssl_mutex; // For synchronizing SSL operations extern pthread_mutex_t ssl_mutex; // For synchronizing SSL operations
extern volatile int global_shutdown; // Global flag to signal threads to stop
// Function declarations // Function declarations
frame_buffer_t *frame_buffer_init(void); frame_buffer_t *frame_buffer_init(void);
......
...@@ -253,6 +253,9 @@ int connect_to_server(const wssshc_config_t *config) { ...@@ -253,6 +253,9 @@ int connect_to_server(const wssshc_config_t *config) {
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
int bytes_read; int bytes_read;
// Reset global shutdown flag for new connection
global_shutdown = 0;
// Clean up any leftover tunnel state from previous connection // Clean up any leftover tunnel state from previous connection
cleanup_tunnel(config->debug); cleanup_tunnel(config->debug);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment