Skip to content
Snippets Groups Projects
Commit 8b4d0a88 authored by Christoph Berg's avatar Christoph Berg :satellite: Committed by Christoph Berg
Browse files

Replace chown by lchown where applicable

PostgreSQL's upstream init scripts have been found vulnerable to symlink
attacks on the server log file (CVE-2017-12172). We don't use the
upstream scripts, but inspection of pg_ctlcluster has shown that it is
vulnerable to exactly the same problem. We fixed this problem
previously via c8989206 (CVE-2016-1255), but the fix merely made
the attack window smaller.

We now use lchown instead of chown so a symlink put into place while
pg_ctlcluster is running cannot be used to chown files elsewhere on the
filesystem.

In passing, apply the same fix to pg_createcluster and pg_upgradecluster
as well.
parent d09868b3
No related branches found
No related tags found
No related merge requests found
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
......
......@@ -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;
......
......@@ -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);
}
}
......
......@@ -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 {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment