v0.7.17 - Fixed critical race condition in CLOSE message handler causing segfault during subscription storms
This commit is contained in:
@@ -89,9 +89,9 @@ RUN cd nostr_core_lib && \
|
|||||||
COPY src/ /build/src/
|
COPY src/ /build/src/
|
||||||
COPY Makefile /build/Makefile
|
COPY Makefile /build/Makefile
|
||||||
|
|
||||||
# Build c-relay with full static linking (only rebuilds when src/ changes)
|
# Build c-relay with full static linking and debug symbols (only rebuilds when src/ changes)
|
||||||
# Disable fortification to avoid __*_chk symbols that don't exist in MUSL
|
# Disable fortification to avoid __*_chk symbols that don't exist in MUSL
|
||||||
RUN gcc -static -O2 -Wall -Wextra -std=c99 \
|
RUN gcc -static -g -O0 -DDEBUG -Wall -Wextra -std=c99 \
|
||||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||||
-I. -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
-I. -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
||||||
@@ -103,8 +103,8 @@ RUN gcc -static -O2 -Wall -Wextra -std=c99 \
|
|||||||
-lwebsockets -lssl -lcrypto -lsqlite3 -lsecp256k1 \
|
-lwebsockets -lssl -lcrypto -lsqlite3 -lsecp256k1 \
|
||||||
-lcurl -lz -lpthread -lm -ldl
|
-lcurl -lz -lpthread -lm -ldl
|
||||||
|
|
||||||
# Strip binary to reduce size
|
# DO NOT strip - we need debug symbols for debugging
|
||||||
RUN strip /build/c_relay_static
|
# RUN strip /build/c_relay_static
|
||||||
|
|
||||||
# Verify it's truly static
|
# Verify it's truly static
|
||||||
RUN echo "=== Binary Information ===" && \
|
RUN echo "=== Binary Information ===" && \
|
||||||
|
|||||||
@@ -1086,19 +1086,30 @@ int send_nip17_response(const char* sender_pubkey, const char* response_content,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the gift wrap in database
|
// Broadcast FIRST before storing (broadcasting needs the event intact)
|
||||||
|
// Make a copy for broadcasting to avoid use-after-free issues
|
||||||
|
cJSON* gift_wrap_copy = cJSON_Duplicate(gift_wraps[0], 1);
|
||||||
|
if (!gift_wrap_copy) {
|
||||||
|
cJSON_Delete(gift_wraps[0]);
|
||||||
|
strncpy(error_message, "NIP-17: Failed to duplicate gift wrap for broadcast", error_size - 1);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast the copy to active subscriptions
|
||||||
|
broadcast_event_to_subscriptions(gift_wrap_copy);
|
||||||
|
|
||||||
|
// Store the original in database
|
||||||
int store_result = store_event(gift_wraps[0]);
|
int store_result = store_event(gift_wraps[0]);
|
||||||
|
|
||||||
|
// Clean up both copies
|
||||||
|
cJSON_Delete(gift_wrap_copy);
|
||||||
|
cJSON_Delete(gift_wraps[0]);
|
||||||
|
|
||||||
if (store_result != 0) {
|
if (store_result != 0) {
|
||||||
cJSON_Delete(gift_wraps[0]);
|
|
||||||
strncpy(error_message, "NIP-17: Failed to store response gift wrap", error_size - 1);
|
strncpy(error_message, "NIP-17: Failed to store response gift wrap", error_size - 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast the response event to active subscriptions
|
|
||||||
broadcast_event_to_subscriptions(gift_wraps[0]);
|
|
||||||
|
|
||||||
cJSON_Delete(gift_wraps[0]);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -895,10 +895,9 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from global manager
|
// CRITICAL FIX: Remove from session list FIRST (while holding lock)
|
||||||
remove_subscription_from_manager(subscription_id, wsi);
|
// to prevent race condition where global manager frees the subscription
|
||||||
|
// while we're still iterating through the session list
|
||||||
// Remove from session list if present
|
|
||||||
if (pss) {
|
if (pss) {
|
||||||
pthread_mutex_lock(&pss->session_lock);
|
pthread_mutex_lock(&pss->session_lock);
|
||||||
|
|
||||||
@@ -916,6 +915,10 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
|||||||
pthread_mutex_unlock(&pss->session_lock);
|
pthread_mutex_unlock(&pss->session_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove from global manager AFTER removing from session list
|
||||||
|
// This prevents use-after-free when iterating session subscriptions
|
||||||
|
remove_subscription_from_manager(subscription_id, wsi);
|
||||||
|
|
||||||
// Subscription closed
|
// Subscription closed
|
||||||
} else {
|
} else {
|
||||||
send_notice_message(wsi, "error: missing or invalid subscription ID in CLOSE");
|
send_notice_message(wsi, "error: missing or invalid subscription ID in CLOSE");
|
||||||
|
|||||||
Reference in New Issue
Block a user