From 5a5b9b9dfa616e434dc17087543f67879e6430fe Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 4 Sep 2023 15:46:00 +0200 Subject: [PATCH 1/2] gh-107902: Don't test setting suid/sgid on systems that don't support them (GH-108368) --- Lib/test/test_tarfile.py | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 2218401e3867be..f4e67eda432d1a 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -3651,34 +3651,43 @@ def test_modes(self): arc.add('read_group_only', mode='?---r-----') arc.add('no_bits', mode='?---------') arc.add('dir/', mode='?---rwsrwt') + arc.add('dir_all_bits/', mode='?rwsrwsrwt') - # On some systems, setting the sticky bit is a no-op. - # Check if that's the case. + # On some systems, setting the uid, gid, and/or sticky bit is a no-ops. + # Check which bits we can set, so we can compare tarfile machinery to + # a simple chmod. tmp_filename = os.path.join(TEMPDIR, "tmp.file") with open(tmp_filename, 'w'): pass - os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) - have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + new_mode = (os.stat(tmp_filename).st_mode + | stat.S_ISVTX | stat.S_ISGID | stat.S_ISUID) + os.chmod(tmp_filename, new_mode) + got_mode = os.stat(tmp_filename).st_mode + _t_file = 't' if (got_mode & stat.S_ISVTX) else 'x' + _suid_file = 's' if (got_mode & stat.S_ISUID) else 'x' + _sgid_file = 's' if (got_mode & stat.S_ISGID) else 'x' os.unlink(tmp_filename) os.mkdir(tmp_filename) - os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX) - have_sticky_dirs = (os.stat(tmp_filename).st_mode & stat.S_ISVTX) + new_mode = (os.stat(tmp_filename).st_mode + | stat.S_ISVTX | stat.S_ISGID | stat.S_ISUID) + os.chmod(tmp_filename, new_mode) + got_mode = os.stat(tmp_filename).st_mode + _t_dir = 't' if (got_mode & stat.S_ISVTX) else 'x' + _suid_dir = 's' if (got_mode & stat.S_ISUID) else 'x' + _sgid_dir = 's' if (got_mode & stat.S_ISGID) else 'x' os.rmdir(tmp_filename) with self.check_context(arc.open(), 'fully_trusted'): - if have_sticky_files: - self.expect_file('all_bits', mode='?rwsrwsrwt') - else: - self.expect_file('all_bits', mode='?rwsrwsrwx') + self.expect_file('all_bits', + mode=f'?rw{_suid_file}rw{_sgid_file}rw{_t_file}') self.expect_file('perm_bits', mode='?rwxrwxrwx') self.expect_file('exec_group_other', mode='?rw-rwxrwx') self.expect_file('read_group_only', mode='?---r-----') self.expect_file('no_bits', mode='?---------') - if have_sticky_dirs: - self.expect_file('dir/', mode='?---rwsrwt') - else: - self.expect_file('dir/', mode='?---rwsrwx') + self.expect_file('dir/', mode=f'?---rw{_sgid_dir}rw{_t_dir}') + self.expect_file('dir_all_bits/', + mode=f'?rw{_suid_dir}rw{_sgid_dir}rw{_t_dir}') with self.check_context(arc.open(), 'tar'): self.expect_file('all_bits', mode='?rwxr-xr-x') @@ -3687,6 +3696,7 @@ def test_modes(self): self.expect_file('read_group_only', mode='?---r-----') self.expect_file('no_bits', mode='?---------') self.expect_file('dir/', mode='?---r-xr-x') + self.expect_file('dir_all_bits/', mode='?rwxr-xr-x') with self.check_context(arc.open(), 'data'): normal_dir_mode = stat.filemode(stat.S_IMODE( @@ -3697,6 +3707,7 @@ def test_modes(self): self.expect_file('read_group_only', mode='?rw-r-----') self.expect_file('no_bits', mode='?rw-------') self.expect_file('dir/', mode=normal_dir_mode) + self.expect_file('dir_all_bits/', mode=normal_dir_mode) def test_pipe(self): # Test handling of a special file From 7ab6520ac96dc4f977909225e0e15ea24e4cf46c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 22 Sep 2023 00:59:08 +0200 Subject: [PATCH 2/2] gh-108948: Skip test_tarfile.test_modes() on EFTYPE error (#109697) On FreeBSD, regular users cannot set the sticky bit. Skip the test if chmod() fails with EFTYPE error. --- Lib/test/test_tarfile.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index f4e67eda432d1a..57ce58f0709041 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -1,3 +1,4 @@ +import errno import sys import os import io @@ -3659,14 +3660,26 @@ def test_modes(self): tmp_filename = os.path.join(TEMPDIR, "tmp.file") with open(tmp_filename, 'w'): pass - new_mode = (os.stat(tmp_filename).st_mode - | stat.S_ISVTX | stat.S_ISGID | stat.S_ISUID) - os.chmod(tmp_filename, new_mode) - got_mode = os.stat(tmp_filename).st_mode - _t_file = 't' if (got_mode & stat.S_ISVTX) else 'x' - _suid_file = 's' if (got_mode & stat.S_ISUID) else 'x' - _sgid_file = 's' if (got_mode & stat.S_ISGID) else 'x' - os.unlink(tmp_filename) + try: + new_mode = (os.stat(tmp_filename).st_mode + | stat.S_ISVTX | stat.S_ISGID | stat.S_ISUID) + try: + os.chmod(tmp_filename, new_mode) + except OSError as exc: + if exc.errno == getattr(errno, "EFTYPE", 0): + # gh-108948: On FreeBSD, regular users cannot set + # the sticky bit. + self.skipTest("chmod() failed with EFTYPE: " + "regular users cannot set sticky bit") + else: + raise + + got_mode = os.stat(tmp_filename).st_mode + _t_file = 't' if (got_mode & stat.S_ISVTX) else 'x' + _suid_file = 's' if (got_mode & stat.S_ISUID) else 'x' + _sgid_file = 's' if (got_mode & stat.S_ISGID) else 'x' + finally: + os.unlink(tmp_filename) os.mkdir(tmp_filename) new_mode = (os.stat(tmp_filename).st_mode