22
22
# include <stropts.h> // I_FLUSHBAND
23
23
#endif
24
24
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
+
25
29
/*[clinic input]
26
30
module fcntl
27
31
[clinic start generated code]*/
@@ -80,9 +84,10 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
80
84
return PyLong_FromLong (ret );
81
85
}
82
86
if (PyUnicode_Check (arg ) || PyObject_CheckBuffer (arg )) {
83
- #define FCNTL_BUFSZ 1024
84
87
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 ];
86
91
87
92
if (!PyArg_Parse (arg , "s*" , & view )) {
88
93
return NULL ;
@@ -95,7 +100,7 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
95
100
return NULL ;
96
101
}
97
102
memcpy (buf , view .buf , len );
98
- buf [ len ] = '\0' ;
103
+ memcpy ( buf + len , guard , GUARDSZ ) ;
99
104
PyBuffer_Release (& view );
100
105
101
106
do {
@@ -106,6 +111,10 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
106
111
if (ret < 0 ) {
107
112
return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
108
113
}
114
+ if (memcmp (buf + len , guard , GUARDSZ ) != 0 ) {
115
+ PyErr_SetString (PyExc_SystemError , "buffer overflow" );
116
+ return NULL ;
117
+ }
109
118
return PyBytes_FromStringAndSize (buf , len );
110
119
#undef FCNTL_BUFSZ
111
120
}
@@ -199,34 +208,37 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
199
208
if (PyUnicode_Check (arg ) || PyObject_CheckBuffer (arg )) {
200
209
Py_buffer view ;
201
210
#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 ];
203
213
if (mutate_arg && !PyBytes_Check (arg ) && !PyUnicode_Check (arg )) {
204
214
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 ;
221
221
}
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 ()));
222
227
if (ret < 0 ) {
223
228
if (!async_err ) {
224
229
PyErr_SetFromErrno (PyExc_OSError );
225
230
}
226
231
PyBuffer_Release (& view );
227
232
return NULL ;
228
233
}
234
+ if (ptr == buf ) {
235
+ memcpy (view .buf , buf , len );
236
+ }
229
237
PyBuffer_Release (& view );
238
+ if (ptr == buf && memcmp (buf + len , guard , GUARDSZ ) != 0 ) {
239
+ PyErr_SetString (PyExc_SystemError , "buffer overflow" );
240
+ return NULL ;
241
+ }
230
242
return PyLong_FromLong (ret );
231
243
}
232
244
if (!PyErr_ExceptionMatches (PyExc_BufferError )) {
@@ -246,7 +258,7 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
246
258
return NULL ;
247
259
}
248
260
memcpy (buf , view .buf , len );
249
- buf [ len ] = '\0' ;
261
+ memcpy ( buf + len , guard , GUARDSZ ) ;
250
262
PyBuffer_Release (& view );
251
263
252
264
do {
@@ -257,6 +269,10 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
257
269
if (ret < 0 ) {
258
270
return !async_err ? PyErr_SetFromErrno (PyExc_OSError ) : NULL ;
259
271
}
272
+ if (memcmp (buf + len , guard , GUARDSZ ) != 0 ) {
273
+ PyErr_SetString (PyExc_SystemError , "buffer overflow" );
274
+ return NULL ;
275
+ }
260
276
return PyBytes_FromStringAndSize (buf , len );
261
277
#undef IOCTL_BUFSZ
262
278
}
0 commit comments