Skip to content

Commit f06b1c5

Browse files
committed
pg_upgrade: Check version of target cluster binaries
This expands the binary validation in pg_upgrade with a version check per binary to ensure that the target cluster installation only contains binaries from the target version. In order to reduce duplication, validate_exec is exported from port.h and the local copy in pg_upgrade is removed. Author: Daniel Gustafsson <daniel@yesql.se> Discussion: https://www.postgresql.org/message-id/flat/9328.1552952117@sss.pgh.pa.us
1 parent 8af3c23 commit f06b1c5

File tree

3 files changed

+38
-54
lines changed

3 files changed

+38
-54
lines changed

src/bin/pg_upgrade/exec.c

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111

1212
#include <fcntl.h>
1313

14+
#include "common/string.h"
1415
#include "pg_upgrade.h"
1516

1617
static void check_data_dir(ClusterInfo *cluster);
1718
static void check_bin_dir(ClusterInfo *cluster);
1819
static void get_bin_version(ClusterInfo *cluster);
19-
static void validate_exec(const char *dir, const char *cmdName);
20+
static void check_exec(const char *dir, const char *program);
2021

2122
#ifdef WIN32
2223
static int win32_check_directory_write_permissions(void);
@@ -375,9 +376,9 @@ check_bin_dir(ClusterInfo *cluster)
375376
report_status(PG_FATAL, "\"%s\" is not a directory\n",
376377
cluster->bindir);
377378

378-
validate_exec(cluster->bindir, "postgres");
379-
validate_exec(cluster->bindir, "pg_controldata");
380-
validate_exec(cluster->bindir, "pg_ctl");
379+
check_exec(cluster->bindir, "postgres");
380+
check_exec(cluster->bindir, "pg_controldata");
381+
check_exec(cluster->bindir, "pg_ctl");
381382

382383
/*
383384
* Fetch the binary version after checking for the existence of pg_ctl.
@@ -388,9 +389,9 @@ check_bin_dir(ClusterInfo *cluster)
388389

389390
/* pg_resetxlog has been renamed to pg_resetwal in version 10 */
390391
if (GET_MAJOR_VERSION(cluster->bin_version) <= 906)
391-
validate_exec(cluster->bindir, "pg_resetxlog");
392+
check_exec(cluster->bindir, "pg_resetxlog");
392393
else
393-
validate_exec(cluster->bindir, "pg_resetwal");
394+
check_exec(cluster->bindir, "pg_resetwal");
394395

395396
if (cluster == &new_cluster)
396397
{
@@ -399,63 +400,46 @@ check_bin_dir(ClusterInfo *cluster)
399400
* pg_dumpall are used to dump the old cluster, but must be of the
400401
* target version.
401402
*/
402-
validate_exec(cluster->bindir, "initdb");
403-
validate_exec(cluster->bindir, "pg_dump");
404-
validate_exec(cluster->bindir, "pg_dumpall");
405-
validate_exec(cluster->bindir, "pg_restore");
406-
validate_exec(cluster->bindir, "psql");
407-
validate_exec(cluster->bindir, "vacuumdb");
403+
check_exec(cluster->bindir, "initdb");
404+
check_exec(cluster->bindir, "pg_dump");
405+
check_exec(cluster->bindir, "pg_dumpall");
406+
check_exec(cluster->bindir, "pg_restore");
407+
check_exec(cluster->bindir, "psql");
408+
check_exec(cluster->bindir, "vacuumdb");
408409
}
409410
}
410411

411-
412-
/*
413-
* validate_exec()
414-
*
415-
* validate "path" as an executable file
416-
*/
417412
static void
418-
validate_exec(const char *dir, const char *cmdName)
413+
check_exec(const char *dir, const char *program)
419414
{
420-
char path[MAXPGPATH];
421-
struct stat buf;
415+
char path[MAXPGPATH];
416+
char line[MAXPGPATH];
417+
char cmd[MAXPGPATH];
418+
char versionstr[128];
419+
int ret;
422420

423-
snprintf(path, sizeof(path), "%s/%s", dir, cmdName);
421+
snprintf(path, sizeof(path), "%s/%s", dir, program);
424422

425-
#ifdef WIN32
426-
/* Windows requires a .exe suffix for stat() */
427-
if (strlen(path) <= strlen(EXE_EXT) ||
428-
pg_strcasecmp(path + strlen(path) - strlen(EXE_EXT), EXE_EXT) != 0)
429-
strlcat(path, EXE_EXT, sizeof(path));
430-
#endif
423+
ret = validate_exec(path);
431424

432-
/*
433-
* Ensure that the file exists and is a regular file.
434-
*/
435-
if (stat(path, &buf) < 0)
436-
pg_fatal("check for \"%s\" failed: %s\n",
437-
path, strerror(errno));
438-
else if (!S_ISREG(buf.st_mode))
425+
if (ret == -1)
439426
pg_fatal("check for \"%s\" failed: not a regular file\n",
440427
path);
441-
442-
/*
443-
* Ensure that the file is both executable and readable (required for
444-
* dynamic loading).
445-
*/
446-
#ifndef WIN32
447-
if (access(path, R_OK) != 0)
448-
#else
449-
if ((buf.st_mode & S_IRUSR) == 0)
450-
#endif
451-
pg_fatal("check for \"%s\" failed: cannot read file (permission denied)\n",
428+
else if (ret == -2)
429+
pg_fatal("check for \"%s\" failed: cannot execute (permission denied)\n",
452430
path);
453431

454-
#ifndef WIN32
455-
if (access(path, X_OK) != 0)
456-
#else
457-
if ((buf.st_mode & S_IXUSR) == 0)
458-
#endif
459-
pg_fatal("check for \"%s\" failed: cannot execute (permission denied)\n",
432+
snprintf(cmd, sizeof(cmd), "\"%s\" -V", path);
433+
434+
if (!pipe_read_line(cmd, line, sizeof(line)))
435+
pg_fatal("check for \"%s\" failed: cannot execute\n",
460436
path);
437+
438+
pg_strip_crlf(line);
439+
440+
snprintf(versionstr, sizeof(versionstr), "%s (PostgreSQL) " PG_VERSION, program);
441+
442+
if (strcmp(line, versionstr) != 0)
443+
pg_fatal("check for \"%s\" failed: incorrect version: found \"%s\", expected \"%s\"\n",
444+
path, line, versionstr);
461445
}

src/common/exec.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
#define getcwd(cwd,len) GetCurrentDirectory(len, cwd)
5050
#endif
5151

52-
static int validate_exec(const char *path);
5352
static int resolve_symlinks(char *path);
5453

5554
#ifdef WIN32
@@ -63,7 +62,7 @@ static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
6362
* -1 if the regular file "path" does not exist or cannot be executed.
6463
* -2 if the file is otherwise valid but cannot be read.
6564
*/
66-
static int
65+
int
6766
validate_exec(const char *path)
6867
{
6968
struct stat buf;

src/include/port.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ extern void pgfnames_cleanup(char **filenames);
125125
extern void set_pglocale_pgservice(const char *argv0, const char *app);
126126

127127
/* Portable way to find and execute binaries (in exec.c) */
128+
extern int validate_exec(const char *path);
128129
extern int find_my_exec(const char *argv0, char *retpath);
129130
extern int find_other_exec(const char *argv0, const char *target,
130131
const char *versionstr, char *retpath);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy