From 25afdd7fbb60a811a085cc56fc405c13dbf2f942 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 8 May 2024 22:00:06 +0100 Subject: [PATCH 1/3] gh-118773: Use well-known constants instead of aliases for ACLs. --- ...-05-08-21-59-38.gh-issue-118773.7dFRJY.rst | 2 + Modules/posixmodule.c | 46 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst diff --git a/Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst b/Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst new file mode 100644 index 00000000000000..bfec178f6318a7 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2024-05-08-21-59-38.gh-issue-118773.7dFRJY.rst @@ -0,0 +1,2 @@ +Fixes creation of ACLs in :func:`os.mkdir` on Windows to work correctly on +non-English machines. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 9f4be98b35186e..ebd943438b52df 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5587,9 +5587,18 @@ struct _Py_SECURITY_ATTRIBUTE_DATA { PACL acl; SECURITY_DESCRIPTOR sd; EXPLICIT_ACCESS_W ea[4]; - char sid[64]; + BYTE sidAdmins[SECURITY_MAX_SID_SIZE]; + BYTE sidSystem[SECURITY_MAX_SID_SIZE]; + BYTE sidCreator[SECURITY_MAX_SID_SIZE]; }; +static int +_initializeSid(BYTE *sid, WELL_KNOWN_SID_TYPE sidType) +{ + DWORD cbSid = SECURITY_MAX_SID_SIZE; + return CreateWellKnownSid(sidType, NULL, sid, &cbSid) ? 1 : 0; +} + static int initializeDefaultSecurityAttributes( PSECURITY_ATTRIBUTES *securityAttributes, @@ -5612,44 +5621,37 @@ initializeMkdir700SecurityAttributes( *securityAttributes = NULL; memset(data, 0, sizeof(*data)); + SID_IDENTIFIER_AUTHORITY SidNtAuthority = SECURITY_NT_AUTHORITY; if (!InitializeSecurityDescriptor(&data->sd, SECURITY_DESCRIPTOR_REVISION) - || !SetSecurityDescriptorGroup(&data->sd, NULL, TRUE)) { + || !SetSecurityDescriptorGroup(&data->sd, NULL, TRUE) + || !_initializeSid(data->sidAdmins, WinBuiltinAdministratorsSid) + || !_initializeSid(data->sidSystem, WinLocalSystemSid) + || !_initializeSid(data->sidCreator, WinCreatorOwnerRightsSid) + ) { return GetLastError(); } - int use_alias = 0; - DWORD cbSid = sizeof(data->sid); - if (!CreateWellKnownSid(WinCreatorOwnerRightsSid, NULL, (PSID)data->sid, &cbSid)) { - use_alias = 1; - } - data->securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); data->ea[0].grfAccessPermissions = GENERIC_ALL; data->ea[0].grfAccessMode = SET_ACCESS; data->ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - if (use_alias) { - data->ea[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME; - data->ea[0].Trustee.TrusteeType = TRUSTEE_IS_ALIAS; - data->ea[0].Trustee.ptstrName = L"CURRENT_USER"; - } else { - data->ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; - data->ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - data->ea[0].Trustee.ptstrName = (LPWCH)(SID*)data->sid; - } + data->ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; + data->ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + data->ea[0].Trustee.ptstrName = (LPWCH)data->sidSystem; data->ea[1].grfAccessPermissions = GENERIC_ALL; data->ea[1].grfAccessMode = SET_ACCESS; data->ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - data->ea[1].Trustee.TrusteeForm = TRUSTEE_IS_NAME; - data->ea[1].Trustee.TrusteeType = TRUSTEE_IS_ALIAS; - data->ea[1].Trustee.ptstrName = L"SYSTEM"; + data->ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + data->ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + data->ea[1].Trustee.ptstrName = (LPWCH)data->sidAdmins; data->ea[2].grfAccessPermissions = GENERIC_ALL; data->ea[2].grfAccessMode = SET_ACCESS; data->ea[2].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - data->ea[2].Trustee.TrusteeForm = TRUSTEE_IS_NAME; + data->ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; data->ea[2].Trustee.TrusteeType = TRUSTEE_IS_ALIAS; - data->ea[2].Trustee.ptstrName = L"ADMINISTRATORS"; + data->ea[2].Trustee.ptstrName = (LPWCH)data->sidCreator; int r = SetEntriesInAclW(3, data->ea, NULL, &data->acl); if (r) { From 99ae180ada8f2a790a7270bb84305db261b7b9f2 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 9 May 2024 12:24:53 +0100 Subject: [PATCH 2/3] Switch to SDDL string --- Modules/posixmodule.c | 175 +++++------------------------------------- 1 file changed, 19 insertions(+), 156 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ebd943438b52df..cece077543b918 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5541,148 +5541,6 @@ os__path_normpath_impl(PyObject *module, PyObject *path) return result; } -#ifdef MS_WINDOWS - -/* We centralise SECURITY_ATTRIBUTE initialization based around -templates that will probably mostly match common POSIX mode settings. -The _Py_SECURITY_ATTRIBUTE_DATA structure contains temporary data, as -a constructed SECURITY_ATTRIBUTE structure typically refers to memory -that has to be alive while it's being used. - -Typical use will look like: - SECURITY_ATTRIBUTES *pSecAttr = NULL; - struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData; - int error, error2; - - Py_BEGIN_ALLOW_THREADS - switch (mode) { - case 0x1C0: // 0o700 - error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData); - break; - ... - default: - error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData); - break; - } - - if (!error) { - // do operation, passing pSecAttr - } - - // Unconditionally clear secAttrData. - error2 = clearSecurityAttributes(&pSecAttr, &secAttrData); - if (!error) { - error = error2; - } - Py_END_ALLOW_THREADS - - if (error) { - PyErr_SetFromWindowsErr(error); - return NULL; - } -*/ - -struct _Py_SECURITY_ATTRIBUTE_DATA { - SECURITY_ATTRIBUTES securityAttributes; - PACL acl; - SECURITY_DESCRIPTOR sd; - EXPLICIT_ACCESS_W ea[4]; - BYTE sidAdmins[SECURITY_MAX_SID_SIZE]; - BYTE sidSystem[SECURITY_MAX_SID_SIZE]; - BYTE sidCreator[SECURITY_MAX_SID_SIZE]; -}; - -static int -_initializeSid(BYTE *sid, WELL_KNOWN_SID_TYPE sidType) -{ - DWORD cbSid = SECURITY_MAX_SID_SIZE; - return CreateWellKnownSid(sidType, NULL, sid, &cbSid) ? 1 : 0; -} - -static int -initializeDefaultSecurityAttributes( - PSECURITY_ATTRIBUTES *securityAttributes, - struct _Py_SECURITY_ATTRIBUTE_DATA *data -) { - assert(securityAttributes); - assert(data); - *securityAttributes = NULL; - memset(data, 0, sizeof(*data)); - return 0; -} - -static int -initializeMkdir700SecurityAttributes( - PSECURITY_ATTRIBUTES *securityAttributes, - struct _Py_SECURITY_ATTRIBUTE_DATA *data -) { - assert(securityAttributes); - assert(data); - *securityAttributes = NULL; - memset(data, 0, sizeof(*data)); - - SID_IDENTIFIER_AUTHORITY SidNtAuthority = SECURITY_NT_AUTHORITY; - if (!InitializeSecurityDescriptor(&data->sd, SECURITY_DESCRIPTOR_REVISION) - || !SetSecurityDescriptorGroup(&data->sd, NULL, TRUE) - || !_initializeSid(data->sidAdmins, WinBuiltinAdministratorsSid) - || !_initializeSid(data->sidSystem, WinLocalSystemSid) - || !_initializeSid(data->sidCreator, WinCreatorOwnerRightsSid) - ) { - return GetLastError(); - } - - data->securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - data->ea[0].grfAccessPermissions = GENERIC_ALL; - data->ea[0].grfAccessMode = SET_ACCESS; - data->ea[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - data->ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; - data->ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - data->ea[0].Trustee.ptstrName = (LPWCH)data->sidSystem; - - data->ea[1].grfAccessPermissions = GENERIC_ALL; - data->ea[1].grfAccessMode = SET_ACCESS; - data->ea[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - data->ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; - data->ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; - data->ea[1].Trustee.ptstrName = (LPWCH)data->sidAdmins; - - data->ea[2].grfAccessPermissions = GENERIC_ALL; - data->ea[2].grfAccessMode = SET_ACCESS; - data->ea[2].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT; - data->ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID; - data->ea[2].Trustee.TrusteeType = TRUSTEE_IS_ALIAS; - data->ea[2].Trustee.ptstrName = (LPWCH)data->sidCreator; - - int r = SetEntriesInAclW(3, data->ea, NULL, &data->acl); - if (r) { - return r; - } - if (!SetSecurityDescriptorDacl(&data->sd, TRUE, data->acl, FALSE)) { - return GetLastError(); - } - data->securityAttributes.lpSecurityDescriptor = &data->sd; - *securityAttributes = &data->securityAttributes; - return 0; -} - -static int -clearSecurityAttributes( - PSECURITY_ATTRIBUTES *securityAttributes, - struct _Py_SECURITY_ATTRIBUTE_DATA *data -) { - assert(securityAttributes); - assert(data); - *securityAttributes = NULL; - if (data->acl) { - if (LocalFree((void *)data->acl)) { - return GetLastError(); - } - } - return 0; -} - -#endif - /*[clinic input] os.mkdir @@ -5715,8 +5573,8 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) #ifdef MS_WINDOWS int error = 0; int pathError = 0; + SECURITY_ATTRIBUTES secAttr = { sizeof(secAttr) }; SECURITY_ATTRIBUTES *pSecAttr = NULL; - struct _Py_SECURITY_ATTRIBUTE_DATA secAttrData; #endif #ifdef HAVE_MKDIRAT int mkdirat_unavailable = 0; @@ -5729,26 +5587,31 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - switch (mode) { - case 0x1C0: // 0o700 - error = initializeMkdir700SecurityAttributes(&pSecAttr, &secAttrData); - break; - default: - error = initializeDefaultSecurityAttributes(&pSecAttr, &secAttrData); - break; + if (mode == 0700 /* 0o700 */) { + ULONG sdSize; + pSecAttr = &secAttr; + // Set a discreationary ACL (D) that is protected (P) and includes + // inheritable (OICI) entries that allow (A) full control (FA) to + // SYSTEM (SY), Administrators (BA), and the owner (OW). + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( + L"D:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)", + SDDL_REVISION_1, + &secAttr.lpSecurityDescriptor, + &sdSize + )) { + error = GetLastError(); + } } if (!error) { result = CreateDirectoryW(path->wide, pSecAttr); - error = clearSecurityAttributes(&pSecAttr, &secAttrData); - } else { - // Ignore error from "clear" - we have a more interesting one already - clearSecurityAttributes(&pSecAttr, &secAttrData); + if (LocalFree(secAttr.lpSecurityDescriptor)) { + error = GetLastError(); + } } Py_END_ALLOW_THREADS if (error) { - PyErr_SetFromWindowsErr(error); - return NULL; + return PyErr_SetFromWindowsErr(error); } if (!result) { return path_error(path); From 9216aa324e627548f69f5a0c6925822febbe5ab6 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 9 May 2024 16:35:49 +0100 Subject: [PATCH 3/3] Review feedback --- Modules/posixmodule.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index cece077543b918..5fe6036b3817e4 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -5594,7 +5594,7 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) // inheritable (OICI) entries that allow (A) full control (FA) to // SYSTEM (SY), Administrators (BA), and the owner (OW). if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( - L"D:PAI(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)", + L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)", SDDL_REVISION_1, &secAttr.lpSecurityDescriptor, &sdSize @@ -5604,7 +5604,10 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd) } if (!error) { result = CreateDirectoryW(path->wide, pSecAttr); - if (LocalFree(secAttr.lpSecurityDescriptor)) { + if (secAttr.lpSecurityDescriptor && + // uncommonly, LocalFree returns non-zero on error, but still uses + // GetLastError() to see what the error code is + LocalFree(secAttr.lpSecurityDescriptor)) { error = GetLastError(); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy