]> granicus.if.org Git - postgresql/commitdiff
Convert newlines to spaces in names written in pg_dump comments.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 23 Feb 2012 20:53:09 +0000 (15:53 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 23 Feb 2012 20:53:09 +0000 (15:53 -0500)
pg_dump was incautious about sanitizing object names that are emitted
within SQL comments in its output script.  A name containing a newline
would at least render the script syntactically incorrect.  Maliciously
crafted object names could present a SQL injection risk when the script
is reloaded.

Reported by Heikki Linnakangas, patch by Robert Haas

Security: CVE-2012-0868

src/bin/pg_dump/pg_backup_archiver.c

index 55c84fdd47993fd6d3d39631a766fd3920d7ac0d..79f7dda211a9683da2ecdc6bd2d1613e4adfb454 100644 (file)
@@ -99,6 +99,7 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
 static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
                                          ArchiveHandle *AH);
 static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData, bool acl_pass);
+static char *replace_line_endings(const char *str);
 
 
 static void _doSetFixedOutputState(ArchiveHandle *AH);
@@ -2932,6 +2933,9 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
        if (!AH->noTocComments)
        {
                const char *pfx;
+               char       *sanitized_name;
+               char       *sanitized_schema;
+               char       *sanitized_owner;
 
                if (isData)
                        pfx = "Data for ";
@@ -2953,12 +2957,39 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
                                ahprintf(AH, "\n");
                        }
                }
+
+               /*
+                * Zap any line endings embedded in user-supplied fields, to prevent
+                * corruption of the dump (which could, in the worst case, present an
+                * SQL injection vulnerability if someone were to incautiously load a
+                * dump containing objects with maliciously crafted names).
+                */
+               sanitized_name = replace_line_endings(te->tag);
+               if (te->namespace)
+                       sanitized_schema = replace_line_endings(te->namespace);
+               else
+                       sanitized_schema = pg_strdup("-");
+               if (!ropt->noOwner)
+                       sanitized_owner = replace_line_endings(te->owner);
+               else
+                       sanitized_owner = pg_strdup("-");
+
                ahprintf(AH, "-- %sName: %s; Type: %s; Schema: %s; Owner: %s",
-                                pfx, te->tag, te->desc,
-                                te->namespace ? te->namespace : "-",
-                                ropt->noOwner ? "-" : te->owner);
+                                pfx, sanitized_name, te->desc, sanitized_schema,
+                                sanitized_owner);
+
+               free(sanitized_name);
+               free(sanitized_schema);
+               free(sanitized_owner);
+
                if (te->tablespace && !ropt->noTablespace)
-                       ahprintf(AH, "; Tablespace: %s", te->tablespace);
+               {
+                       char   *sanitized_tablespace;
+
+                       sanitized_tablespace = replace_line_endings(te->tablespace);
+                       ahprintf(AH, "; Tablespace: %s", sanitized_tablespace);
+                       free(sanitized_tablespace);
+               }
                ahprintf(AH, "\n");
 
                if (AH->PrintExtraTocPtr !=NULL)
@@ -3053,6 +3084,27 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
        }
 }
 
+/*
+ * Sanitize a string to be included in an SQL comment, by replacing any
+ * newlines with spaces.
+ */
+static char *
+replace_line_endings(const char *str)
+{
+       char   *result;
+       char   *s;
+
+       result = pg_strdup(str);
+
+       for (s = result; *s != '\0'; s++)
+       {
+               if (*s == '\n' || *s == '\r')
+                       *s = ' ';
+       }
+
+       return result;
+}
+
 void
 WriteHead(ArchiveHandle *AH)
 {