v1-0001-pg_dump-Validate-archive-entry-filenames-in-direc.patch

application/octet-stream

Filename: v1-0001-pg_dump-Validate-archive-entry-filenames-in-direc.patch
Type: application/octet-stream
Part: 0
Message: Path Traversal Vulnerability in pg_dump Directory Format

Patch

Format: format-patch
Series: patch v1-0001
Subject: pg_dump: Validate archive entry filenames in directory format
File+
src/bin/pg_dump/pg_backup_directory.c 11 1
From d126ea36bddc19168b54c668a84c531f605f314d Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilipkumarb@google.com>
Date: Fri, 3 Jul 2026 10:52:26 +0530
Subject: [PATCH v1] pg_dump: Validate archive entry filenames in directory
 format

Filenames listed in directory-format TOC files (toc.dat and blobs_*.toc)
are untrusted when reading an archive.  If an archive entry filename
contains path traversal elements such as ".." or directory separators,
it could lead to reading files outside the intended archive directory.

Add validation in setFilePath() to refuse empty filenames, filenames
containing "..", or filenames with directory separators, raising a fatal
error if any are found.

In addition, update _LoadLOs() to construct large object file paths using
setFilePath() rather than manual snprintf(), ensuring LO filenames read
from blobs_*.toc undergo the same validation checks.
---
 src/bin/pg_dump/pg_backup_directory.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c
index c0b50223cec..2746c426462 100644
--- a/src/bin/pg_dump/pg_backup_directory.c
+++ b/src/bin/pg_dump/pg_backup_directory.c
@@ -434,7 +434,7 @@ _LoadLOs(ArchiveHandle *AH, TocEntry *te)
 					 tocfname, line);
 
 		StartRestoreLO(AH, oid, AH->public.ropt->dropSchema);
-		snprintf(path, MAXPGPATH, "%s/%s", ctx->directory, lofname);
+		setFilePath(AH, path, lofname);
 		_PrintFileData(AH, path);
 		EndRestoreLO(AH, oid);
 	}
@@ -686,6 +686,16 @@ setFilePath(ArchiveHandle *AH, char *buf, const char *relativeFilename)
 
 	dname = ctx->directory;
 
+	/*
+	 * Per-entry filenames come from the (untrusted) toc.dat / blobs_*.toc.
+	 * Refuse anything that is not a plain leaf name.
+	 */
+	if (relativeFilename[0] == '\0' ||
+		strstr(relativeFilename, "..") != NULL ||
+		first_dir_separator(relativeFilename) != NULL)
+		pg_fatal("invalid archive: entry filename \"%s\" is not a plain file name",
+				 relativeFilename);
+
 	if (strlen(dname) + 1 + strlen(relativeFilename) + 1 > MAXPGPATH)
 		pg_fatal("file name too long: \"%s\"", dname);
 
-- 
2.49.0