[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#849865: jessie-pu: package postgresql-common/165+deb8u2



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


Reply to: