From c508fb100757e2968247865eaa0a678dd5afb146 Mon Sep 17 00:00:00 2001 From: Mahendra Singh Thalor Date: Fri, 11 Apr 2025 18:31:06 +0530 Subject: [PATCH] add some more error checks into _fileExistsInDirectory function to report "too long name" error. --- src/bin/pg_dump/pg_backup_archiver.c | 9 +++++++- src/bin/pg_dump/pg_dumpall.c | 22 ++++++++++++++---- src/bin/pg_dump/pg_restore.c | 34 ++++++++++++++++++++++------ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index f961162f365..30dcf5780a3 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -2218,9 +2218,16 @@ _fileExistsInDirectory(const char *dir, const char *filename) struct stat st; char buf[MAXPGPATH]; - if (snprintf(buf, MAXPGPATH, "%s/%s", dir, filename) >= MAXPGPATH) + if (strlen(dir) >= MAXPGPATH) pg_fatal("directory name too long: \"%s\"", dir); + if (strlen(filename) >= MAXPGPATH) + pg_fatal("file name too long: \"%s\"", filename); + + /* Now check path length of dir/filename */ + if (snprintf(buf, MAXPGPATH, "%s/%s", dir, filename) >= MAXPGPATH) + pg_fatal("combined name of directory:\"%s\" and file:\"%s\" is too long", filename, dir); + return (stat(buf, &st) == 0 && S_ISREG(st.st_mode)); } diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 3395d559518..f4a9bb07503 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -506,6 +506,9 @@ main(int argc, char *argv[]) if (statistics_only) appendPQExpBufferStr(pgdumpopts, " --statistics-only"); + if (filename && strlen(filename) >= MAXPGPATH) + pg_fatal("out file name:\"%s\" is too long", filename); + /* * Open the output file if required, otherwise use stdout. If required, * then create new directory and global.dat file. @@ -517,7 +520,8 @@ main(int argc, char *argv[]) /* Create new directory or accept the empty existing directory. */ create_or_open_dir(filename); - snprintf(global_path, MAXPGPATH, "%s/global.dat", filename); + if (snprintf(global_path, MAXPGPATH, "%s/global.dat", filename) >= MAXPGPATH) + pg_fatal("combined name of out file:\"%s\" and global.dat is too long", filename); OPF = fopen(global_path, PG_BINARY_W); if (!OPF) @@ -1650,6 +1654,7 @@ dumpDatabases(PGconn *conn, ArchiveFormat archDumpFormat) { char map_file_path[MAXPGPATH]; + /* No need to check path length as %s/global.dat was OK. */ snprintf(db_subdir, MAXPGPATH, "%s/databases", filename); /* Create a subdirectory with 'databases' name under main directory. */ @@ -1689,11 +1694,20 @@ dumpDatabases(PGconn *conn, ArchiveFormat archDumpFormat) if (archDumpFormat != archNull) { if (archDumpFormat == archCustom) - snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".dmp", db_subdir, oid); + { + if (snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".dmp", db_subdir, oid) >= MAXPGPATH) + pg_fatal("combined name of file:\"%s\" and \"%s\".dmp is too long", db_subdir, oid); + } else if (archDumpFormat == archTar) - snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".tar", db_subdir, oid); + { + if (snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\".tar", db_subdir, oid) >= MAXPGPATH) + pg_fatal("combined name of file:\"%s\" and \"%s\".tar is too long", db_subdir, oid); + } else - snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\"", db_subdir, oid); + { + if (snprintf(dbfilepath, MAXPGPATH, "\"%s\"/\"%s\"", db_subdir, oid) >= MAXPGPATH) + pg_fatal("combined name of file:\"%s\" and \"%s\" is too long", db_subdir, oid); + } /* Put one line entry for dboid and dbname in map file. */ fprintf(map_file, "%s %s\n", oid, dbname); diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index 24a44b81a95..157f7ac8c29 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -834,9 +834,16 @@ file_exists_in_directory(const char *dir, const char *filename) struct stat st; char buf[MAXPGPATH]; - if (snprintf(buf, MAXPGPATH, "%s/%s", dir, filename) >= MAXPGPATH) + if (strlen(dir) >= MAXPGPATH) pg_fatal("directory name too long: \"%s\"", dir); + if (strlen(filename) >= MAXPGPATH) + pg_fatal("file name too long: \"%s\"", filename); + + /* Now check path length of dir/filename */ + if (snprintf(buf, MAXPGPATH, "%s/%s", dir, filename) >= MAXPGPATH) + pg_fatal("combined name of directory:\"%s\" and file:\"%s\" is too long", filename, dir); + return (stat(buf, &st) == 0 && S_ISREG(st.st_mode)); } @@ -1190,6 +1197,10 @@ restore_all_databases(PGconn *conn, const char *dumpdirpath, opts->cparams.override_dbname = NULL; } + /* + * No need to check dumpdirpath/databases path as + * dumpdirpath/global.dat was OK. + */ snprintf(subdirdbpath, MAXPGPATH, "%s/databases", dumpdirpath); /* @@ -1197,17 +1208,23 @@ restore_all_databases(PGconn *conn, const char *dumpdirpath, * {oid}.dmp file, use it. Otherwise try to use a directory called * {oid} */ - snprintf(dbfilename, MAXPGPATH, "%u.tar", db_cell->oid); + snprintf(dbfilename, MAXPGPATH, "%u", db_cell->oid); /* path length is OK */ + if (file_exists_in_directory(subdirdbpath, dbfilename)) - snprintf(subdirpath, MAXPGPATH, "%s/databases/%u.tar", dumpdirpath, db_cell->oid); + snprintf(subdirpath, MAXPGPATH, "%s/databases/%s", dumpdirpath, dbfilename); else { - snprintf(dbfilename, MAXPGPATH, "%u.dmp", db_cell->oid); - + snprintf(dbfilename, MAXPGPATH, "%u.tar", db_cell->oid); if (file_exists_in_directory(subdirdbpath, dbfilename)) - snprintf(subdirpath, MAXPGPATH, "%s/databases/%u.dmp", dumpdirpath, db_cell->oid); + snprintf(subdirpath, MAXPGPATH, "%s/databases/%u.tar", dumpdirpath, db_cell->oid); else - snprintf(subdirpath, MAXPGPATH, "%s/databases/%u", dumpdirpath, db_cell->oid); + { + snprintf(dbfilename, MAXPGPATH, "%u.dmp", db_cell->oid); + if (file_exists_in_directory(subdirdbpath, dbfilename)) + snprintf(subdirpath, MAXPGPATH, "%s/databases/%u.dmp", dumpdirpath, db_cell->oid); + else + snprintf(subdirpath, MAXPGPATH, "%s/databases/%u", dumpdirpath, db_cell->oid); + } } pg_log_info("restoring database \"%s\"", db_cell->str); @@ -1364,6 +1381,9 @@ copy_or_print_global_file(const char *outfile, FILE *pfile) OPF = stdout; else { + if (strlen(outfile) >= MAXPGPATH) + pg_fatal("out file name:\"%s\" is too long", outfile); + snprintf(out_file_path, MAXPGPATH, "%s", outfile); OPF = fopen(out_file_path, PG_BINARY_W); -- 2.39.3