summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Bossart2026-08-10 13:38:37 +0000
committerNoah Misch2026-08-10 13:38:37 +0000
commit2006fca401e07fc116a5d1777fc0f22bf49c9fae (patch)
tree96ece7a50914aa9c0a503f9099e114cc12e3a986
parente2c48c81fcf858266625e835becff3f17478beea (diff)
psql: Don't do backquote expansion in \unrestrict.
This oversight in commit 71ea0d6795 allows a malicious server to inject shell commands into plain-text dump output that are run at restore time on the machine running psql. To fix, interpret all text after \unrestrict until the end of the line as its argument. Reported-by: Lucas Velgus <velgusgus599@gmail.com> Reported-by: Filip Janus <fjanus@redhat.com> Reported-by: Daniel Bakker <daniel@jackds.nl> Author: Nathan Bossart <nathandbossart@gmail.com> Reviewed-by: Robert Haas <robertmhaas@gmail.com> Reviewed-by: Noah Misch <noah@leadboat.com> Security: CVE-2026-18408 Backpatch-through: 14
-rw-r--r--doc/src/sgml/ref/psql-ref.sgml5
-rw-r--r--src/bin/psql/command.c19
2 files changed, 22 insertions, 2 deletions
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index ebb7a1173f9..012c8ce8c94 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -3397,6 +3397,11 @@ testdb=&gt; <userinput>\setenv LESS -imx4F</userinput>
<application>pg_dumpall</application>, and
<application>pg_restore</application>, but it may be useful elsewhere.
</para>
+ <para>
+ Unlike most other meta-commands, the entire remainder of the line is
+ always taken to be the argument of <command>\unrestrict</command>, and
+ neither variable interpolation nor backquote expansion are performed.
+ </para>
</listitem>
</varlistentry>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 5d95bdb5f6f..3202aa3db8f 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -2285,6 +2285,12 @@ exec_command_restrict(PsqlScanState scan_state, bool active_branch,
Assert(!restricted);
+ /*
+ * Unlike \unrestrict, this argument may safely undergo backquote and
+ * variable expansion: HandleSlashCmds() rejects \restrict in
+ * restricted mode before its argument is scanned, so we only get here
+ * when the input could execute such things anyway.
+ */
opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true);
if (opt == NULL || opt[0] == '\0')
{
@@ -2613,14 +2619,23 @@ exec_command_unrestrict(PsqlScanState scan_state, bool active_branch,
if (active_branch)
{
char *opt;
+ size_t len;
- opt = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true);
+ opt = psql_scan_slash_option(scan_state, OT_WHOLE_LINE, NULL, true);
if (opt == NULL || opt[0] == '\0')
{
pg_log_error("\\%s: missing required argument", cmd);
return PSQL_CMD_ERROR;
}
+ /* strip any trailing spaces and semicolons */
+ len = strlen(opt);
+ while (len > 0 &&
+ (opt[len - 1] == ';' ||
+ (isascii((unsigned char) opt[len - 1]) &&
+ isspace((unsigned char) opt[len - 1]))))
+ opt[--len] = '\0';
+
if (!restricted)
{
pg_log_error("\\%s: not currently in restricted mode", cmd);
@@ -2638,7 +2653,7 @@ exec_command_unrestrict(PsqlScanState scan_state, bool active_branch,
}
}
else
- ignore_slash_options(scan_state);
+ ignore_slash_whole_line(scan_state);
return PSQL_CMD_SKIP_LINE;
}