From: Luciano Bello <luciano@debian.org>
Subject: Patch for tempfile vulnerability, CVE-2013-4969
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -710,31 +710,22 @@
   def write(property)
     remove_existing(:file)
 
-    use_temporary_file = write_temporary_file?
-    if use_temporary_file
-      path = "#{self[:path]}.puppettmp_#{rand(10000)}"
-      path = "#{self[:path]}.puppettmp_#{rand(10000)}" while File.exists?(path) or File.symlink?(path)
-    else
-      path = self[:path]
-    end
+    default_mode = 0644
 
-    mode = self.should(:mode) # might be nil
-    umask = mode ? 000 : 022
-    mode_int = mode ? mode.to_i(8) : nil
+    catalog_mode = self.should(:mode) # might be nil
 
-    content_checksum = Puppet::Util.withumask(umask) { File.open(path, 'w', mode_int ) { |f| write_content(f) } }
+    mode = catalog_mode ? catalog_mode : default_mode
 
-    # And put our new file in place
-    if use_temporary_file # This is only not true when our file is empty.
-      begin
-        fail_if_checksum_is_wrong(path, content_checksum) if validate_checksum?
-        File.rename(path, self[:path])
-      rescue => detail
-        fail "Could not rename temporary file #{path} to #{self[:path]}: #{detail}"
-      ensure
-        # Make sure the created file gets removed
-        File.unlink(path) if FileTest.exists?(path)
+    if write_temporary_file?
+      Puppet::Util.replace_file(self[:path], mode) do |file|
+        file.binmode
+        content_checksum = write_content(file)
+        file.flush
+        fail_if_checksum_is_wrong(file.path, content_checksum) if validate_checksum?
       end
+    else
+      umask = mode ? 000 : 022
+      Puppet::Util.withumask(umask) { ::File.open(self[:path], 'wb', mode ) { |f| write_content(f) } }
     end
 
     # make sure all of the modes are actually correct
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -439,13 +439,12 @@
     if file_exists
       stat = file.lstat
 
-      # We only care about the four lowest-order octets. Higher octets are
-      # filesystem-specific.
-      mode = stat.mode & 07777
+      tempfile.chown(stat.uid, stat.gid)
+      effective_mode = stat.mode
       uid = stat.uid
       gid = stat.gid
     else
-      mode = default_mode
+      effective_mode = default_mode
       uid = Process.euid
       gid = Process.egid
     end
@@ -453,7 +452,7 @@
     # Set properties of the temporary file before we write the content, because
     # Tempfile doesn't promise to be safe from reading by other people, just
     # that it avoids races around creating the file.
-    tempfile.chmod(mode)
+    tempfile.chmod(effective_mode & 07777)
     tempfile.chown(uid, gid)
 
     # OK, now allow the caller to write the content of the file.
--- a/spec/integration/type/file_spec.rb
+++ b/spec/integration/type/file_spec.rb
@@ -130,21 +130,6 @@
       bucket.bucket.getfile(foomd5).should == "fooyay"
       bucket.bucket.getfile(barmd5).should == "baryay"
     end
-
-    it "should propagate failures encountered when renaming the temporary file" do
-      file = Puppet::Type.type(:file).new :path => tmpfile("fail_rename"), :content => "foo"
-      file.stubs(:remove_existing) # because it tries to make a backup
-
-      catalog = Puppet::Resource::Catalog.new
-      catalog.add_resource file
-
-      File.open(file[:path], "w") { |f| f.print "bar" }
-
-      File.expects(:rename).raises ArgumentError
-
-      lambda { file.write(:content) }.should raise_error(Puppet::Error)
-      File.read(file[:path]).should == "bar"
-    end
   end
 
   describe "when recursing" do
--- a/spec/unit/type/file_spec.rb
+++ b/spec/unit/type/file_spec.rb
@@ -39,34 +39,6 @@
 
   describe "#write" do
 
-    it "should propagate failures encountered when renaming the temporary file" do
-      File.stubs(:open)
-
-      File.expects(:rename).raises ArgumentError
-      file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet")
-
-      file.stubs(:validate_checksum?).returns(false)
-
-      property = stub('content_property', :actual_content => "something", :length => "something".length)
-      file.stubs(:property).with(:content).returns(property)
-
-      lambda { file.write(:content) }.should raise_error(Puppet::Error)
-    end
-
-    it "should delegate writing to the content property" do
-      filehandle = stub_everything 'fh'
-      File.stubs(:open).yields(filehandle)
-      File.stubs(:rename)
-      property = stub('content_property', :actual_content => "something", :length => "something".length)
-      file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet")
-      file.stubs(:validate_checksum?).returns(false)
-      file.stubs(:property).with(:content).returns(property)
-
-      property.expects(:write).with(filehandle)
-
-      file.write(:content)
-    end
-
     describe "when validating the checksum" do
       before { @file.stubs(:validate_checksum?).returns(true) }
 
