From d40f8b5e193d4fcb6fb6010c9e6e9ccbb1f66790 Mon Sep 17 00:00:00 2001 From: Thomas Kowalski Date: Sun, 23 Aug 2026 10:50:22 +0200 Subject: [PATCH 1/2] fix: add missing checks in os.chmod --- Lib/test/test_os/test_posix.py | 24 +++++++++++++++++++ ...-08-23-08-41-00.gh-issue-156264.hJ8qJn.rst | 3 +++ Modules/posixmodule.c | 9 +++++++ 3 files changed, 36 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-08-23-08-41-00.gh-issue-156264.hJ8qJn.rst diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index 814f945aac7453c..4c5082831632db1 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -1109,6 +1109,30 @@ def test_fchmod_file(self): self.check_chmod(posix.fchmod, f.fileno()) self.check_chmod(posix.chmod, f.fileno()) + @os_helper.skip_unless_working_chmod + @unittest.skipUnless(os.chmod in os.supports_fd, + "test needs fd support in os.chmod()") + @unittest.skipUnless(os.chmod in os.supports_dir_fd, + "test needs dir_fd support in os.chmod()") + def test_chmod_fd_with_dir_fd(self): + with open(os_helper.TESTFN, 'wb+') as f: + dir_fd = os.open(os.curdir, os.O_RDONLY) + self.addCleanup(os.close, dir_fd) + with self.assertRaisesRegex(ValueError, + 'can\'t specify both dir_fd and fd'): + posix.chmod(f.fileno(), 0o600, dir_fd=dir_fd) + + @os_helper.skip_unless_working_chmod + @unittest.skipUnless(os.chmod in os.supports_fd, + "test needs fd support in os.chmod()") + @unittest.skipIf(os.name == 'nt', + 'follow_symlinks defaults to False on Windows') + def test_chmod_fd_follow_symlinks(self): + with open(os_helper.TESTFN, 'wb+') as f: + with self.assertRaisesRegex(ValueError, + 'cannot use fd and follow_symlinks together'): + posix.chmod(f.fileno(), 0o600, follow_symlinks=False) + @unittest.skipUnless(hasattr(posix, 'lchmod'), 'test needs os.lchmod()') def test_lchmod_file(self): self.check_chmod(posix.lchmod, os_helper.TESTFN) diff --git a/Misc/NEWS.d/next/Library/2026-08-23-08-41-00.gh-issue-156264.hJ8qJn.rst b/Misc/NEWS.d/next/Library/2026-08-23-08-41-00.gh-issue-156264.hJ8qJn.rst new file mode 100644 index 000000000000000..836e804182276c8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-23-08-41-00.gh-issue-156264.hJ8qJn.rst @@ -0,0 +1,3 @@ +:func:`os.chmod` now raises :exc:`ValueError` when *dir_fd* or +*follow_symlinks* is used together with a file descriptor *path*, matching +the documented behaviour and :func:`os.chown`. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index bec305a4042c49d..1d09db4030136e1 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4113,6 +4113,15 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd, return NULL; #endif + if (dir_fd_and_fd_invalid("chmod", dir_fd, path->fd)) + return NULL; +#ifndef MS_WINDOWS + /* On Windows, follow_symlinks defaults to False, so doing this check + would reject the valid os.chmod(fd, mode). */ + if (fd_and_follow_symlinks_invalid("chmod", path->is_fd, follow_symlinks)) + return NULL; +#endif + if (PySys_Audit("os.chmod", "Oii", path->object, mode, dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) { return NULL; From 6d581de03c835570013f08c537e8097e6c7b04bf Mon Sep 17 00:00:00 2001 From: Thomas Kowalski Date: Mon, 24 Aug 2026 17:57:17 +0200 Subject: [PATCH 2/2] review: pep-7 compliance --- Modules/posixmodule.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 1d09db4030136e1..148abb170c30984 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -4113,13 +4113,18 @@ os_chmod_impl(PyObject *module, path_t *path, int mode, int dir_fd, return NULL; #endif - if (dir_fd_and_fd_invalid("chmod", dir_fd, path->fd)) + if (dir_fd_and_fd_invalid("chmod", dir_fd, path->fd)) { return NULL; + } + #ifndef MS_WINDOWS /* On Windows, follow_symlinks defaults to False, so doing this check would reject the valid os.chmod(fd, mode). */ - if (fd_and_follow_symlinks_invalid("chmod", path->is_fd, follow_symlinks)) + if (fd_and_follow_symlinks_invalid("chmod", + path->is_fd, + follow_symlinks)) { return NULL; + } #endif if (PySys_Audit("os.chmod", "Oii", path->object, mode,