]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-134744: Fix fcntl error handling (#134748)
authorVictor Stinner <vstinner@python.org>
Tue, 27 May 2025 13:09:46 +0000 (15:09 +0200)
committerGitHub <noreply@github.com>
Tue, 27 May 2025 13:09:46 +0000 (15:09 +0200)
Fix also reference leak on buffer overflow.

Lib/test/test_fcntl.py
Lib/test/test_ioctl.py
Modules/fcntlmodule.c

index e0e6782258fa78f715c6ddb6b4e0223c6b4e76aa..7140a7b4f29188d297f5b1d22e62a93090890117 100644 (file)
@@ -11,7 +11,7 @@ from test.support import (
     cpython_only, get_pagesize, is_apple, requires_subprocess, verbose
 )
 from test.support.import_helper import import_module
-from test.support.os_helper import TESTFN, unlink
+from test.support.os_helper import TESTFN, unlink, make_bad_fd
 
 
 # Skip test if no fcntl module.
@@ -274,6 +274,17 @@ class TestFcntl(unittest.TestCase):
     def test_fcntl_large_buffer(self):
         self._check_fcntl_not_mutate_len(2024)
 
+    @unittest.skipUnless(hasattr(fcntl, 'F_DUPFD'), 'need fcntl.F_DUPFD')
+    def test_bad_fd(self):
+        # gh-134744: Test error handling
+        fd = make_bad_fd()
+        with self.assertRaises(OSError):
+            fcntl.fcntl(fd, fcntl.F_DUPFD, 0)
+        with self.assertRaises(OSError):
+            fcntl.fcntl(fd, fcntl.F_DUPFD, b'\0' * 10)
+        with self.assertRaises(OSError):
+            fcntl.fcntl(fd, fcntl.F_DUPFD, b'\0' * 2048)
+
 
 if __name__ == '__main__':
     unittest.main()
index 3c7a58aa2bc7bfbaf71b9047cb5053b4c76e1f91..277d2fc99eaec65f93d11d396d9db9b98aa8f791 100644 (file)
@@ -5,7 +5,7 @@ import sys
 import threading
 import unittest
 from test import support
-from test.support import threading_helper
+from test.support import os_helper, threading_helper
 from test.support.import_helper import import_module
 fcntl = import_module('fcntl')
 termios = import_module('termios')
@@ -201,6 +201,17 @@ class IoctlTestsPty(unittest.TestCase):
         new_winsz = struct.unpack("HHHH", result)
         self.assertEqual(new_winsz[:2], (20, 40))
 
+    @unittest.skipUnless(hasattr(fcntl, 'FICLONE'), 'need fcntl.FICLONE')
+    def test_bad_fd(self):
+        # gh-134744: Test error handling
+        fd = os_helper.make_bad_fd()
+        with self.assertRaises(OSError):
+            fcntl.ioctl(fd, fcntl.FICLONE, fd)
+        with self.assertRaises(OSError):
+            fcntl.ioctl(fd, fcntl.FICLONE, b'\0' * 10)
+        with self.assertRaises(OSError):
+            fcntl.ioctl(fd, fcntl.FICLONE, b'\0' * 2048)
+
 
 if __name__ == "__main__":
     unittest.main()
index 8b6379f1e6501be9371728b16e7976d4c65c9237..90363b9dca331627444aeb1a7d74447f6f7369a1 100644 (file)
@@ -128,7 +128,7 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
                 Py_END_ALLOW_THREADS
             } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
             if (ret < 0) {
-                if (async_err) {
+                if (!async_err) {
                     PyErr_SetFromErrno(PyExc_OSError);
                 }
                 Py_DECREF(result);
@@ -136,6 +136,7 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
             }
             if (ptr[len] != '\0') {
                 PyErr_SetString(PyExc_SystemError, "buffer overflow");
+                Py_DECREF(result);
                 return NULL;
             }
             return result;
@@ -310,7 +311,7 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
                 Py_END_ALLOW_THREADS
             } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
             if (ret < 0) {
-                if (async_err) {
+                if (!async_err) {
                     PyErr_SetFromErrno(PyExc_OSError);
                 }
                 Py_DECREF(result);
@@ -318,6 +319,7 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
             }
             if (ptr[len] != '\0') {
                 PyErr_SetString(PyExc_SystemError, "buffer overflow");
+                Py_DECREF(result);
                 return NULL;
             }
             return result;