From: Vsevolod Stakhov Date: Thu, 23 Jul 2026 12:42:40 +0000 (+0100) Subject: [Fix] lua_http: bound HTTP responses by default X-Git-Tag: 4.1.3~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9fe7ae5f50697bad41493e7e14b7491a90de5d5a;p=thirdparty%2Frspamd.git [Fix] lua_http: bound HTTP responses by default Lua HTTP client responses were unlimited unless a plugin explicitly passed max_size, and a negative max_size was converted straight to an unsigned gsize, silently producing an effectively unlimited cap. Add a max_lua_http_response option (256Mb by default, 0 disables) applied as the reply body limit whenever a request does not specify max_size; an explicit max_size of 0 still disables the limit per request. Reject negative max_size values with a logged error instead of letting them wrap. --- diff --git a/src/libserver/cfg_file.h b/src/libserver/cfg_file.h index 3c7f357f81..9fa8ab4d32 100644 --- a/src/libserver/cfg_file.h +++ b/src/libserver/cfg_file.h @@ -395,6 +395,7 @@ struct rspamd_config { char *cores_dir; /**< directory for core files */ gsize max_message; /**< maximum size for messages */ gsize max_pic_size; /**< maximum size for a picture to process */ + gsize max_lua_http_response; /**< maximum size of a reply in the Lua HTTP client */ gsize images_cache_size; /**< size of LRU cache for DCT data from images */ double task_timeout; /**< maximum message processing time */ int default_max_shots; /**< default maximum count of symbols hits permitted (-1 for unlimited) */ diff --git a/src/libserver/cfg_rcl.cxx b/src/libserver/cfg_rcl.cxx index 5583524c6a..0134043014 100644 --- a/src/libserver/cfg_rcl.cxx +++ b/src/libserver/cfg_rcl.cxx @@ -2333,6 +2333,12 @@ rspamd_rcl_config_init(struct rspamd_config *cfg, GHashTable *skip_sections) G_STRUCT_OFFSET(struct rspamd_config, max_pic_size), RSPAMD_CL_FLAG_INT_SIZE, "Maximum size of the picture to be normalized (1Mb by default)"); + rspamd_rcl_add_default_handler(sub, + "max_lua_http_response", + rspamd_rcl_parse_struct_integer, + G_STRUCT_OFFSET(struct rspamd_config, max_lua_http_response), + RSPAMD_CL_FLAG_INT_SIZE, + "Maximum size of an HTTP reply in the Lua HTTP client when no explicit max_size is set (256Mb by default, 0 to disable the limit)"); rspamd_rcl_add_default_handler(sub, "images_cache", rspamd_rcl_parse_struct_integer, diff --git a/src/libserver/cfg_utils.cxx b/src/libserver/cfg_utils.cxx index 1c5ebd03c3..7e2386a861 100644 --- a/src/libserver/cfg_utils.cxx +++ b/src/libserver/cfg_utils.cxx @@ -93,6 +93,7 @@ #define DEFAULT_WORDS_DECAY 600 #define DEFAULT_MAX_MESSAGE (50 * 1024 * 1024) #define DEFAULT_MAX_PIC (1 * 1024 * 1024) +#define DEFAULT_MAX_LUA_HTTP_RESPONSE (256 * 1024 * 1024) #define DEFAULT_MAX_SHOTS 100 #define DEFAULT_MAX_SESSIONS 100 #define DEFAULT_MAX_WORKERS 4 @@ -353,6 +354,7 @@ rspamd_config_new(enum rspamd_config_init_flags flags) cfg->ssl_ciphers = rspamd_mempool_strdup(cfg->cfg_pool, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"); cfg->max_message = DEFAULT_MAX_MESSAGE; cfg->max_pic_size = DEFAULT_MAX_PIC; + cfg->max_lua_http_response = DEFAULT_MAX_LUA_HTTP_RESPONSE; cfg->images_cache_size = 256; cfg->monitored_ctx = rspamd_monitored_ctx_init(); cfg->neighbours = ucl_object_typed_new(UCL_OBJECT); diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c index 00814b7fcf..6c9cca0d1e 100644 --- a/src/lua/lua_http.c +++ b/src/lua/lua_http.c @@ -800,6 +800,7 @@ lua_http_push_headers(lua_State *L, struct rspamd_http_message *msg) * @param {string} mime_type MIME type of the HTTP content (for example, `text/html`) * @param {string/text} body full body content, can be opaque `rspamd{text}` to avoid data copying * @param {number} timeout floating point request timeout value in seconds (default is 5.0 seconds) + * @param {number} max_size maximum size of the reply body in bytes (default is the `max_lua_http_response` global option, 256Mb; 0 disables the limit) * @param {resolver} resolver to perform DNS-requests. Usually got from either `task` or `config` * @param {boolean} gzip if true, body of the requests will be compressed * @param {boolean} no_ssl_verify disable SSL peer checks @@ -839,7 +840,7 @@ lua_http_request(lua_State *L) int flags = 0; char *mime_type = NULL; char *auth = NULL; - gsize max_size = 0; + gssize max_size = -1; /* -1 = use the global default; 0 = unlimited */ gboolean gzip = FALSE; if (lua_gettop(L) >= 2) { @@ -1166,7 +1167,15 @@ lua_http_request(lua_State *L) lua_gettable(L, 1); if (lua_type(L, -1) == LUA_TNUMBER) { - max_size = lua_tointeger(L, -1); + lua_Integer i = lua_tointeger(L, -1); + + if (i >= 0) { + max_size = i; + } + else { + msg_err_task_check("ignore negative max_size %L in HTTP request to %s", + (int64_t) i, url); + } } lua_pop(L, 1); @@ -1286,7 +1295,12 @@ lua_http_request(lua_State *L) cbd->peer_pk = peer_key; cbd->local_kp = local_kp; cbd->flags = flags; - cbd->max_size = max_size; + if (max_size >= 0) { + cbd->max_size = max_size; + } + else { + cbd->max_size = cfg ? cfg->max_lua_http_response : 0; + } cbd->url = url; cbd->auth = auth; cbd->task = task;