]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] lua_http: bound HTTP responses by default
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 23 Jul 2026 12:42:40 +0000 (13:42 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 23 Jul 2026 12:42:40 +0000 (13:42 +0100)
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.

src/libserver/cfg_file.h
src/libserver/cfg_rcl.cxx
src/libserver/cfg_utils.cxx
src/lua/lua_http.c

index 3c7f357f816d3cc54ff03269518b7590f0f9b4af..9fa8ab4d32baad9db9c7f7413ad8b26052ae5dc2 100644 (file)
@@ -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) */
index 5583524c6a335852482f894e05be6bf2a5884dfd..0134043014d99a0745eb796802be8a7f74822b81 100644 (file)
@@ -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,
index 1c5ebd03c39cb7408720a7583eebd65cd49d7aae..7e2386a861a6698340bd01035ee6093dc4473de1 100644 (file)
@@ -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);
index 00814b7fcf1830c6e62ed2566823928634a86682..6c9cca0d1ed1631c701fab38da7eee79a4a6168d 100644 (file)
@@ -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;