From 68beecef0a2a07649b05cc9723662f11ebdd52f3 Mon Sep 17 00:00:00 2001 From: jfreegman Date: Wed, 28 Feb 2024 11:31:19 -0500 Subject: [PATCH] feat: hard cap the size of a session chat log to 100 MiB This mitigates a potential DOS attack vector. --- src/log.c | 24 +++++++++++++++++++++--- src/log.h | 10 ++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/log.c b/src/log.c index 2d4e1a3d8..81f812a87 100644 --- a/src/log.c +++ b/src/log.c @@ -124,7 +124,13 @@ static int init_logging_session(const Client_Config *c_config, const char *name, return 0; } -#define LOG_FLUSH_LIMIT 1 /* limits calls to fflush to a max of one per LOG_FLUSH_LIMIT seconds */ +/* limits calls to fflush to a max of one per LOG_FLUSH_LIMIT seconds */ +#define LOG_FLUSH_LIMIT 1 + +/* We stop writing to the log after we've written at least this many bytes during the current session. + * A new session is started with `log_enable()`, and ended with `log_disable()`. + */ +#define LOG_BYTES_THRESHOLD ((1024 << 10) * 100) // 100 MiB int write_to_log(struct chatlog *log, const Client_Config *c_config, const char *msg, const char *name, bool is_event, Log_Hint log_hint) @@ -142,6 +148,11 @@ int write_to_log(struct chatlog *log, const Client_Config *c_config, const char return -1; } + if (log->bytes_written >= LOG_BYTES_THRESHOLD) { + fprintf(stderr, "Warning: Log file is full (%u bytes written)\n", log->bytes_written); + return -1; + } + char name_frmt[TOXIC_MAX_NAME_LENGTH + 3]; if (name != NULL) { @@ -156,10 +167,12 @@ int write_to_log(struct chatlog *log, const Client_Config *c_config, const char char s[MAX_STR_SIZE]; get_time_str(s, sizeof(s), t); + int bytes_written; + if (name == NULL) { - fprintf(log->file, "{%d} %s %s\n", log_hint, s, msg); + bytes_written = fprintf(log->file, "{%d} %s %s\n", log_hint, s, msg); } else { - fprintf(log->file, "{%d} %s %s %s\n", log_hint, s, name_frmt, msg); + bytes_written = fprintf(log->file, "{%d} %s %s %s\n", log_hint, s, name_frmt, msg); } if (timed_out(log->lastwrite, LOG_FLUSH_LIMIT)) { @@ -167,6 +180,10 @@ int write_to_log(struct chatlog *log, const Client_Config *c_config, const char log->lastwrite = get_unix_time(); } + if (bytes_written > 0) { + log->bytes_written += bytes_written; + } + return 0; } @@ -183,6 +200,7 @@ void log_disable(struct chatlog *log) log->lastwrite = 0; log->log_on = false; + log->bytes_written = 0; } int log_enable(struct chatlog *log) diff --git a/src/log.h b/src/log.h index ec1557d93..f0c171ebd 100644 --- a/src/log.h +++ b/src/log.h @@ -30,6 +30,7 @@ struct chatlog { time_t lastwrite; char path[MAX_STR_SIZE]; bool log_on; /* specific to current chat window */ + uint32_t bytes_written; }; typedef enum Log_Type { @@ -75,14 +76,19 @@ int log_init(struct chatlog *log, const Client_Config *c_config, const char *nam int write_to_log(struct chatlog *log, const Client_Config *c_config, const char *msg, const char *name, bool is_event, Log_Hint log_hint); -/* enables logging for specified log. +/* Enables logging for specified log. + * + * Calling this function on a log that's already enabled has no effect. * * Returns 0 on success. * Returns -1 on failure. */ int log_enable(struct chatlog *log); -/* disables logging for specified log and closes file */ +/* Disables logging for specified log and closes file. + * + * Calling this function on a log that's already disabled has no effect. + */ void log_disable(struct chatlog *log); /* Loads chat log history and prints it to `self` window.