Back-patch "Only quote libpq connection string values that need quoting."
authorNoah Misch <noah@leadboat.com>
Mon, 8 Aug 2016 14:07:53 +0000 (10:07 -0400)
committerNoah Misch <noah@leadboat.com>
Mon, 8 Aug 2016 14:07:53 +0000 (10:07 -0400)
Back-patch commit 2953cd6d17210935098c803c52c6df5b12a725b9 and certain
runPgDump() bits of 3dee636e0404885d07885d41c0d70e50c784f324 to 9.2 and
9.1.  This synchronizes their doConnStrQuoting() implementations with
later releases.  Subsequent security patches will modify that function.

Security: CVE-2016-5424

src/bin/pg_dump/pg_dumpall.c

index 47fb7008462b76d7ae5b65c135e3a6dd2939e449..2c46b5ee90b1d8603f7c19002b8fc1a5f681741e 100644 (file)
@@ -1656,7 +1656,7 @@ dumpDatabases(PGconn *conn)
 static int
 runPgDump(const char *dbname)
 {
-       PQExpBuffer connstr = createPQExpBuffer();
+       PQExpBuffer connstrbuf = createPQExpBuffer();
        PQExpBuffer cmd = createPQExpBuffer();
        int                     ret;
 
@@ -1678,11 +1678,10 @@ runPgDump(const char *dbname)
         * database name as is, but if it contains any = characters, it would
         * incorrectly treat it as a connection string.
         */
-       appendPQExpBuffer(connstr, "dbname='");
-       doConnStrQuoting(connstr, dbname);
-       appendPQExpBuffer(connstr, "'");
+       appendPQExpBufferStr(connstrbuf, "dbname=");
+       doConnStrQuoting(connstrbuf, dbname);
 
-       doShellQuoting(cmd, connstr->data);
+       doShellQuoting(cmd, connstrbuf->data);
 
        appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);
 
@@ -1695,7 +1694,7 @@ runPgDump(const char *dbname)
        ret = system(cmd->data);
 
        destroyPQExpBuffer(cmd);
-       destroyPQExpBuffer(connstr);
+       destroyPQExpBuffer(connstrbuf);
 
        return ret;
 }
@@ -1943,15 +1942,40 @@ dumpTimestamp(char *msg)
 static void
 doConnStrQuoting(PQExpBuffer buf, const char *str)
 {
-       while (*str)
+       const char *s;
+       bool            needquotes;
+
+       /*
+        * If the string consists entirely of plain ASCII characters, no need to
+        * quote it. This is quite conservative, but better safe than sorry.
+        */
+       needquotes = false;
+       for (s = str; *s; s++)
+       {
+               if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
+                         (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
+               {
+                       needquotes = true;
+                       break;
+               }
+       }
+
+       if (needquotes)
        {
-               /* ' and \ must be escaped by to \' and \\ */
-               if (*str == '\'' || *str == '\\')
-                       appendPQExpBufferChar(buf, '\\');
+               appendPQExpBufferChar(buf, '\'');
+               while (*str)
+               {
+                       /* ' and \ must be escaped by to \' and \\ */
+                       if (*str == '\'' || *str == '\\')
+                               appendPQExpBufferChar(buf, '\\');
 
-               appendPQExpBufferChar(buf, *str);
-               str++;
+                       appendPQExpBufferChar(buf, *str);
+                       str++;
+               }
+               appendPQExpBufferChar(buf, '\'');
        }
+       else
+               appendPQExpBufferStr(buf, str);
 }
 
 /*