2222# include <stropts.h> // I_FLUSHBAND
2323#endif
2424
25+ #define GUARDSZ 8
26+ // NUL followed by random bytes.
27+ static const char guard [GUARDSZ ] = "\x00\xfa\x69\xc4\x67\xa3\x6c\x58" ;
28+
2529/*[clinic input]
2630module fcntl
2731[clinic start generated code]*/
@@ -80,9 +84,10 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
8084 return PyLong_FromLong (ret );
8185 }
8286 if (PyUnicode_Check (arg ) || PyObject_CheckBuffer (arg )) {
83- #define FCNTL_BUFSZ 1024
8487 Py_buffer view ;
85- char buf [FCNTL_BUFSZ + 1 ]; /* argument plus NUL byte */
88+ #define FCNTL_BUFSZ 1024
89+ /* argument plus NUL byte plus guard to detect a buffer overflow */
90+ char buf [FCNTL_BUFSZ + GUARDSZ ];
8691
8792 if (!PyArg_Parse (arg , "s*" , & view )) {
8893 return NULL ;
@@ -95,7 +100,7 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
95100 return NULL ;
96101 }
97102 memcpy (buf , view .buf , len );
98- buf [ len ] = '\0' ;
103+ memcpy ( buf + len , guard , GUARDSZ ) ;
99104 PyBuffer_Release (& view );
100105
101106 do {
@@ -106,6 +111,10 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
106111 if (ret < 0 ) {
107112 return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
108113 }
114+ if (memcmp (buf + len , guard , GUARDSZ ) != 0 ) {
115+ PyErr_SetString (PyExc_SystemError , "buffer overflow" );
116+ return NULL ;
117+ }
109118 return PyBytes_FromStringAndSize (buf , len );
110119#undef FCNTL_BUFSZ
111120 }
@@ -199,34 +208,37 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
199208 if (PyUnicode_Check (arg ) || PyObject_CheckBuffer (arg )) {
200209 Py_buffer view ;
201210#define IOCTL_BUFSZ 1024
202- char buf [IOCTL_BUFSZ + 1 ]; /* argument plus NUL byte */
211+ /* argument plus NUL byte plus guard to detect a buffer overflow */
212+ char buf [IOCTL_BUFSZ + GUARDSZ ];
203213 if (mutate_arg && !PyBytes_Check (arg ) && !PyUnicode_Check (arg )) {
204214 if (PyObject_GetBuffer (arg , & view , PyBUF_WRITABLE ) == 0 ) {
205- if (view .len <= IOCTL_BUFSZ ) {
206- memcpy (buf , view .buf , view .len );
207- buf [view .len ] = '\0' ;
208- do {
209- Py_BEGIN_ALLOW_THREADS
210- ret = ioctl (fd , code , buf );
211- Py_END_ALLOW_THREADS
212- } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
213- memcpy (view .buf , buf , view .len );
214- }
215- else {
216- do {
217- Py_BEGIN_ALLOW_THREADS
218- ret = ioctl (fd , code , view .buf );
219- Py_END_ALLOW_THREADS
220- } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
215+ Py_ssize_t len = view .len ;
216+ void * ptr = view .buf ;
217+ if (len <= IOCTL_BUFSZ ) {
218+ memcpy (buf , ptr , len );
219+ memcpy (buf + len , guard , GUARDSZ );
220+ ptr = buf ;
221221 }
222+ do {
223+ Py_BEGIN_ALLOW_THREADS
224+ ret = ioctl (fd , code , ptr );
225+ Py_END_ALLOW_THREADS
226+ } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals ()));
222227 if (ret < 0 ) {
223228 if (!async_err ) {
224229 PyErr_SetFromErrno (PyExc_OSError );
225230 }
226231 PyBuffer_Release (& view );
227232 return NULL ;
228233 }
234+ if (ptr == buf ) {
235+ memcpy (view .buf , buf , len );
236+ }
229237 PyBuffer_Release (& view );
238+ if (ptr == buf && memcmp (buf + len , guard , GUARDSZ ) != 0 ) {
239+ PyErr_SetString (PyExc_SystemError , "buffer overflow" );
240+ return NULL ;
241+ }
230242 return PyLong_FromLong (ret );
231243 }
232244 if (!PyErr_ExceptionMatches (PyExc_BufferError )) {
@@ -246,7 +258,7 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
246258 return NULL ;
247259 }
248260 memcpy (buf , view .buf , len );
249- buf [ len ] = '\0' ;
261+ memcpy ( buf + len , guard , GUARDSZ ) ;
250262 PyBuffer_Release (& view );
251263
252264 do {
@@ -257,6 +269,10 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
257269 if (ret < 0 ) {
258270 return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
259271 }
272+ if (memcmp (buf + len , guard , GUARDSZ ) != 0 ) {
273+ PyErr_SetString (PyExc_SystemError , "buffer overflow" );
274+ return NULL ;
275+ }
260276 return PyBytes_FromStringAndSize (buf , len );
261277#undef IOCTL_BUFSZ
262278 }
0 commit comments