Vulnerability: Buffer overflow in redis-cli of Redis before 4.0.10 and 5.x before 5.0 RC3 allows an attacker to achieve code execution and escalate to higher privileges via a crafted command line. NOTE: It is unclear whether there are any common situations in which redis-cli is used with, for example, a -h (aka hostname) argument from an untrusted source.
Vulnerability ID: CVE-2018-12326
CWE: CWE-119
Severity score: 6.4
Project: https://github.com/antirez/redis
Published: 2018-06-17
File: src/redis-cli.c
Commit message: Security: fix redis-cli buffer overflow.

Thanks to Fakhri Zulkifli for reporting it.

The fix switched to dynamic allocation, copying the final prompt in the
static buffer only at the end.
Commit author: antirez

Vulnerable version (before fix):
 static long long mstime(void) { }  static void cliRefreshPrompt(void) {     int len;      if (config.eval_ldb) return;     if (config.hostsocket != NULL)         len = snprintf(config.prompt,sizeof(config.prompt),"redis %s",                        config.hostsocket);     else         len = anetFormatAddr(config.prompt, sizeof(config.prompt),                            config.hostip, config.hostport);     /* Add [dbnum] if needed */     if (config.dbnum != 0)         len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]",             config.dbnum);     snprintf(config.prompt+len,sizeof(config.prompt)-len,"> "); }  /* Return the name of the dotfile for the specified 'dotfilename'.

Fixed version (after fix):
 static long long mstime(void) { }  static void cliRefreshPrompt(void) {     if (config.eval_ldb) return;      sds prompt = sdsempty();     if (config.hostsocket != NULL) {         prompt = sdscatfmt(prompt,"redis %s",config.hostsocket);     } else {         char addr[256];         anetFormatAddr(addr, sizeof(addr), config.hostip, config.hostport);         prompt = sdscatlen(prompt,addr,strlen(addr));     }      /* Add [dbnum] if needed */     if (config.dbnum != 0)         prompt = sdscatfmt(prompt,"[%i]",config.dbnum);      /* Copy the prompt in the static buffer. */     prompt = sdscatlen(prompt,"> ",2);     snprintf(config.prompt,sizeof(config.prompt),"%s",prompt);     sdsfree(prompt); }  /* Return the name of the dotfile for the specified 'dotfilename'.

Patch:
patch: @@ -152,20 +152,25 @@ static long long mstime(void) {
 }
 
 static void cliRefreshPrompt(void) {
-    int len;
-
     if (config.eval_ldb) return;
-    if (config.hostsocket != NULL)
-        len = snprintf(config.prompt,sizeof(config.prompt),"redis %s",
-                       config.hostsocket);
-    else
-        len = anetFormatAddr(config.prompt, sizeof(config.prompt),
-                           config.hostip, config.hostport);
+
+    sds prompt = sdsempty();
+    if (config.hostsocket != NULL) {
+        prompt = sdscatfmt(prompt,"redis %s",config.hostsocket);
+    } else {
+        char addr[256];
+        anetFormatAddr(addr, sizeof(addr), config.hostip, config.hostport);
+        prompt = sdscatlen(prompt,addr,strlen(addr));
+    }
+
     /* Add [dbnum] if needed */
     if (config.dbnum != 0)
-        len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]",
-            config.dbnum);
-    snprintf(config.prompt+len,sizeof(config.prompt)-len,"> ");
+        prompt = sdscatfmt(prompt,"[%i]",config.dbnum);
+
+    /* Copy the prompt in the static buffer. */
+    prompt = sdscatlen(prompt,"> ",2);
+    snprintf(config.prompt,sizeof(config.prompt),"%s",prompt);
+    sdsfree(prompt);
 }
 
 /* Return the name of the dotfile for the specified 'dotfilename'.
path: src/redis-cli.c