From 30029bdcc7b3fbddf1476abc37507aaf42f95bc3 Mon Sep 17 00:00:00 2001 From: Liviu Chircu Date: Wed, 17 Nov 2021 15:29:30 +0200 Subject: [PATCH] rest_client: Add the 'max_transfer_size' setting Sets a limit on the maximum size of a single download. May be important for security purposes, to prevent certain attack vectors such as malicious "x5u" certificate URLs in STIR/SHAKEN setups. Default: 0 KB (check disabled) Issue discovered during OpenSIPIt'02, by Alfred Farrugia & Sandro Gauci (Enable Security) (cherry picked from commit b56bba344e0c067ee7af53bdd1add9ed05b403f3) --- modules/rest_client/doc/rest_client_admin.xml | 23 +++++++++++++++++++ modules/rest_client/rest_cb.c | 11 ++++++--- modules/rest_client/rest_cb.h | 2 ++ modules/rest_client/rest_client.c | 2 ++ modules/rest_client/rest_client.h | 1 + 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/modules/rest_client/doc/rest_client_admin.xml b/modules/rest_client/doc/rest_client_admin.xml index 24cc656b98b..adf5189cb1d 100644 --- a/modules/rest_client/doc/rest_client_admin.xml +++ b/modules/rest_client/doc/rest_client_admin.xml @@ -147,6 +147,29 @@ modparam("rest_client", "max_async_transfers", 300) +
+ <varname>max_transfer_size</varname> (integer) + + The maximum allowed size of a single transfer (download). Reaching + this limit during a transfer will cause the transfer to stop + immediately, returning error -10 at script level. A value of + 0 will disable the check. + + + + Default value is 0 (KB). + + + + Setting the <varname>max_transfer_size</varname> parameter + +... +modparam("rest_client", "max_transfer_size", 64) +... + + +
+
<varname>ssl_verifypeer</varname> (integer) diff --git a/modules/rest_client/rest_cb.c b/modules/rest_client/rest_cb.c index 53fc46f16ea..d2d0d887f98 100644 --- a/modules/rest_client/rest_cb.c +++ b/modules/rest_client/rest_cb.c @@ -34,6 +34,8 @@ * @size: size of a block * @nmemb: number of blocks * @body: parameter previously set with the CURLOPT_WRITEDATA option + * + * Return: number of bytes processed (if != @len, transfer is aborted) */ size_t write_func(char *ptr, size_t size, size_t nmemb, void *body) { @@ -47,14 +49,17 @@ size_t write_func(char *ptr, size_t size, size_t nmemb, void *body) if (len == 0) return 0; - if (len < 0) - len = strlen(ptr); + if (max_transfer_size && buff->len + len > max_transfer_size * 1024UL) { + LM_ERR("max download size exceeded (%u KB, per 'max_transfer_size'), " + "aborting transfer\n", max_transfer_size); + return 0; + } buff->s = pkg_realloc(buff->s, buff->len + len + 1); if (!buff->s) { buff->len = 0; LM_ERR("No more pkg memory!\n"); - return E_OUT_OF_MEM; + return 0; } memcpy(buff->s + buff->len, ptr, len); diff --git a/modules/rest_client/rest_cb.h b/modules/rest_client/rest_cb.h index 23affe1bde0..2f40349351f 100644 --- a/modules/rest_client/rest_cb.h +++ b/modules/rest_client/rest_cb.h @@ -25,6 +25,8 @@ #ifndef _REST_CB_H_ #define _REST_CB_H_ +#include "rest_client.h" + #include "../../str.h" #include "../../mem/mem.h" #include "../../error.h" diff --git a/modules/rest_client/rest_client.c b/modules/rest_client/rest_client.c index 8b2826cfa5b..a9404f79568 100644 --- a/modules/rest_client/rest_client.c +++ b/modules/rest_client/rest_client.c @@ -51,6 +51,7 @@ long connection_timeout_ms; int max_async_transfers = 100; long curl_timeout = 20; char *ssl_capath; +unsigned int max_transfer_size = 0; /* KB */ /* * curl_multi_perform() may indicate a "try again" response even @@ -196,6 +197,7 @@ static param_export_t params[] = { { "connection_timeout", INT_PARAM, &connection_timeout }, { "connect_poll_interval", INT_PARAM, &connect_poll_interval }, { "max_async_transfers", INT_PARAM, &max_async_transfers }, + { "max_transfer_size", INT_PARAM, &max_transfer_size }, { "curl_timeout", INT_PARAM, &curl_timeout }, { "ssl_capath", STR_PARAM, &ssl_capath }, { "ssl_verifypeer", INT_PARAM, &ssl_verifypeer }, diff --git a/modules/rest_client/rest_client.h b/modules/rest_client/rest_client.h index 2c786b69eac..6ae9e2e79d0 100644 --- a/modules/rest_client/rest_client.h +++ b/modules/rest_client/rest_client.h @@ -31,5 +31,6 @@ enum tr_rest_subtype { }; extern int enable_expect_100; +extern unsigned int max_transfer_size; #endif /* _REST_CLIENT_ */