diff -u apport-2.6.1/data/general-hooks/ubuntu.py apport-2.6.1/data/general-hooks/ubuntu.py --- apport-2.6.1/data/general-hooks/ubuntu.py +++ apport-2.6.1/data/general-hooks/ubuntu.py @@ -101,7 +101,11 @@ apport.hookutils.attach_upstart_overrides(report, package) # build a duplicate signature tag for package reports - if report.get('ProblemType') == 'Package': + if report.get('ProblemType') == 'Package' and 'ErrorMessage' in report and 'Package' in report: + (package, version) = report['Package'].split(None, 1) + dupe_sig = 'package:%s:%s:%s' % (package, version, report['ErrorMessage']) + report['DuplicateSignature'] = dupe_sig + if 'DpkgTerminalLog' in report: # this was previously trimmed in check_attachment_for_errors termlog = report['DpkgTerminalLog'] @@ -118,29 +122,16 @@ if re.search(ug_failure, termlog) or re.search(mkconfig_failure, termlog): if report['SourcePackage'] in UPDATE_BOOT: apport.hookutils.attach_default_grub(report, 'EtcDefaultGrub') - dupe_sig = '' - PKG_MSGS = ('Authenticating', 'De-configuring', 'Examining', - 'Installing ', 'Preparing', 'Processing triggers', 'Purging', - 'Removing', 'Replaced', 'Replacing', 'Setting up', - 'Unpacking', 'Would remove') - for line in termlog.split('\n'): - if line.startswith(PKG_MSGS): - dupe_sig = '%s\n' % line - continue - dupe_sig += '%s\n' % line - if 'dpkg: error' in dupe_sig and line.startswith(' '): - if 'trying to overwrite' in line: - conflict_pkg = re.search('in package (.*) ', line) - if conflict_pkg and not apport.packaging.is_distro_package(conflict_pkg.group(1)): - report['UnreportableReason'] = _('An Ubuntu package has a file conflict with a package that is not a genuine Ubuntu package') - add_tag(report, 'package-conflict') - if [d for d in PKG_MSGS if d in dupe_sig]: - report['DuplicateSignature'] = dupe_sig - # the duplicate signature should be the first failure - break - if dupe_sig: - if dpkg_log_without_error.find(dupe_sig) != -1: - report['UnreportableReason'] = _('You have already encountered this package installation failure.') + + if 'trying to overwrite' in dupe_sig: + conflict_pkg = re.search('in package (.*) ', dupe_sig) + if conflict_pkg and not apport.packaging.is_distro_package(conflict_pkg.group(1)): + report['UnreportableReason'] = _('An Ubuntu package has a file conflict with a package that is not a genuine Ubuntu package') + add_tag(report, 'package-conflict') + + if dupe_sig: + if dpkg_log_without_error.find(dupe_sig) != -1: + report['UnreportableReason'] = _('You have already encountered this package installation failure.') # running Unity? username = pwd.getpwuid(os.geteuid()).pw_name @@ -291,8 +282,8 @@ def add_release_info(report): # https://bugs.launchpad.net/bugs/364649 - apport.hookutils.attach_file_if_exists( - report, '/var/log/installer/media-info', 'InstallationMedia') + media = '/var/log/installer/media-info' + apport.hookutils.attach_file_if_exists(report, media, 'InstallationMedia') # if we are running from a live system, add the build timestamp apport.hookutils.attach_file_if_exists( @@ -310,6 +301,12 @@ else: add_tag(report, release_codename) + if os.path.exists(media): + mtime = os.stat(media).st_mtime + human_mtime = time.strftime('%Y-%m-%d', time.gmtime(mtime)) + delta = time.time() - mtime + report['InstallationDate'] = 'Installed on %s (%d days ago)' % (human_mtime, delta / 86400) + log = '/var/log/dist-upgrade/main.log' if os.path.exists(log): mtime = os.stat(log).st_mtime @@ -416,13 +413,21 @@ if 'DpkgTerminalLog' not in report: return lines = [] - trim_re = re.compile(b'^\(.* ... \d+ .*\)$') - start_re = re.compile(b'^Log started:') - for line in report['DpkgTerminalLog'].splitlines(): + dpkg_log = report['DpkgTerminalLog'] + if isinstance(dpkg_log, bytes): + trim_re = re.compile(b'^\(.* ... \d+ .*\)$') + start_re = re.compile(b'^Log started:') + elif isinstance(dpkg_log, str): + trim_re = re.compile('^\(.* ... \d+ .*\)$') + start_re = re.compile('^Log started:') + for line in dpkg_log.splitlines(): if start_re.match(line) or trim_re.match(line): lines = [] continue - lines.append(line.decode('UTF-8')) + if isinstance(line, bytes): + lines.append(line.decode('UTF-8')) + else: + lines.append(line) report['DpkgTerminalLog'] = '\n'.join(lines) if not report['DpkgTerminalLog'].strip(): diff -u apport-2.6.1/debian/changelog apport-2.6.1/debian/changelog --- apport-2.6.1/debian/changelog +++ apport-2.6.1/debian/changelog @@ -1,3 +1,91 @@ +apport (2.6.1-0ubuntu13) quantal-security; urgency=low + + * SECURITY UPDATE: incorrect permissions on setuid process core dumps + (LP: #1242435) + - use correct permissions when writing the core file in data/apport, + added test to test/test_signal_crashes.py. + - Thanks to Martin Pitt for the patch! + - CVE-2013-1067 + + -- Marc Deslauriers Wed, 23 Oct 2013 13:03:40 -0400 + +apport (2.6.1-0ubuntu12) quantal-proposed; urgency=low + + * Enable suid_dumpable (core dumps of setuid binaries). This has + always been safe for us, as we set a core pipe handler, but the + kernel now protects against one not being set: + http://kernel.ubuntu.com/git?p=ubuntu/ubuntu- + raring.git;a=blob;f=Documentation/sysctl/fs.txt;h=88152f214f48cb69c6 + 43d4bf2ff2ac9a61ad2eb0;hb=HEAD (LP: #1194541). + + -- Evan Dandrea Tue, 25 Jun 2013 16:32:21 +0100 + +apport (2.6.1-0ubuntu11) quantal-proposed; urgency=low + + * data/general-hooks/ubuntu.py: For package installation failures, build a + DuplicateSignature from the package, version, and dpkg ErrorMessage, + instead of using the whole dpkg terminal log. (LP: #1185515) + + -- Brian Murray Wed, 29 May 2013 11:51:44 -0700 + +apport (2.6.1-0ubuntu10) quantal-proposed; urgency=low + + * apport_python_hook.py: Update "ExecutableTimestamp" field when mangling + "ExecutablePath". (LP: #1077253) + + -- Brian Murray Fri, 11 Jan 2013 10:59:53 -0800 + +apport (2.6.1-0ubuntu9) quantal-proposed; urgency=low + + * Fix OSError crash in mark_report_upload(); regression from + 2.6.1-0ubuntu8. + + -- Martin Pitt Wed, 05 Dec 2012 10:16:00 +0000 + +apport (2.6.1-0ubuntu8) quantal-proposed; urgency=low + + * Ignore implausibly low addresses when computing + StacktraceAddressSignature. These are usually artifacts from gdb when not + having debug symbols, and having too many of them prevents proper + client-side duplicate detection and proper bucketing in daisy. + Backported from trunk r2541. (LP: #1084996) + * mark_report_upload(): Refresh the .upload stamps if a previous version of + the report was already uploaded, but another instance of the problem + happened since then. Thanks Brian Murray. Backported from trunk r2540. + (LP: #1084296) + + -- Martin Pitt Tue, 04 Dec 2012 10:53:52 +0000 + +apport (2.6.1-0ubuntu7) quantal-proposed; urgency=low + + * data/general-hooks/ubuntu.py: Deal with dpkg_log file being a string + instead of bytes (LP: #1080915) + + -- Brian Murray Mon, 19 Nov 2012 17:25:12 -0800 + +apport (2.6.1-0ubuntu6) quantal-proposed; urgency=low + + * Do not refer to the current release in the InstallationDate field + (LP: #1070400). We have the installed release version in the + InstallationMedia field. + + -- Evan Dandrea Wed, 24 Oct 2012 14:31:10 +0100 + +apport (2.6.1-0ubuntu5) quantal-proposed; urgency=low + + * Include the date that Ubuntu was installed with each report + (LP: #1070400). + + -- Evan Dandrea Wed, 24 Oct 2012 11:29:18 +0100 + +apport (2.6.1-0ubuntu4) quantal-proposed; urgency=low + + * apport/ui.py: create a MarkForUpload field and set that to false for + binaries that changed since the crash happened thereby preventing uploads + to the crash database (LP: #1039220) + + -- Brian Murray Tue, 16 Oct 2012 13:31:24 -0700 + apport (2.6.1-0ubuntu3) quantal; urgency=low * etc/apport/crashdb.conf: Disable Launchpad crash/kernel reports for the diff -u apport-2.6.1/debian/apport.upstart apport-2.6.1/debian/apport.upstart --- apport-2.6.1/debian/apport.upstart +++ apport-2.6.1/debian/apport.upstart @@ -31,6 +31,7 @@ fi echo "|/usr/share/apport/apport %p %s %c" > /proc/sys/kernel/core_pattern + echo 2 > /proc/sys/fs/suid_dumpable end script post-stop script @@ -45,6 +46,7 @@ then exit 1 else + echo 0 > /proc/sys/fs/suid_dumpable echo "core" > /proc/sys/kernel/core_pattern fi end script only in patch2: unchanged: --- apport-2.6.1.orig/apport_python_hook.py +++ apport-2.6.1/apport_python_hook.py @@ -104,6 +104,8 @@ pr.add_user_info() # override the ExecutablePath with the script that was actually running pr['ExecutablePath'] = binary + if 'ExecutableTimestamp' in pr: + pr['ExecutableTimestamp'] = str(int(os.stat(binary).st_mtime)) try: pr['PythonArgs'] = '%r' % sys.argv except AttributeError: only in patch2: unchanged: --- apport-2.6.1.orig/apport/ui.py +++ apport-2.6.1/apport/ui.py @@ -280,7 +280,12 @@ if not response['report']: return - apport.fileutils.mark_report_upload(report_file) + # We don't want to send crashes to the crash database for binaries + # that changed since the crash happened. See LP: #1039220 for + # details. + if 'MarkForUpload' in self.report and \ + self.report['MarkForUpload'] != 'False': + apport.fileutils.mark_report_upload(report_file) # We check for duplicates and unreportable crashes here, rather # than before we show the dialog, as we want to submit these to the # crash database, but not Launchpad. @@ -929,6 +934,7 @@ If a symptom script is given, this will be run first (used by run_symptom()). ''' + self.report['MarkForUpload'] = 'True' # check if binary changed since the crash happened if 'ExecutablePath' in self.report and 'ExecutableTimestamp' in self.report: orig_time = int(self.report['ExecutableTimestamp']) @@ -936,6 +942,7 @@ cur_time = int(os.stat(self.report['ExecutablePath']).st_mtime) if orig_time != cur_time: + self.report['MarkForUpload'] = 'False' self.report['UnreportableReason'] = ( _('The problem happened with the program %s which changed ' 'since the crash occurred.') % self.report['ExecutablePath']) only in patch2: unchanged: --- apport-2.6.1.orig/apport/report.py +++ apport-2.6.1/apport/report.py @@ -1287,6 +1287,10 @@ if not addr.startswith('0x'): continue addr = int(addr, 16) # we do want to know about ValueErrors here, so don't catch + # ignore impossibly low addresses; these are usually artifacts + # from gdb when not having debug symbols + if addr < 0x1000: + continue offset = self._address_to_offset(addr) if offset: # avoid ':' in ELF paths, we use that as separator only in patch2: unchanged: --- apport-2.6.1.orig/apport/fileutils.py +++ apport-2.6.1/apport/fileutils.py @@ -101,8 +101,15 @@ def mark_report_upload(report): - report = '%s.upload' % report.rsplit('.', 1)[0] - with open(report, 'a'): + upload = '%s.upload' % report.rsplit('.', 1)[0] + uploaded = '%s.uploaded' % report.rsplit('.', 1)[0] + # if uploaded exists and is older than the report remove it and upload + if os.path.exists(uploaded) and os.path.exists(upload): + report_st = os.stat(report) + upload_st = os.stat(upload) + if upload_st.st_mtime < report_st.st_mtime: + os.unlink(upload) + with open(upload, 'a'): pass only in patch2: unchanged: --- apport-2.6.1.orig/test/test_report.py +++ apport-2.6.1/test/test_report.py @@ -1798,6 +1798,8 @@ self.assertEqual(pr._address_to_offset(0x006de000), '/bin/bash+0') self.assertEqual(pr._address_to_offset(0x006df000), '/bin/bash+1000') self.assertEqual(pr._address_to_offset(0x006df001), None) + self.assertEqual(pr._address_to_offset(0), None) + self.assertEqual(pr._address_to_offset(0x10), None) self.assertEqual(pr._address_to_offset(0x7f491fc24010), '/lib/with spaces !/libfoo.so+10') @@ -1870,7 +1872,27 @@ #6 0x000000000041d715 in main () #7 0x000000000041d703 in _start () ''' - self.assertNotEqual(pr.crash_signature_addresses(), None) + sig = pr.crash_signature_addresses() + self.assertNotEqual(sig, None) + + # one true unresolvable, and some "low address" artifacts; should be + # identical to the one above + pr['Stacktrace'] = ''' +#0 0x00007f491fac5687 in kill () at ../sysdeps/unix/syscall-template.S:82 +No locals. +#1 0x000001000043fd51 in kill_pid () +#2 0x0000000000000010 in ?? +#3 g_main_context_iterate (context=0x1731680) at gmain.c:3068 +#4 0x000000000042eb76 in ?? () +#5 0x0000000000000000 in ?? () +#6 0x0000000000000421 in ?? () +#7 0x00000000004324d8 in ?? +No symbol table info available. +#8 0x00000000004707e3 in parse_and_execute () +#9 0x000000000041d715 in main () +#10 0x000000000041d703 in _start () +''' + self.assertEqual(pr.crash_signature_addresses(), sig) # two unresolvables, 2/7 is too much pr['Stacktrace'] = ''' only in patch2: unchanged: --- apport-2.6.1.orig/test/test_signal_crashes.py +++ apport-2.6.1/test/test_signal_crashes.py @@ -289,12 +289,12 @@ self.check_report_coredump(self.test_report) apport.fileutils.delete_report(self.test_report) resource.setrlimit(resource.RLIMIT_CORE, (10000, -1)) - self.do_crash(expect_corefile=True) + self.do_crash(expect_corefile=True, expect_corefile_owner=os.geteuid()) self.assertEqual(apport.fileutils.get_all_reports(), [self.test_report]) self.check_report_coredump(self.test_report) apport.fileutils.delete_report(self.test_report) resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) - self.do_crash(expect_corefile=True) + self.do_crash(expect_corefile=True, expect_corefile_owner=os.geteuid()) self.assertEqual(apport.fileutils.get_all_reports(), [self.test_report]) self.check_report_coredump(self.test_report) apport.fileutils.delete_report(self.test_report) @@ -308,11 +308,11 @@ self.assertEqual(apport.fileutils.get_all_reports(), [self.test_report]) apport.fileutils.delete_report(self.test_report) resource.setrlimit(resource.RLIMIT_CORE, (10000, -1)) - self.do_crash(expect_corefile=True, sig=signal.SIGABRT) + self.do_crash(expect_corefile=True, sig=signal.SIGABRT, expect_corefile_owner=os.geteuid()) self.assertEqual(apport.fileutils.get_all_reports(), [self.test_report]) apport.fileutils.delete_report(self.test_report) resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) - self.do_crash(expect_corefile=True, sig=signal.SIGABRT) + self.do_crash(expect_corefile=True, sig=signal.SIGABRT, expect_corefile_owner=os.geteuid()) self.assertEqual(apport.fileutils.get_all_reports(), [self.test_report]) # creates core file with existing crash report, too @@ -534,12 +534,64 @@ self.assertEqual(pr['ExecutablePath'], test_executable) self.assertEqual(pr['CoreDump'], b'hel\x01lo') + @unittest.skipIf(os.geteuid() != 0, 'this test needs to be run as root') + def test_crash_setuid_keep(self): + '''report generation and core dump for setuid program which stays root''' + + # create suid root executable in a path we can modify which apport + # regards as likely packaged + (fd, myexe) = tempfile.mkstemp(dir='/var/tmp') + self.addCleanup(os.unlink, myexe) + with open(test_executable, 'rb') as f: + os.write(fd, f.read()) + os.close(fd) + os.chmod(myexe, 0o4755) + + # run test program as user "mail" + resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) + # expect the core file to be owned by root + self.do_crash(command=myexe, expect_corefile=True, uid=8, + expect_corefile_owner=0) + + # check crash report + reports = apport.fileutils.get_all_reports() + self.assertEqual(len(reports), 1) + report = reports[0] + st = os.stat(report) + os.unlink(report) + self.assertEqual(stat.S_IMODE(st.st_mode), 0o640, 'report has correct permissions') + # this must not be owned by root as it is a setuid binary + self.assertEqual(st.st_uid, 0, 'report has correct owner') + + @unittest.skipUnless(os.path.exists('/bin/ping'), 'this test needs /bin/ping') + @unittest.skipIf(os.geteuid() != 0, 'this test needs to be run as root') + def test_crash_setuid_drop(self): + '''report generation and core dump for setuid program which drops root''' + + # run ping as user "mail" + resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) + # expect the core file to be owned by root + self.do_crash(command='/bin/ping', args=['127.0.0.1'], + expect_corefile=True, uid=8, + expect_corefile_owner=0) + + # check crash report + reports = apport.fileutils.get_all_reports() + self.assertEqual(len(reports), 1) + report = reports[0] + st = os.stat(report) + os.unlink(report) + self.assertEqual(stat.S_IMODE(st.st_mode), 0o640, 'report has correct permissions') + # this must not be owned by root as it is a setuid binary + self.assertEqual(st.st_uid, 0, 'report has correct owner') + # # Helper methods # @classmethod - def create_test_process(klass, check_running=True, command=test_executable): + def create_test_process(klass, check_running=True, command=test_executable, + uid=None, args=[]): '''Spawn test_executable. Wait until it is fully running, and return its PID. @@ -549,10 +601,12 @@ assert subprocess.call(['pidof', command]) == 1, 'no running test executable processes' pid = os.fork() if pid == 0: + if uid is not None: + os.setuid(uid) os.dup2(os.open('/dev/null', os.O_WRONLY), sys.stdout.fileno()) sys.stdin.close() os.setsid() - os.execv(command, [command]) + os.execv(command, [command] + args) assert False, 'Could not execute ' + command # wait until child process has execv()ed properly @@ -569,7 +623,8 @@ def do_crash(self, expect_coredump=True, expect_corefile=False, sig=signal.SIGSEGV, check_running=True, sleep=0, - command=test_executable): + command=test_executable, uid=None, + expect_corefile_owner=None, args=[]): '''Generate a test crash. This runs command (by default test_executable) in /tmp, lets it crash, @@ -581,7 +636,7 @@ already running. ''' self.assertFalse(os.path.exists('core'), '/tmp/core already exists, please clean up first') - pid = self.create_test_process(check_running, command) + pid = self.create_test_process(check_running, command, uid=uid, args=args) if sleep > 0: time.sleep(sleep) os.kill(pid, sig) @@ -609,6 +664,12 @@ if expect_corefile: self.assertTrue(os.path.exists('/tmp/core'), 'leaves wanted core file') try: + # check core file permissions + st = os.stat('/tmp/core') + self.assertEqual(stat.S_IMODE(st.st_mode), 0o600, 'core file has correct permissions') + if expect_corefile_owner is not None: + self.assertEqual(st.st_uid, expect_corefile_owner, 'core file has correct owner') + # check that core file is valid gdb = subprocess.Popen(['gdb', '--batch', '--ex', 'bt', command, '/tmp/core'], only in patch2: unchanged: --- apport-2.6.1.orig/test/test_python_crashes.py +++ apport-2.6.1/test/test_python_crashes.py @@ -35,8 +35,9 @@ fd = os.open(scriptname, os.O_CREAT | os.O_WRONLY) else: (fd, script) = tempfile.mkstemp(dir='/var/tmp') - try: - os.write(fd, ('''#!/usr/bin/env %s + self.addCleanup(os.unlink, script) + + os.write(fd, ('''#!/usr/bin/env %s import apport_python_hook apport_python_hook.install() @@ -46,21 +47,19 @@ %s func(42) ''' % (os.getenv('PYTHON', 'python3'), extracode)).encode()) - os.close(fd) - os.chmod(script, 0o755) - env = os.environ.copy() - env['PYTHONPATH'] = '/my/bogus/path' - - p = subprocess.Popen([script, 'testarg1', 'testarg2'], - stderr=subprocess.PIPE, env=env) - err = p.communicate()[1].decode() - self.assertEqual(p.returncode, 1, - 'crashing test python program exits with failure code') - if not extracode: - self.assertTrue('This should happen.' in err, err) - self.assertFalse('OSError' in err, err) - finally: - os.unlink(script) + os.close(fd) + os.chmod(script, 0o755) + env = os.environ.copy() + env['PYTHONPATH'] = '/my/bogus/path' + + p = subprocess.Popen([script, 'testarg1', 'testarg2'], + stderr=subprocess.PIPE, env=env) + err = p.communicate()[1].decode() + self.assertEqual(p.returncode, 1, + 'crashing test python program exits with failure code') + if not extracode: + self.assertTrue('This should happen.' in err, err) + self.assertFalse('OSError' in err, err) return script @@ -89,6 +88,8 @@ 'report has necessary fields') self.assertTrue('bin/python' in pr['InterpreterPath']) self.assertEqual(pr['ExecutablePath'], script) + self.assertEqual(pr['ExecutableTimestamp'], + str(int(os.stat(script).st_mtime))) self.assertEqual(pr['PythonArgs'], "['%s', 'testarg1', 'testarg2']" % script) self.assertTrue(pr['Traceback'].startswith('Traceback')) self.assertTrue("func\n raise Exception(b'This should happen." in @@ -143,6 +144,12 @@ self.assertTrue(set(expected_keys).issubset(set(pr.keys())), 'report has necessary fields') self.assertTrue('bin/python' in pr['InterpreterPath']) + # we have no actual executable, so we should fall back to the + # interpreter + self.assertEqual(pr['ExecutablePath'], pr['InterpreterPath']) + if 'ExecutableTimestamp' in pr: + self.assertEqual(pr['ExecutableTimestamp'], + str(int(os.stat(pr['ExecutablePath']).st_mtime))) self.assertTrue(pr['Traceback'].startswith('Traceback')) def test_python_env(self): @@ -247,14 +254,17 @@ count = 0 limit = 5 - while count < limit: - self._test_crash(scriptname='/var/tmp/pytestcrash') - reports = apport.fileutils.get_new_reports() - if not reports: - break - self.assertEqual(len(reports), 1, 'crashed Python program produced one report') - apport.fileutils.mark_report_seen(reports[0]) - count += 1 + try: + while count < limit: + self._test_crash(scriptname='/var/tmp/pytestcrash') + reports = apport.fileutils.get_new_reports() + if not reports: + break + self.assertEqual(len(reports), 1, 'crashed Python program produced one report') + apport.fileutils.mark_report_seen(reports[0]) + count += 1 + finally: + os.unlink('/var/tmp/pytestcrash') self.assertGreater(count, 1) self.assertLess(count, limit) only in patch2: unchanged: --- apport-2.6.1.orig/test/test_fileutils.py +++ apport-2.6.1/test/test_fileutils.py @@ -130,6 +130,24 @@ expected = os.path.join(apport.fileutils.report_dir, 'report.upload') self.assertTrue(os.path.exists(expected)) + def test_mark_2nd_report_upload(self): + '''mark_report_upload() for a previously uploaded report''' + upload = os.path.join(apport.fileutils.report_dir, 'report.upload') + with open(upload, 'w'): + pass + uploaded = os.path.join(apport.fileutils.report_dir, 'report.uploaded') + with open(uploaded, 'w'): + pass + time.sleep(1) + report = os.path.join(apport.fileutils.report_dir, 'report.crash') + with open(report, 'w'): + pass + time.sleep(1) + apport.fileutils.mark_report_upload(report) + upload_st = os.stat(upload) + report_st = os.stat(report) + self.assertTrue(upload_st.st_mtime > report_st.st_mtime) + def test_get_all_reports(self): '''get_all_reports()''' only in patch2: unchanged: --- apport-2.6.1.orig/data/apport +++ apport-2.6.1/data/apport @@ -51,7 +51,7 @@ stat = None try: - stat = os.stat('/proc/' + pid) + stat = os.stat('/proc/%s/stat' % pid) except OSError as e: raise ValueError('Invalid process ID: ' + str(e)) @@ -145,7 +145,7 @@ with open('/proc/sys/kernel/core_uses_pid') as f: if f.read().strip() != '0': core_path += '.' + str(pid) - core_file = os.open(core_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o640) + core_file = os.open(core_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) except (OSError, IOError): return @@ -300,7 +300,7 @@ core_ulimit = -1 try: - pidstat = os.stat('/proc/' + pid) + pidstat = os.stat('/proc/%s/stat' % pid) except OSError: error_log('Invalid PID') sys.exit(1)