289
289
self.assertGreater(count, 1, 'gets at least 2 repeated crashes')
290
290
self.assertLess(count, 7, 'stops flooding after less than 7 repeated crashes')
292
@unittest.skipIf(os.access('/run', os.W_OK), 'this test needs to be run as user')
292
293
def test_nonwritable_cwd(self):
293
294
'''core dump works for non-writable cwd'''
297
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
297
299
pr = apport.Report()
298
300
self.assertTrue(os.path.exists(self.test_report))
301
self.assertFalse(os.path.exists('/run/core'))
299
302
with open(self.test_report, 'rb') as f:
301
304
assert set(required_fields).issubset(set(pr.keys()))
306
@unittest.skipIf(os.access('/run', os.W_OK), 'this test needs to be run as user')
307
def test_nonwritable_cwd_nonreadable_exe(self):
308
'''no core file for non-readable exe in non-writable cwd'''
310
# CVE-2015-1324: if a user cannot read an executable, it behaves much
311
# like a suid root binary in terms of writing a core dump
313
# create a non-readable executable in a path we can modify which apport
314
# regards as likely packaged
315
(fd, myexe) = tempfile.mkstemp(dir='/var/tmp')
316
self.addCleanup(os.unlink, myexe)
317
with open(test_executable, 'rb') as f:
318
os.write(fd, f.read())
320
os.chmod(myexe, 0o111)
323
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
326
self.do_crash(True, command=myexe, expect_corefile=False)
329
reports = apport.fileutils.get_new_system_reports()
330
self.assertEqual(len(reports), 1)
333
# FIXME: we would like to clean up this, but don't have privileges for that
335
self.assertEqual(stat.S_IMODE(st.st_mode), 0o640, 'report has correct permissions')
336
# this must be owned by root as it is an unreadable binary
337
self.assertEqual(st.st_uid, 0, 'report has correct owner')
340
self.assertEqual(apport.fileutils.get_all_reports(), [])
342
# no cores/dump if suid_dumpable == 0
343
self.do_crash(False, command=myexe, expect_corefile=False)
344
self.assertEqual(apport.fileutils.get_all_reports(), [])
303
346
def test_core_dump_packaged(self):
304
347
'''packaged executables create core dumps on proper ulimits'''
544
587
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
546
589
if suid_dumpable:
547
# expect the core file to be owned by root
548
self.do_crash(command=myexe, expect_corefile=True, uid=8,
549
expect_corefile_owner=0)
590
# if a user can crash a suid root binary, it should not create core files
591
self.do_crash(command=myexe, uid=8)
551
593
# check crash report
552
594
reports = apport.fileutils.get_all_reports()
565
607
@unittest.skipUnless(os.path.exists('/bin/ping'), 'this test needs /bin/ping')
566
608
@unittest.skipIf(os.geteuid() != 0, 'this test needs to be run as root')
567
609
def test_crash_setuid_drop(self):
568
'''report generation and core dump for setuid program which drops root'''
610
'''report generation for setuid program which drops root'''
570
612
# run ping as user "mail"
571
613
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
573
615
if suid_dumpable:
574
# expect the core file to be owned by root
575
self.do_crash(command='/bin/ping', args=['127.0.0.1'],
576
expect_corefile=True, uid=8,
577
expect_corefile_owner=0)
616
# if a user can crash a suid root binary, it should not create core files
617
self.do_crash(command='/bin/ping', args=['127.0.0.1'], uid=8)
579
619
# check crash report
580
620
reports = apport.fileutils.get_all_reports()
592
632
self.assertEqual(apport.fileutils.get_all_reports(), [])
634
@unittest.skipIf(os.geteuid() != 0, 'this test needs to be run as root')
635
def test_crash_setuid_unpackaged(self):
636
'''report generation for unpackaged setuid program'''
638
# create suid root executable in a path we can modify which apport
639
# regards as not packaged
640
(fd, myexe) = tempfile.mkstemp(dir='/tmp')
641
self.addCleanup(os.unlink, myexe)
642
with open(test_executable, 'rb') as f:
643
os.write(fd, f.read())
645
os.chmod(myexe, 0o4755)
647
# run test program as user "mail"
648
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
651
# if a user can crash a suid root binary, it should not create core files
652
self.do_crash(command=myexe, expect_corefile=False, uid=8)
654
# no cores/dump if suid_dumpable == 0
655
self.do_crash(False, command=myexe, expect_corefile=False, uid=8)
657
# there should not be a crash report
658
self.assertEqual(apport.fileutils.get_all_reports(), [])
660
@unittest.skipIf(os.geteuid() != 0, 'this test needs to be run as root')
661
def test_crash_setuid_nonwritable_cwd(self):
662
'''report generation and core dump for setuid program, non-writable cwd'''
664
# create suid root executable in a path we can modify which apport
665
# regards as likely packaged
666
(fd, myexe) = tempfile.mkstemp(dir='/var/tmp')
667
self.addCleanup(os.unlink, myexe)
668
with open(test_executable, 'rb') as f:
669
os.write(fd, f.read())
671
os.chmod(myexe, 0o4755)
673
# run test program as user "mail" in /run (which should only be
676
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
679
# we expect a report, but no core file
680
self.do_crash(command=myexe, expect_corefile=False, uid=8)
683
reports = apport.fileutils.get_all_reports()
684
self.assertEqual(len(reports), 1)
688
self.assertEqual(stat.S_IMODE(st.st_mode), 0o640, 'report has correct permissions')
689
# this must be owned by root as it is a setuid binary
690
self.assertEqual(st.st_uid, 0, 'report has correct owner')
692
# no core/report if suid_dumpable == 0
693
self.do_crash(False, command=myexe, expect_corefile=False, uid=8)
694
self.assertEqual(apport.fileutils.get_all_reports(), [])
594
696
@unittest.skipUnless(os.path.exists('/usr/bin/lxc-usernsexec'), 'this test needs lxc')
595
697
@unittest.skipUnless(os.path.exists('/bin/busybox'), 'this test needs busybox')
596
698
@unittest.skipIf(os.access('/etc/shadow', os.R_OK), 'this test needs to be run as user')