diff --git a/debian/changelog b/debian/changelog index d400cdb057ee6f2e49ef8672b9cea149726124c5..171577f584b2c46d2a0631040aac2079b11739be 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,8 @@ postgresql-common (188) UNRELEASED; urgency=medium + * pg_ctlcluster, pg_createcluster, pg_upgradecluster: Use lchown instead + of chown to mitigate privilege escalation via symlinks. (Related to + CVE-2017-12172 in PostgreSQL; extends our earlier fix for CVE-2016-1255.) * dh_make_pgxs: Add options to set package name and version. * pg_lsclusters: Raise error when called on a specific cluster that does not exist. This was the behavior before the "accept dead postgresql.conf diff --git a/pg_createcluster b/pg_createcluster index e8aa59e7b0d903a296a6317e4e4931aa0ddcb6cf..d6002c4693ed915419ecf2630a3136e16f0f57da 100755 --- a/pg_createcluster +++ b/pg_createcluster @@ -18,7 +18,7 @@ use PgCommon; use Getopt::Long; -use POSIX qw/setlocale LC_ALL LC_CTYPE/; +use POSIX qw/lchown setlocale LC_ALL LC_CTYPE/; $ENV{'PATH'} = '/bin:/usr/bin'; # untaint @@ -369,8 +369,9 @@ set_cluster_pg_ctl_conf $version, $cluster, ''; move_conffile "$datadir/postgresql.conf", $confdir, $owneruid, $ownergid, '644'; move_conffile "$datadir/pg_hba.conf", $confdir, $owneruid, $ownergid, '640', 'hba_file'; move_conffile "$datadir/pg_ident.conf", $confdir, $owneruid, $ownergid, '640', 'ident_file'; -chown $owneruid, $ownergid, $datadir, $confdir, "$confdir/start.conf" or die "chown: $!"; -chown $owneruid, $ownergid, $datadir, $confdir, "$confdir/pg_ctl.conf" or die "chown: $!"; +foreach my $f ($datadir, $confdir, "$confdir/start.conf", "$confdir/pg_ctl.conf") { + lchown $owneruid, $ownergid, $f or error "lchown $f: $!"; +} PgCommon::set_conf_value $version, $cluster, 'postgresql.conf', 'data_directory', $datadir; @@ -410,7 +411,7 @@ if (! -d '/var/log/postgresql') { mkdir '/var/log/postgresql' or error "could not create log directory; you might need to run this program with root privileges"; chmod 01775, '/var/log/postgresql'; - chown 0, $postgres_user[3], '/var/log/postgresql'; + lchown 0, $postgres_user[3], '/var/log/postgresql'; } $real_logfile = $custom_logfile || "/var/log/postgresql/postgresql-$version-$cluster.log"; error "logfile $real_logfile is a directory, not a file" if (-d $real_logfile); @@ -425,11 +426,11 @@ if ($owneruid < 500) { } else { $g = $ownergid; } -chown $owneruid, $g, $real_logfile; +lchown $owneruid, $g, $real_logfile; # if we are using a non-default log file, create a log symlink if ($custom_logfile) { symlink $real_logfile, "$confdir/log"; - chown $owneruid, $ownergid, "$confdir/log"; + lchown $owneruid, $ownergid, "$confdir/log"; } # SSL configuration @@ -539,7 +540,7 @@ open ENV, ">$confdir/environment" or error "could not create environment file $c print ENV $defaultenv; close ENV; chmod 0644, "$confdir/environment"; -chown $owneruid, $ownergid, "$confdir/environment"; +lchown $owneruid, $ownergid, "$confdir/environment"; $cleanup_cruft = 0; @@ -559,7 +560,7 @@ foreach my $guc (sort keys %defaultconf) { next if ($version < 9.3); if ($val =~ /^[\w.]+$/ and not -e "$confdir/$val") { # create directory relative to new config directory mkdir "$confdir/$val", 0755; - chown $owneruid, $ownergid, "$confdir/$val"; + lchown $owneruid, $ownergid, "$confdir/$val"; } } PgCommon::set_conf_value $version, $cluster, 'postgresql.conf', $guc, $val; diff --git a/pg_ctlcluster b/pg_ctlcluster index 6d19e2ba2ebdde8bde5f761221c0c76c69b74d74..def8b6bef30e50eedd461e53cf2c4d2b9efeb148 100755 --- a/pg_ctlcluster +++ b/pg_ctlcluster @@ -24,6 +24,7 @@ use Getopt::Long; use POSIX qw/setsid dup2 :sys_wait_h/; use PgCommon; use Fcntl qw(SEEK_SET O_RDWR O_CREAT O_EXCL); +use POSIX qw(lchown); my ($version, $cluster, $pg_ctl, $force); my (@postgres_auxoptions, @pg_ctl_opts_from_cli); @@ -452,7 +453,7 @@ if ($action ne 'stop' && $info{'logfile'} && ! -e $info{'logfile'}) { $( = $) = 0; if ($info{'owneruid'} < 500) { my $g = (getgrnam 'adm')[2]; - chown $info{'owneruid'}, $g, $info{'logfile'} if (defined $g); + lchown $info{'owneruid'}, $g, $info{'logfile'} if (defined $g); } } diff --git a/pg_upgradecluster b/pg_upgradecluster index ed93114d9489bdc1b057db6fb34e817c1e40ef5a..d08364ea322aa3bebf8b1e4b94eec8f3d37fd0c4 100755 --- a/pg_upgradecluster +++ b/pg_upgradecluster @@ -20,7 +20,7 @@ use strict; use warnings; use PgCommon; use Getopt::Long; -use POSIX; +use POSIX qw(lchown); # untaint environment $ENV{'PATH'} = '/bin:/usr/bin'; @@ -128,7 +128,7 @@ sub adapt_conffiles { } close O; close N; - chown $newinfo{'owneruid'}, $newinfo{'ownergid'}, "$hba.new"; + lchown $newinfo{'owneruid'}, $newinfo{'ownergid'}, "$hba.new"; chmod 0640, "$hba.new"; rename "$hba.new", $hba or error "rename: $!"; } @@ -208,7 +208,7 @@ sub disable_connections { error "could not create $hba"; } chmod 0400, $hba; - chown $_[3], 0, $hba; + lchown $_[3], 0, $hba; if ($_[0] >= '8.4') { print F "local all $_[2] ident\n"; } else {