]> git.proxmox.com Git - pve-common.git/commitdiff
harden file_set_contents against symlink attacks
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Tue, 16 Aug 2016 14:31:09 +0000 (16:31 +0200)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Tue, 16 Aug 2016 15:12:55 +0000 (17:12 +0200)
src/PVE/Tools.pm

index 0fb7f3c0b15b6a47a4c7d33a29b2f8db60e3339b..7ee3450f9eb603c92a0ea7b613c216104f1673d0 100644 (file)
@@ -2,7 +2,7 @@ package PVE::Tools;
 
 use strict;
 use warnings;
-use POSIX qw(EINTR);
+use POSIX qw(EINTR EEXIST);
 use IO::Socket::IP;
 use Socket qw(AF_INET AF_INET6 AI_ALL AI_V4MAPPED);
 use IO::Select;
@@ -203,7 +203,13 @@ sub file_set_contents {
     my $tmpname = "$filename.tmp.$$";
 
     eval {
-       my $fh = IO::File->new($tmpname, O_WRONLY|O_CREAT, $perm);
+       my ($fh, $tries) = (undef, 0);
+       while (!$fh && $tries++ < 3) {
+           $fh = IO::File->new($tmpname, O_WRONLY|O_CREAT|O_EXCL, $perm);
+           if (!$fh && $! == EEXIST) {
+               unlink($tmpname) or die "unable to delete old temp file: $!\n";
+           }
+       }
        die "unable to open file '$tmpname' - $!\n" if !$fh;
        die "unable to write '$tmpname' - $!\n" unless print $fh $data;
        die "closing file '$tmpname' failed - $!\n" unless close $fh;