MT#63826 db_redis: add string key length protection

Introduce a list of improvements for size overflow
protection:
- change func signatures to work with `size_t` only
- check the raw pointer and its length
- introduce optional max allowed keys size

This measure will protect inserts from extremely
large key size (e.g. negative length that then
gets into integer overflow) and from triggering
the stack canary.

Change-Id: I7e07e28b0ae398675f9980f42fe2b0f8ed61d51f
(cherry picked from commit c1876f6bae)
mr13.5
Donat Zenichev 5 months ago
parent ebd0cd71f6
commit 6fed6ff029

@ -44,6 +44,7 @@ sipwise/usrloc-don-t-synchronize-on-destroy-for-DB_ONLY.patch
sipwise/presence_offline_cleanup.patch sipwise/presence_offline_cleanup.patch
### active development ### active development
sipwise/permissions-don-t-allow-reloads-in-the-middle-of-ong.patch sipwise/permissions-don-t-allow-reloads-in-the-middle-of-ong.patch
sipwise/db_redis_protect_length_overflow.patch
### Don't just put stuff in any order ### Don't just put stuff in any order
### use gbp pq import/export tooling to help maintain patches ### use gbp pq import/export tooling to help maintain patches
### ###

@ -0,0 +1,121 @@
--- a/src/modules/db_redis/db_redis_mod.c
+++ b/src/modules/db_redis/db_redis_mod.c
@@ -42,6 +42,7 @@ MODULE_VERSION
str redis_keys = str_init("");
str redis_schema_path = str_init(SHARE_DIR "db_redis/kamailio");
int db_redis_verbosity = 1;
+unsigned int db_redis_max_key_len = 0;
static int db_redis_bind_api(db_func_t *dbb);
static int mod_init(void);
@@ -60,6 +61,7 @@ static param_export_t params[] = {
{"keys", PARAM_STRING | PARAM_USE_FUNC, (void *)keys_param},
{"schema_path", PARAM_STR, &redis_schema_path},
{"verbosity", PARAM_INT, &db_redis_verbosity},
+ {"max_key_length", PARAM_INT, &db_redis_max_key_len},
#ifdef WITH_SSL
{"opt_tls", PARAM_INT, &db_redis_opt_tls},
{"ca_path", PARAM_STRING, &db_redis_ca_path},
--- a/src/modules/db_redis/redis_dbase.c
+++ b/src/modules/db_redis/redis_dbase.c
@@ -876,7 +876,7 @@ static int db_redis_scan_query_keys_patt
LM_ERR("Failed to add scan command to scan query\n");
goto err;
}
- if(db_redis_key_add_string(&query_v, index_key->s, index_key->len)
+ if(db_redis_key_add_str(&query_v, index_key)
!= 0) {
LM_ERR("Failed to add scan command to scan query\n");
goto err;
@@ -891,8 +891,7 @@ static int db_redis_scan_query_keys_patt
LM_ERR("Failed to add match command to scan query\n");
goto err;
}
- if(db_redis_key_add_string(
- &query_v, match_pattern->s, match_pattern->len)
+ if (db_redis_key_add_str(&query_v, match_pattern)
!= 0) {
LM_ERR("Failed to add match pattern to scan query\n");
goto err;
@@ -907,7 +906,7 @@ static int db_redis_scan_query_keys_patt
LM_ERR("Failed to print integer for scan query\n");
goto err;
}
- if(db_redis_key_add_string(&query_v, match_count_str, l) != 0) {
+ if(db_redis_key_add_string(&query_v, match_count_str, (size_t)l) != 0) {
LM_ERR("Failed to add count value to scan query\n");
goto err;
}
--- a/src/modules/db_redis/redis_table.c
+++ b/src/modules/db_redis/redis_table.c
@@ -24,14 +24,24 @@
#include <sys/stat.h>
#include <dirent.h>
-#include "db_redis_mod.h"
-#include "redis_connection.h"
#include "redis_table.h"
-int db_redis_key_add_string(redis_key_t **list, const char *entry, int len)
+extern unsigned int db_redis_max_key_len;
+
+int db_redis_key_add_string(redis_key_t **list, const char *entry, size_t len)
{
redis_key_t *k;
+ if (!entry || !len) {
+ LM_ERR("Empty entry or zero length\n");
+ return -1;
+ }
+
+ if (db_redis_max_key_len > 0 && len > db_redis_max_key_len) {
+ LM_ERR("Too big length for key being added: allowed '%u' / given '%zu'\n",
+ db_redis_max_key_len, len);
+ return -1;
+ }
k = (redis_key_t *)pkg_malloc(sizeof(redis_key_t));
if(!k) {
@@ -69,13 +79,26 @@ err:
int db_redis_key_add_str(redis_key_t **list, const str *entry)
{
- return db_redis_key_add_string(list, entry->s, entry->len);
+ if (entry->len < 0)
+ return -1;
+ return db_redis_key_add_string(list, entry->s, (size_t)entry->len);
}
-int db_redis_key_prepend_string(redis_key_t **list, const char *entry, int len)
+int db_redis_key_prepend_string(redis_key_t **list, const char *entry, size_t len)
{
redis_key_t *k;
+ if (!entry || !len) {
+ LM_ERR("Empty entry or zero length\n");
+ return -1;
+ }
+
+ if (db_redis_max_key_len > 0 && len > db_redis_max_key_len) {
+ LM_ERR("Too big length for key being prepended: allowed '%u' / given '%zu'\n",
+ db_redis_max_key_len, len);
+ return -1;
+ }
+
k = (redis_key_t *)pkg_malloc(sizeof(redis_key_t));
if(!k) {
LM_ERR("Failed to allocate memory for key list entry\n");
--- a/src/modules/db_redis/redis_table.h
+++ b/src/modules/db_redis/redis_table.h
@@ -61,9 +61,9 @@ void db_redis_free_tables(km_redis_con_t
int db_redis_parse_schema(km_redis_con_t *con);
int db_redis_parse_keys(km_redis_con_t *con);
-int db_redis_key_add_string(redis_key_t **list, const char *entry, int len);
+int db_redis_key_add_string(redis_key_t **list, const char *entry, size_t len);
int db_redis_key_add_str(redis_key_t **list, const str *entry);
-int db_redis_key_prepend_string(redis_key_t **list, const char *entry, int len);
+int db_redis_key_prepend_string(redis_key_t **list, const char *entry, size_t len);
int db_redis_key_list2arr(redis_key_t *list, char ***arr);
redis_key_t *db_redis_key_shift(redis_key_t **list);
void db_redis_key_free(redis_key_t **list);
Loading…
Cancel
Save