Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bd65371

Browse files
committed
Fix Windows shell argument quoting.
The incorrect quoting may have permitted arbitrary command execution. At a minimum, it gave broader control over the command line to actors supposed to have control over a single argument. Back-patch to 9.1 (all supported versions). Security: CVE-2016-5424
1 parent 142c24c commit bd65371

File tree

1 file changed

+47
-5
lines changed

1 file changed

+47
-5
lines changed

src/bin/pg_dump/pg_dumpall.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,7 +2217,7 @@ doConnStrQuoting(PQExpBuffer buf, const char *str)
22172217

22182218
/*
22192219
* Append the given string to the shell command being built in the buffer,
2220-
* with suitable shell-style quoting.
2220+
* with suitable shell-style quoting to create exactly one argument.
22212221
*
22222222
* Forbid LF or CR characters, which have scant practical use beyond designing
22232223
* security breaches. The Windows command shell is unusable as a conduit for
@@ -2249,8 +2249,20 @@ doShellQuoting(PQExpBuffer buf, const char *str)
22492249
}
22502250
appendPQExpBufferChar(buf, '\'');
22512251
#else /* WIN32 */
2252+
int backslash_run_length = 0;
22522253

2253-
appendPQExpBufferChar(buf, '"');
2254+
/*
2255+
* A Windows system() argument experiences two layers of interpretation.
2256+
* First, cmd.exe interprets the string. Its behavior is undocumented,
2257+
* but a caret escapes any byte except LF or CR that would otherwise have
2258+
* special meaning. Handling of a caret before LF or CR differs between
2259+
* "cmd.exe /c" and other modes, and it is unusable here.
2260+
*
2261+
* Second, the new process parses its command line to construct argv (see
2262+
* https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats
2263+
* backslash-double quote sequences specially.
2264+
*/
2265+
appendPQExpBufferStr(buf, "^\"");
22542266
for (p = str; *p; p++)
22552267
{
22562268
if (*p == '\n' || *p == '\r')
@@ -2261,11 +2273,41 @@ doShellQuoting(PQExpBuffer buf, const char *str)
22612273
exit(EXIT_FAILURE);
22622274
}
22632275

2276+
/* Change N backslashes before a double quote to 2N+1 backslashes. */
22642277
if (*p == '"')
2265-
appendPQExpBufferStr(buf, "\\\"");
2278+
{
2279+
while (backslash_run_length)
2280+
{
2281+
appendPQExpBufferStr(buf, "^\\");
2282+
backslash_run_length--;
2283+
}
2284+
appendPQExpBufferStr(buf, "^\\");
2285+
}
2286+
else if (*p == '\\')
2287+
backslash_run_length++;
22662288
else
2267-
appendPQExpBufferChar(buf, *p);
2289+
backslash_run_length = 0;
2290+
2291+
/*
2292+
* Decline to caret-escape the most mundane characters, to ease
2293+
* debugging and lest we approach the command length limit.
2294+
*/
2295+
if (!((*p >= 'a' && *p <= 'z') ||
2296+
(*p >= 'A' && *p <= 'Z') ||
2297+
(*p >= '0' && *p <= '9')))
2298+
appendPQExpBufferChar(buf, '^');
2299+
appendPQExpBufferChar(buf, *p);
2300+
}
2301+
2302+
/*
2303+
* Change N backslashes at end of argument to 2N backslashes, because they
2304+
* precede the double quote that terminates the argument.
2305+
*/
2306+
while (backslash_run_length)
2307+
{
2308+
appendPQExpBufferStr(buf, "^\\");
2309+
backslash_run_length--;
22682310
}
2269-
appendPQExpBufferChar(buf, '"');
2311+
appendPQExpBufferStr(buf, "^\"");
22702312
#endif /* WIN32 */
22712313
}

0 commit comments

Comments
 (0)