roehling / postsrsd

Postfix Sender Rewriting Scheme daemon
327 stars 39 forks source link

Segfault when using redis through a unix socket #146

Closed timo-schluessler closed 1 year ago

timo-schluessler commented 1 year ago

Null pointer dereference in db_redis_write because redisCommand returns NULL because the redis handle is in error state because redisEnableKeepalive fails when used with unix socket connections (see this note).

Possible fix:

diff --git a/src/database.c b/src/database.c
index 0451796..3773f90 100644
--- a/src/database.c
+++ b/src/database.c
@@ -184,6 +184,10 @@ static char* db_redis_read(database_t* db, const char* key)
     redisContext* handle = (redisContext*)db->handle;
     redisReply* reply = redisCommand(handle, "GET %s", buffer);
     char* value = NULL;
+    if (!reply) {
+        log_err("redis read error: %s", handle->errstring);
+        return value;
+    }
     if (reply->type == REDIS_REPLY_ERROR)
     {
         log_warn("redis read error: %s", reply->str);
@@ -205,6 +209,11 @@ static bool db_redis_write(database_t* db, const char* key, const char* value,
     bool success = true;
     redisReply* reply =
         redisCommand(handle, "SETEX %s %u %s", buffer, lifetime, value);
+    if (!reply)
+    {
+        log_err("redis write error: %s", handle->errstring);
+        return false;
+    }
     if (reply->type == REDIS_REPLY_ERROR)
     {
         log_warn("redis write error: %s", reply->str);
@@ -223,6 +232,7 @@ static void db_redis_disconnect(database_t* db)
 static bool db_redis_connect(database_t* db, const char* hostname, int port)
 {
     redisContext* handle;
+    bool is_unix = false;
     if (port > 0)
     {
         handle = redisConnect(hostname, port);
@@ -230,6 +240,7 @@ static bool db_redis_connect(database_t* db, const char* hostname, int port)
     else
     {
         handle = redisConnectUnix(hostname);
+        is_unix = true;
     }
     if (!handle)
     {
@@ -242,7 +253,14 @@ static bool db_redis_connect(database_t* db, const char* hostname, int port)
         redisFree(handle);
         return false;
     }
-    redisEnableKeepAlive(handle);
+    if (!is_unix) {
+        redisEnableKeepAlive(handle);
+        if (handle->err) {
+            log_error("failed to set keep alive on redis connection: %s", handle->errstr);
+            redisFree(handle);
+            return false;
+        }
+    }
     db->handle = handle;
     db->read = db_redis_read;
     db->write = db_redis_write;