G_STRUCT_OFFSET(struct rspamd_config, maps_cache_dir),
0,
"Directory to save maps cached data (default: $DBDIR)");
+ rspamd_rcl_add_default_handler(sub,
+ "max_map_size",
+ rspamd_rcl_parse_struct_integer,
+ G_STRUCT_OFFSET(struct rspamd_config, max_map_size),
+ RSPAMD_CL_FLAG_INT_SIZE,
+ "Maximum size of a map, compressed or expanded (256Mb by default, 0 to disable the limit)");
rspamd_rcl_add_default_handler(sub,
"monitoring_watch_interval",
rspamd_rcl_parse_struct_time,
#define DEFAULT_RLIMIT_MAXCORE 0
#define DEFAULT_MAP_TIMEOUT 60.0 * 5
#define DEFAULT_MAP_FILE_WATCH_MULTIPLIER 1
+#define DEFAULT_MAX_MAP_SIZE (256 * 1024 * 1024)
#define DEFAULT_MIN_WORD 0
#define DEFAULT_MAX_WORD 40
#define DEFAULT_WORDS_DECAY 600
cfg->map_timeout = DEFAULT_MAP_TIMEOUT;
cfg->map_file_watch_multiplier = DEFAULT_MAP_FILE_WATCH_MULTIPLIER;
+ cfg->max_map_size = DEFAULT_MAX_MAP_SIZE;
cfg->log_level = G_LOG_LEVEL_WARNING;
cfg->log_flags = RSPAMD_LOG_FLAG_DEFAULT;
return FALSE;
}
+static inline gsize
+rspamd_map_effective_max_size(struct http_callback_data *cbd)
+{
+ if (cbd->data->max_size > 0) {
+ return cbd->data->max_size;
+ }
+
+ return cbd->map->cfg ? cbd->map->cfg->max_map_size : 0;
+}
+
static void
rspamd_map_try_load_secretbox_key(struct rspamd_config *cfg,
struct rspamd_map_backend *bk)
ZSTD_inBuffer zin;
ZSTD_outBuffer zout;
gsize outlen, r;
-
- zstream = ZSTD_createDStream();
- ZSTD_initDStream(zstream);
+ gsize max_size = rspamd_map_effective_max_size(cbd);
zin.pos = 0;
zin.src = payload;
if ((outlen = ZSTD_getDecompressedSize(zin.src, zin.size)) == 0) {
outlen = ZSTD_DStreamOutSize();
}
+ else if (max_size > 0 && outlen > max_size) {
+ msg_err_map("%s(%s): declared decompressed size %z exceeds max_map_size %z",
+ cbd->bk->uri,
+ rspamd_inet_address_to_string_pretty(cbd->addr),
+ outlen, max_size);
+ if (cbd->bk->is_encrypted && payload && payload != (unsigned char *) in) {
+ rspamd_explicit_memzero(payload, payload_len);
+ g_free(payload);
+ }
+ MAP_RELEASE(cbd->shmem_data, "shmem_data");
+ goto err;
+ }
+
+ zstream = ZSTD_createDStream();
+ ZSTD_initDStream(zstream);
final_out = g_malloc(outlen);
if (zout.pos == zout.size) {
/* We need to extend output buffer */
+ if (max_size > 0 && zout.size >= max_size) {
+ msg_err_map("%s(%s): decompressed data exceeds max_map_size %z",
+ cbd->bk->uri,
+ rspamd_inet_address_to_string_pretty(cbd->addr),
+ max_size);
+ ZSTD_freeDStream(zstream);
+ g_free(final_out);
+ if (cbd->bk->is_encrypted && payload && payload != (unsigned char *) in) {
+ rspamd_explicit_memzero(payload, payload_len);
+ g_free(payload);
+ }
+ MAP_RELEASE(cbd->shmem_data, "shmem_data");
+ goto err;
+ }
+
zout.size = zout.size * 2 + 1.0;
+
+ if (max_size > 0 && zout.size > max_size) {
+ zout.size = max_size;
+ }
+
final_out = g_realloc(zout.dst, zout.size);
zout.dst = final_out;
}
cbd->addr);
if (cbd->conn != NULL) {
+ gsize max_size = rspamd_map_effective_max_size(cbd);
+
+ if (max_size > 0) {
+ rspamd_http_connection_set_max_size(cbd->conn, max_size);
+ }
/* Apply optional staged timeouts and keepalive tuning */
if (cbd->data->connect_timeout > 0 || cbd->data->ssl_timeout > 0 ||
cbd->data->write_timeout > 0 || cbd->data->read_timeout > 0) {
addr);
if (cbd->conn != NULL) {
+ gsize max_size = rspamd_map_effective_max_size(cbd);
+
+ if (max_size > 0) {
+ rspamd_http_connection_set_max_size(cbd->conn, max_size);
+ }
/* Apply optional staged timeouts and keepalive tuning */
if (cbd->data->connect_timeout > 0 || cbd->data->ssl_timeout > 0 ||
cbd->data->write_timeout > 0 || cbd->data->read_timeout > 0) {
opt = ucl_object_lookup_any(src,
"max_reuse", "max-reuse", "keepalive_max_reuse", NULL);
if (opt) hdata->max_reuse = (unsigned int) ucl_object_toint(opt);
+ opt = ucl_object_lookup_any(src,
+ "max_size", "max-size", NULL);
+ if (opt) hdata->max_size = (gsize) ucl_object_toint(opt);
}
}
double connection_ttl;
double idle_timeout;
unsigned int max_reuse;
+ /* Optional per-map size limit; 0 means use cfg->max_map_size */
+ gsize max_size;
};
struct static_map_data {
double poll_timeout;
time_t next_check;
bool active_http;
- bool non_trivial; /* E.g. has http backends in active mode */
- bool file_only; /* No HTTP backends found */
- bool static_only; /* No need to check */
- bool no_file_read; /* Do not read files, pass filename to consumer */
- bool seen; /* This map has already been watched or pre-loaded */
+ bool non_trivial; /* E.g. has http backends in active mode */
+ bool file_only; /* No HTTP backends found */
+ bool static_only; /* No need to check */
+ bool no_file_read; /* Do not read files, pass filename to consumer */
+ bool seen; /* This map has already been watched or pre-loaded */
gsize no_file_read_offset; /* Payload offset when consumer mmaps the file (0 for file, 4096 for HTTP cache) */
/* Shared lock for temporary disabling of map reading (e.g. when this map is written by UI) */
struct rspamd_map_shared_data *shared;