Skip to content

bpo-32818: Fix a subprocess crash in Windows compatiblity mode#5948

Closed
segevfiner wants to merge 2 commits into
python:mainfrom
segevfiner:bpo-32818-create-process-compatibility-crash
Closed

bpo-32818: Fix a subprocess crash in Windows compatiblity mode#5948
segevfiner wants to merge 2 commits into
python:mainfrom
segevfiner:bpo-32818-create-process-compatibility-crash

Conversation

@segevfiner
Copy link
Copy Markdown
Contributor

@segevfiner segevfiner commented Mar 1, 2018

The crash happens when STARTUPINFO.lpAttributeList is empty. (See https://bugs.python.org/msg313094).

https://bugs.python.org/issue32818

The crash happens when STARTUPINFO.lpAttributeList is empty.
Comment thread Modules/_winapi.c
inherit_handles,
creation_flags | EXTENDED_STARTUPINFO_PRESENT |
creation_flags |
(si.lpAttributeList ? EXTENDED_STARTUPINFO_PRESENT : 0) |
Copy link
Copy Markdown
Contributor

@eryksun eryksun Mar 1, 2018

Choose a reason for hiding this comment

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

It may be more resilient to also always allocate an attribute list, even if it's empty. That avoids any potential Windows bugs where a bad assumption is made based on the struct size and ignoring the creation flags. This could be done with the following changes in getattributelist:

value = PyObject_GetAttrString(obj, name);

if (!value) {
    PyErr_Clear();
    Py_INCREF(Py_None);
    value = Py_None;
} else if (value != Py_None && !PyMapping_Check(value)) {
    ret = -1;
    PyErr_Format(PyExc_TypeError, "%s must be a mapping or None", name);
    goto cleanup;
}

if (value != Py_None) {
    attribute_list->handle_list = gethandlelist(value, "handle_list",
        &handle_list_size);
    if (attribute_list->handle_list == NULL && PyErr_Occurred()) {
        ret = -1;
        goto cleanup;
    }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since this will always allocate the attribute list, it makes the change to the flags passed to CreateProcess redundant. I was contemplating a fix like this too. But I'm not sure which is the best or more robust fix for this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The simplest and most efficient solution is to omit the creation flag, as you implemented it. In Windows 10, the extended startup info creation flag gates further checks. If it's present in the creation flags, and the startup info is the right size, and the attribute list pointer isn't NULL, then CreateProcess calls BasepConvertWin32AttributeList to convert the attribute list to NT form. If the struct is the wrong size, it's handled as an invalid parameter.

That said, I'm more comfortable if the startup info is valid on its own. The docs don't explicitly say it's ok for lpAttributeList to be NULL, but I assumed it was. It's common for an optional parameter or field to be set to NULL when unused. If we omit the creation flag that indicates an extended startup info is present when we're actually using an extended startup info (as indicated by size, but then the flag is redundant), to me that seems like a nonsense hack. In that case I'd rather allocate an empty attribute list.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I don't know how to fix.

I would suggest that add a comment like this, since this patch may be removed in several years later.

/* fix a bug of Windows Compatiblity Mode, bpo-32818 */

@kumaraditya303
Copy link
Copy Markdown
Contributor

Closing as Windows 7 is not supported anymore and Python 3.9 is security fixes only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants