mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-05-10 19:00:57 +08:00
fix: deadlock in whisper, use-after-free in callbacks, log rotation, tail parsing
- Whisper: copy target client ref out of room lock before calling client_send, preventing lock-ordering inversion deadlock - Channel callbacks: call ssh_remove_channel_callbacks before releasing refs to prevent use-after-free if a callback fires during cleanup - Log rotation: rotate messages.log to messages.log.1 when it exceeds 10 MiB, preventing unbounded growth on public servers - tail -nN: accept both "tail -n5" and "tail -n 5" forms, matching standard Unix tail behavior Closes #36
This commit is contained in:
parent
e319c7aa42
commit
b1c1e5a894
3 changed files with 30 additions and 7 deletions
|
|
@ -22,6 +22,7 @@
|
|||
#define MAX_EXEC_COMMAND_LEN 1024
|
||||
#define MAX_CLIENTS 64
|
||||
#define LOG_FILE "messages.log"
|
||||
#define MAX_LOG_SIZE (10 * 1024 * 1024) /* 10 MiB */
|
||||
#define HOST_KEY_FILE "host_key"
|
||||
#define TNT_DEFAULT_STATE_DIR "."
|
||||
|
||||
|
|
|
|||
|
|
@ -227,7 +227,16 @@ int message_save(const message_t *msg) {
|
|||
rc = -1;
|
||||
}
|
||||
|
||||
/* Rotate if the log exceeds MAX_LOG_SIZE */
|
||||
long file_size = ftell(fp);
|
||||
fclose(fp);
|
||||
|
||||
if (file_size > MAX_LOG_SIZE) {
|
||||
char backup_path[PATH_MAX + 4];
|
||||
snprintf(backup_path, sizeof(backup_path), "%s.1", log_path);
|
||||
rename(log_path, backup_path);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_message_file_lock);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -895,7 +895,7 @@ static int parse_tail_count(const char *args, int *count) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (strncmp(args, "-n", 2) == 0 && isspace((unsigned char)args[2])) {
|
||||
if (strncmp(args, "-n", 2) == 0) {
|
||||
args += 2;
|
||||
while (*args && isspace((unsigned char)*args)) {
|
||||
args++;
|
||||
|
|
@ -1171,21 +1171,28 @@ static void execute_command(client_t *client) {
|
|||
" w <username> <message>\n");
|
||||
} else {
|
||||
bool found = false;
|
||||
client_t *target = NULL;
|
||||
pthread_rwlock_rdlock(&g_room->lock);
|
||||
for (int i = 0; i < g_room->client_count; i++) {
|
||||
if (strcmp(g_room->clients[i]->username, target_name) == 0) {
|
||||
char whisper[MAX_MESSAGE_LEN];
|
||||
snprintf(whisper, sizeof(whisper),
|
||||
"\r\n\033[35m[whisper from %s]: %s\033[0m\r\n",
|
||||
client->username, rest);
|
||||
client_send(g_room->clients[i], whisper, strlen(whisper));
|
||||
g_room->clients[i]->redraw_pending = true;
|
||||
target = g_room->clients[i];
|
||||
client_addref(target);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_rwlock_unlock(&g_room->lock);
|
||||
|
||||
if (target) {
|
||||
char whisper[MAX_MESSAGE_LEN];
|
||||
snprintf(whisper, sizeof(whisper),
|
||||
"\r\n\033[35m[whisper from %s]: %s\033[0m\r\n",
|
||||
client->username, rest);
|
||||
client_send(target, whisper, strlen(whisper));
|
||||
target->redraw_pending = true;
|
||||
client_release(target);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
buffer_appendf(output, sizeof(output), &pos,
|
||||
"Whisper sent to %s\n", target_name);
|
||||
|
|
@ -1649,6 +1656,12 @@ cleanup:
|
|||
|
||||
release_ip_connection(client->client_ip);
|
||||
|
||||
/* Remove channel callbacks before releasing refs to prevent use-after-free
|
||||
* if a callback fires between the two releases. */
|
||||
if (client->channel && client->channel_cb) {
|
||||
ssh_remove_channel_callbacks(client->channel, client->channel_cb);
|
||||
}
|
||||
|
||||
/* Release the callback reference (paired with addref before install_client_channel_callbacks) */
|
||||
client_release(client);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue