Skip to content

gh-95380: Removing the 1024 bytes limit in the fcntl_fcntl_impl and fcntl_ioctl_impl functions. #95439

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove max path size limit of 1024 for :func:`fcntl.ioctl` function.
5 changes: 2 additions & 3 deletions Modules/clinic/fcntlmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 24 additions & 44 deletions Modules/fcntlmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ the behavior is as if a string had been passed.
If the argument is an immutable buffer (most likely a string) then a copy
of the buffer is passed to the operating system and the return value is a
string of the same length containing whatever the operating system put in
the buffer. The length of the arg buffer in this case is not allowed to
exceed 1024 bytes.
the buffer.

If the arg given is an integer or if none is specified, the result value is
an integer corresponding to the return value of the ioctl call in the C
Expand All @@ -146,9 +145,8 @@ code.
static PyObject *
fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,
PyObject *ob_arg, int mutate_arg)
/*[clinic end generated code: output=7f7f5840c65991be input=967b4a4cbeceb0a8]*/
/*[clinic end generated code: output=7f7f5840c65991be input=6b70e7e5a8df40fa]*/
{
#define IOCTL_BUFSZ 1024
/* We use the unsigned non-checked 'I' format for the 'code' parameter
because the system expects it to be a 32bit bit field value
regardless of it being passed as an int or unsigned long on
Expand All @@ -164,7 +162,6 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,
Py_buffer pstr;
char *str;
Py_ssize_t len;
char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */

if (PySys_Audit("fcntl.ioctl", "iIO", fd, code,
ob_arg ? ob_arg : Py_None) < 0) {
Expand All @@ -173,79 +170,62 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned int code,

if (ob_arg != NULL) {
if (PyArg_Parse(ob_arg, "w*:ioctl", &pstr)) {
char *arg;
str = pstr.buf;
len = pstr.len;

if (mutate_arg) {
if (len <= IOCTL_BUFSZ) {
memcpy(buf, str, len);
buf[len] = '\0';
arg = buf;
}
else {
arg = str;
}
}
else {
if (len > IOCTL_BUFSZ) {
PyBuffer_Release(&pstr);
PyErr_SetString(PyExc_ValueError,
"ioctl string arg too long");
return NULL;
}
else {
memcpy(buf, str, len);
buf[len] = '\0';
arg = buf;
}
}
if (buf == arg) {
Py_BEGIN_ALLOW_THREADS /* think array.resize() */
ret = ioctl(fd, code, arg);
Py_END_ALLOW_THREADS
}
else {
ret = ioctl(fd, code, arg);
PyObject *o = PyBytes_FromStringAndSize(NULL, len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not be decref/freed in some code path(s) below ?

if (o == NULL) {
return NULL;
}
if (mutate_arg && (len <= IOCTL_BUFSZ)) {
char *buf = PyBytes_AS_STRING(o);

memcpy(buf, str, len);

Py_BEGIN_ALLOW_THREADS /* think array.resize() */
ret = ioctl(fd, code, buf);
Py_END_ALLOW_THREADS

if (mutate_arg) {
memcpy(str, buf, len);
}
PyBuffer_Release(&pstr); /* No further access to str below this point */
if (ret < 0) {
Py_DECREF(o);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
if (mutate_arg) {
Py_DECREF(o);
return PyLong_FromLong(ret);
}
else {
return PyBytes_FromStringAndSize(buf, len);
return o;
}
}

PyErr_Clear();
if (PyArg_Parse(ob_arg, "s*:ioctl", &pstr)) {
str = pstr.buf;
len = pstr.len;
if (len > IOCTL_BUFSZ) {
PyBuffer_Release(&pstr);
PyErr_SetString(PyExc_ValueError,
"ioctl string arg too long");

PyObject *o = PyBytes_FromStringAndSize(NULL, len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not decref in the failure/error code path(s)..

also on line 248 : could not you directly returns it instead of re-creating another object ?

if (o == NULL) {
return NULL;
}
char *buf = PyBytes_AS_STRING(o);

memcpy(buf, str, len);
buf[len] = '\0';
Py_BEGIN_ALLOW_THREADS
ret = ioctl(fd, code, buf);
Py_END_ALLOW_THREADS
if (ret < 0) {
Py_DECREF(o);
PyBuffer_Release(&pstr);
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
PyBuffer_Release(&pstr);
return PyBytes_FromStringAndSize(buf, len);
return o;
}

PyErr_Clear();
Expand Down