Index: apport-0.114/apport/fileutils.py
===================================================================
--- apport-0.114.orig/apport/fileutils.py
+++ apport-0.114/apport/fileutils.py
@@ -180,7 +180,7 @@ def get_recent_crashes(report):
     except (ValueError, KeyError):
         return 0
 
-def make_report_path(report, uid=None):
+def make_report_file(report, uid=None):
     '''Construct a canonical pathname for the given report.
 
     If uid is not given, it defaults to the uid of the current process.'''
@@ -195,7 +195,8 @@ def make_report_path(report, uid=None):
     if not uid:
         uid = os.getuid()
 
-    return os.path.join(report_dir, '%s.%i.crash' % (subject, uid))
+    path = os.path.join(report_dir, '%s.%i.crash' % (subject, uid))
+    return os.fdopen(os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o640), 'wb')
 
 def check_files_md5(sumfile):
     '''Given a list of MD5 sums in md5sum(1) format (relative to /), check
@@ -429,16 +430,30 @@ Date: %s
 CrashCounter: 3''' % time.ctime(time.mktime(time.localtime())-3600))
         self.assertEqual(get_recent_crashes(r), 3)
 
-    def test_make_report_path(self):
+    def test_make_report_file(self):
         '''Test make_report_path().'''
 
         pr = ProblemReport()
-        self.assertRaises(ValueError, make_report_path, pr)
+        self.assertRaises(ValueError, make_report_file, pr)
 
         pr['Package'] = 'bash 1'
-        self.assert_(make_report_path(pr).startswith('%s/bash' % report_dir))
+        with make_report_file(pr) as f:
+            path = os.path.join(report_dir, os.listdir(report_dir)[0])
+            self.assertTrue(path.startswith('%s/bash' % report_dir), path)
+            os.unlink(path)
+
         pr['ExecutablePath'] = '/bin/bash';
-        self.assert_(make_report_path(pr).startswith('%s/_bin_bash' % report_dir))
+        with make_report_file(pr) as f:
+            path = os.path.join(report_dir, os.listdir(report_dir)[0])
+            self.assertTrue(path.startswith('%s/_bin_bash' % report_dir), path)
+
+        # file exists already, should fail now
+        self.assertRaises(OSError, make_report_file, pr)
+
+        # should still fail if it's a dangling symlink
+        os.unlink(path)
+        os.symlink(os.path.join(report_dir, 'pwned'), path)
+        self.assertRaises(OSError, make_report_file, pr)
 
     def test_check_files_md5(self):
         '''Test check_files_md5().'''
Index: apport-0.114/bin/gcc_ice_hook
===================================================================
--- apport-0.114.orig/bin/gcc_ice_hook
+++ apport-0.114/bin/gcc_ice_hook
@@ -31,4 +31,5 @@ else:
     pr['PreprocessedSource'] = (open(sourcefile), False)
 
 # write report
-pr.write(open(apport.fileutils.make_report_path(pr), 'w'))
+with apport.fileutils.make_report_file(pr) as f:
+    pr.write(f)
Index: apport-0.114/bin/kernel_hook
===================================================================
--- apport-0.114.orig/bin/kernel_hook
+++ apport-0.114/bin/kernel_hook
@@ -11,26 +11,40 @@
 # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
 # the full text of the license.
 
-import os, sys
+import os, sys, glob
 import apport, apport.fileutils
 
 vmcore_path = os.path.join(apport.fileutils.report_dir, 'vmcore')
 
 if not os.path.exists(vmcore_path):
-    sys.exit(0)
+    apport.fatal('Cannot create report: ' + str(e))
 
 pr = apport.Report('Kernel')
 pr['Package'] = 'linux-image-' + os.uname()[2]
 pr['SourcePackage'] = 'linux'
 
 pr['VmCore'] = (vmcore_path,)
-if os.path.exists(vmcore_path + '.log'):
-    pr['VmCoreLog'] = (vmcore_path + '.log',)
 
-# write report
-pr.write(open(apport.fileutils.make_report_path(pr), 'w'))
+if os.path.exists(vmcore_path + '.log'):
+    try:
+        log_fd = os.open(vmcore_path + '.log', os.O_RDONLY | os.O_NOFOLLOW)
+        pr['VmCoreLog'] = (os.fdopen(log_fd, 'rb'),)
+        os.unlink(vmcore_path + '.log')
+    except OSError as e:
+        apport.fatal('Cannot open vmcore log: ' + str(e))
+
+# make sure vmcorepath is not a symlink
+try:
+    core_fd = os.open(vmcore_path, os.O_RDONLY | os.O_NOFOLLOW)
+    pr['VmCore'] = (os.fdopen(core_fd, 'rb'),)
+    # now, write the report
+    with apport.fileutils.make_report_file(pr) as f:
+        pr.write(f)
+except (IOError, OSError) as e:
+    apport.fatal('Cannot create report: ' + str(e))
 
 # clean up the core files
-os.unlink(vmcore_path)
-os.unlink(vmcore_path + '.log')
-
+try:
+    os.unlink(vmcore_path)
+except OSError:
+    pass
Index: apport-0.114/bin/package_hook
===================================================================
--- apport-0.114.orig/bin/package_hook
+++ apport-0.114/bin/package_hook
@@ -55,4 +55,5 @@ for l in (options.logs or []):
 	    pr[mkattrname(path)] = (path,)
 
 # write report
-pr.write(open(apport.fileutils.make_report_path(pr), 'w'))
+with apport.fileutils.make_report_file(pr) as f:
+    pr.write(f)
Index: apport-0.114/test-hooks
===================================================================
--- apport-0.114.orig/test-hooks
+++ apport-0.114/test-hooks
@@ -213,6 +193,38 @@ class _HooksTest(unittest.TestCase):
         self.assert_(r['Package'].startswith('gcc-' + gcc_version))
         self.assert_(r['SourcePackage'].startswith('gcc'))
 
+    def test_kernel_crashdump_log_symlink(self):
+        '''attempted DoS with vmcore.log symlink
+
+        We must only accept plain files, otherwise vmcore.log might be a
+        symlink to the .crash file, which would recursively fill itself.
+        '''
+        f = open(os.path.join(apport.fileutils.report_dir, 'vmcore'), 'wb')
+        f.write(b'\x01' * 100)
+        f.close()
+        os.symlink('vmcore', os.path.join(apport.fileutils.report_dir, 'vmcore.log'))
+
+        self.assertNotEqual(subprocess.call('%s/kernel_hook' % basedir,
+                                            stderr=subprocess.PIPE),
+                            0, 'kernel_crashdump unexpectedly succeeded')
+
+        self.assertEqual(apport.fileutils.get_new_reports(), [])
+
+    def test_kernel_crashdump_kdump_log_symlink(self):
+        '''attempted DoS with dmesg symlink with kdump-tools'''
+
+        timedir = "123456"
+        vmcore_dir = os.path.join(apport.fileutils.report_dir, timedir)
+        os.mkdir(vmcore_dir)
+
+        dmesgfile = os.path.join(vmcore_dir, 'dmesg.' + timedir)
+        os.symlink('../kernel.crash', dmesgfile)
+
+        self.assertNotEqual(subprocess.call('%s/kernel_hook' % basedir,
+                                            stderr=subprocess.PIPE),
+                            0, 'kernel_crashdump unexpectedly succeeded')
+        self.assertEqual(apport.fileutils.get_new_reports(), [])
+
 # call tests
 
 tl = unittest.TestLoader()
