gh-144319: obtain SeLockMemoryPrivilege on Windows (#144928)

This commit is contained in:
Chris Eibl 2026-03-24 00:00:26 +01:00 committed by GitHub
parent e017971eb9
commit 306c556fdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 68 additions and 3 deletions

View file

@ -41,6 +41,10 @@
#include "pycore_jit.h" // _PyJIT_Fini()
#endif
#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
#include <Windows.h>
#endif
#include "opcode.h"
#include <locale.h> // setlocale()
@ -486,6 +490,41 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime,
return _PyStatus_OK();
}
#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
static PyStatus
get_huge_pages_privilege(void)
{
HANDLE hToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
return _PyStatus_ERR("failed to open process token");
}
TOKEN_PRIVILEGES tp;
if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid))
{
CloseHandle(hToken);
return _PyStatus_ERR("failed to lookup SeLockMemoryPrivilege for huge pages");
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// AdjustTokenPrivileges can return with nonzero status (i.e. success)
// but without having all privileges adjusted (ERROR_NOT_ALL_ASSIGNED).
BOOL status = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
DWORD error = GetLastError();
if (!status || (error != ERROR_SUCCESS))
{
CloseHandle(hToken);
return _PyStatus_ERR(
"SeLockMemoryPrivilege not held; "
"grant it via Local Security Policy or disable PYTHON_PYMALLOC_HUGEPAGES");
}
if (!CloseHandle(hToken))
{
return _PyStatus_ERR("failed to close process token handle");
}
return _PyStatus_OK();
}
#endif
static PyStatus
pycore_init_runtime(_PyRuntimeState *runtime,
@ -500,6 +539,15 @@ pycore_init_runtime(_PyRuntimeState *runtime,
return status;
}
#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
if (runtime->allocators.use_hugepages) {
status = get_huge_pages_privilege();
if (_PyStatus_EXCEPTION(status)) {
return status;
}
}
#endif
/* Py_Finalize leaves _Py_Finalizing set in order to help daemon
* threads behave a little more gracefully at interpreter shutdown.
* We clobber it here so the new interpreter can start with a clean