Package: release.debian.org
Severity: normal
Tags: jessie
User: release.debian.org@packages.debian.org
Usertags: pu
Hi,
I would like to upload postgresql-common/165+deb8u2 with the diff
quoted below to jessie. It's fixing a data-loss bug, and a security
issue. The issues are already addresses in unstable (both in 178).
Is that ok?
diff --git a/debian/changelog b/debian/changelog
index 0d6bd4f..1d583cb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+postgresql-common (165+deb8u2) jessie; urgency=medium
+
+ * pg_upgradecluster: Properly upgrade databases with non-login role owners.
+ (Closes: #614374, #838812)
+ * pg_ctlcluster, t/020_create_sql_remove.t: Protect against symlink in
+ /var/log/postgresql/ allowing the creation of arbitrary files elsewhere.
+ Discovered by Dawid Golunski, thanks! (CVE-2016-1255)
+ * t/TestLib.pm: Cherry-pick program_ok() from master for use in
+ t/020_create_sql_remove.t.
+
+ -- Christoph Berg <myon@debian.org> Sun, 01 Jan 2017 18:48:30 +0100
+
postgresql-common (165+deb8u1) jessie; urgency=medium
* pg_upgradecluster: Set default dynamic_shared_memory_type = mmap.
diff --git a/pg_ctlcluster b/pg_ctlcluster
index 924f878..d2bb897 100755
--- a/pg_ctlcluster
+++ b/pg_ctlcluster
@@ -23,7 +23,7 @@ use warnings;
use Getopt::Long;
use POSIX qw/setsid dup2 setlocale LC_ALL :sys_wait_h/;
use PgCommon;
-use Fcntl 'SEEK_SET';
+use Fcntl qw(SEEK_SET O_RDWR O_CREAT O_EXCL);
my ($version, $cluster, $pg_ctl, $force);
my (@postmaster_auxoptions, @pg_ctl_opts_from_cli);
@@ -394,17 +394,20 @@ if ($> == 0 && ! -e '/var/log/postgresql' &&
# recreate missing log file
if ($action ne 'stop' && $info{'logfile'} && ! -e $info{'logfile'}) {
- open L, '>', $info{'logfile'} or
+ if ($> == 0) { # drop privileges; this is important if logfile
+ # was determined via an /etc/postgresql/.../log symlink
+ change_ugid $info{'owneruid'}, $info{'ownergid'};
+ }
+ sysopen (L, $info{'logfile'}, O_RDWR|O_CREAT|O_EXCL) or
error 'Could not create log file ' . $info{'logfile'};
+ close L;
chmod 0640, $info{'logfile'};
- my $g;
+ $< = $> = 0; # will silently fail if we were not root before, that's intended
+ $( = $) = 0;
if ($info{'owneruid'} < 500) {
- $g = (getgrnam 'adm')[2];
- } else {
- $g = $info{'ownergid'};
+ my $g = (getgrnam 'adm')[2];
+ chown $info{'owneruid'}, $g, $info{'logfile'} if (defined $g);
}
- chown $info{'owneruid'}, $g, $info{'logfile'};
- close L;
}
# recreate /var/run/postgresql
diff --git a/pg_upgradecluster b/pg_upgradecluster
index 876a0af..04c59c6 100755
--- a/pg_upgradecluster
+++ b/pg_upgradecluster
@@ -433,18 +433,16 @@ if (!fork) {
error 'automatic upgrade of tablespaces is not supported';
}
- # get list of databases, owners, and allowed connections
+ # get list of databases (value = datallowconn)
my %databases;
open F, '-|', $oldpsql, '-h', $oldsocket, '-p', $info{'port'},
'-F|', '-d', 'template1', '-Atc',
- 'SELECT datname, datallowconn, pg_catalog.pg_encoding_to_char(encoding), usename FROM pg_database, pg_user WHERE datdba = usesysid' or
+ 'SELECT datname, datallowconn FROM pg_database' or
error 'Could not get pg_database list';
while (<F>) {
chomp;
- my ($n, $a, $e, $o) = split '\|';
- ($o) = $o =~ /^(.*)$/; # untaint
- ($e) = $e =~ /^([\w_]+)$/; # untaint
- $databases{$n} = [$a eq 't', $o, $e];
+ my ($n, $a) = split '\|';
+ $databases{$n} = ($a eq 't');
}
close F;
error 'could not get list of databases' if $?;
@@ -453,7 +451,7 @@ if (!fork) {
for my $db (keys %databases) {
next if $db eq 'template0';
- unless (${$databases{$db}}[0]) {
+ unless ($databases{$db}) {
print "Temporarily enabling access to database $db\n";
(system $oldpsql, '-h', $oldsocket, '-p', $info{'port'}, '-q',
'-d', 'template1', '-c',
@@ -546,8 +544,8 @@ if (!fork) {
'-d', $db, '-c', 'ANALYZE') == 0 or
error 'Could not ANALZYE database';
- unless (${$databases{$db}}[0]) {
- print "Disabling access to database $db\n";
+ unless ($databases{$db}) {
+ print "Disabling access to database $db again\n";
(system $oldpsql, '-h', $oldsocket, '-p', $info{'port'}, '-q',
'-d', 'template1', '-c',
"BEGIN READ WRITE; UPDATE pg_database SET datallowconn = 'f' where datname = '$db'; COMMIT") == 0 or
diff --git a/t/020_create_sql_remove.t b/t/020_create_sql_remove.t
index 457bf9a..f71b4cf 100644
--- a/t/020_create_sql_remove.t
+++ b/t/020_create_sql_remove.t
@@ -10,7 +10,7 @@ use lib 't';
use TestLib;
use PgCommon;
-use Test::More tests => 127 * ($#MAJORS+1);
+use Test::More tests => 131 * ($#MAJORS+1);
sub check_major {
my $v = $_[0];
@@ -142,6 +142,15 @@ sub check_major {
PgCommon::disable_conf_value $v, 'main', 'postgresql.conf', 'log_filename', '';
unlink "/etc/postgresql/$v/main/log";
+ # check that log creation does not escalate privileges
+ program_ok 'root', "pg_ctlcluster $v main stop", 0, 'stopping cluster';
+ unlink $default_log;
+ symlink "/etc/postgres-hack", $default_log;
+ program_ok 'root', "pg_ctlcluster $v main start", 1, 'starting cluster with rouge /var/log/postgresql symlink fails';
+ ok !-f "/etc/postgres-hack", "/etc/postgres-hack was not created";
+ unlink $default_log;
+ program_ok 'root', "pg_ctlcluster $v main start", 0, 'restarting cluster';
+
# verify that the postmaster does not have an associated terminal
unlike_program_out 0, 'ps -o tty -U postgres h', 0, qr/tty|pts/,
'postmaster processes do not have an associated terminal';
diff --git a/t/TestLib.pm b/t/TestLib.pm
index 2c9a9d0..62f2268 100644
--- a/t/TestLib.pm
+++ b/t/TestLib.pm
@@ -22,7 +22,7 @@ use PgCommon qw/get_versions change_ugid/;
our $VERSION = 1.00;
our @ISA = ('Exporter');
our @EXPORT = qw/ps ok_dir exec_as deb_installed rpm_installed package_version
- version_ge is_program_out like_program_out unlike_program_out pidof pid_env check_clean
+ version_ge program_ok is_program_out like_program_out unlike_program_out pidof pid_env check_clean
@ALL_MAJORS @MAJORS $delay/;
our @ALL_MAJORS = sort (get_versions()); # not affected by PG_VERSIONS/-v
@@ -177,6 +177,16 @@ sub exec_as {
return $result;
}
+# Execute a command as a particular user, and check the exit code
+# Arguments: <user> <command> [<expected exit code>] [<description>]
+sub program_ok {
+ my ($user, $cmd, $exit, $description) = @_;
+ $exit ||= 0;
+ $description ||= $cmd;
+ my $outref;
+ ok ((exec_as $user, $cmd, \$outref, $exit) == $exit, $description);
+}
+
# Execute a command as a particular user, and check the exit code and output
# (merged stdout/stderr).
# Arguments: <user> <command> <expected exit code> <expected output> [<description>]
Thanks,
Christoph
Attachment:
signature.asc
Description: PGP signature