aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2023-05-24 20:28:38 +0200
committerMartin Mares <mj@ucw.cz>2024-02-18 15:48:29 +0100
commitd1f3b5cf8f13370fd21583b91cf406ad789530e6 (patch)
tree6d6e23eec4098f4aaf4ca2b04f8376b2a20bdc87
parent899a7ac5d34e25a62ac231333250ec887cbc8fae (diff)
downloadpciutils-d1f3b5cf8f13370fd21583b91cf406ad789530e6.tar.gz
windows: Move win32_call_func_with_tcb_privilege() from i386-io-windows.h to win32-helpers.c
-rw-r--r--lib/i386-io-windows.h191
-rw-r--r--lib/win32-helpers.c189
-rw-r--r--lib/win32-helpers.h1
3 files changed, 191 insertions, 190 deletions
diff --git a/lib/i386-io-windows.h b/lib/i386-io-windows.h
index eff1901..d2da452 100644
--- a/lib/i386-io-windows.h
+++ b/lib/i386-io-windows.h
@@ -70,11 +70,6 @@ __readeflags(void)
/* Read IOPL of the current process, IOPL is stored in eflag bits [13:12]. */
#define read_iopl() ((__readeflags() >> 12) & 0x3)
-/* Unfortunately some toolchains do not provide this constant. */
-#ifndef SE_IMPERSONATE_NAME
-#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege")
-#endif
-
/*
* Unfortunately NtSetInformationProcess() function, ProcessUserModeIOPL
* constant and all other helpers for its usage are not specified in any
@@ -101,190 +96,6 @@ typedef NTSTATUS (NTAPI *NtSetInformationProcessProt)(HANDLE ProcessHandle, PROC
typedef ULONG (NTAPI *RtlNtStatusToDosErrorProt)(NTSTATUS Status);
/*
- * Call supplied function Func with its Arg and if it fails with
- * ERROR_PRIVILEGE_NOT_HELD then try to enable Tcb privilege and
- * call Func with its Arg again.
- */
-static BOOL
-CallFuncWithTcbPrivilege(BOOL (*Func)(LPVOID), LPVOID Arg)
-{
- LUID luid_tcb_privilege;
- LUID luid_impersonate_privilege;
-
- HANDLE revert_token_tcb_privilege;
- BOOL revert_only_tcb_privilege;
-
- HANDLE revert_token_impersonate_privilege;
- BOOL revert_only_impersonate_privilege;
-
- BOOL impersonate_privilege_enabled;
-
- BOOL revert_to_old_token;
- HANDLE old_token;
-
- HANDLE lsass_process;
- HANDLE lsass_token;
-
- BOOL ret;
-
- impersonate_privilege_enabled = FALSE;
- revert_to_old_token = FALSE;
- lsass_token = NULL;
- old_token = NULL;
-
- /* Call supplied function. */
- ret = Func(Arg);
- if (ret || GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
- goto ret;
-
- /*
- * If function call failed with ERROR_PRIVILEGE_NOT_HELD
- * error then it means that the current thread token does not have
- * Tcb privilege enabled. Try to enable it.
- */
-
- if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &luid_tcb_privilege))
- goto err_privilege_not_held;
-
- /*
- * If the current thread has already Tcb privilege enabled then there
- * is some additional unhanded restriction.
- */
- if (win32_have_privilege(luid_tcb_privilege))
- goto err_privilege_not_held;
-
- /* Try to enable Tcb privilege and try function call again. */
- if (win32_enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
- {
- ret = Func(Arg);
- win32_revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
- goto ret;
- }
-
- /*
- * If enabling of Tcb privilege failed then it means that current thread
- * does not have this privilege. But current process may have it. So try it
- * again with primary process access token.
- */
-
- /*
- * If system supports Impersonate privilege (Windows 2000 SP4 or higher) then
- * all future actions in this function require this Impersonate privilege.
- * So try to enable it in case it is currently disabled.
- */
- if (LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME, &luid_impersonate_privilege) &&
- !win32_have_privilege(luid_impersonate_privilege))
- {
- /*
- * If current thread does not have Impersonate privilege enabled
- * then first try to enable it just for the current thread. If
- * it is not possible to enable it just for the current thread
- * then try it to enable globally for whole process (which
- * affects all process threads). Both actions will be reverted
- * at the end of this function.
- */
- if (win32_enable_privilege(luid_impersonate_privilege, &revert_token_impersonate_privilege, &revert_only_impersonate_privilege))
- {
- impersonate_privilege_enabled = TRUE;
- }
- else if (win32_enable_privilege(luid_impersonate_privilege, NULL, NULL))
- {
- impersonate_privilege_enabled = TRUE;
- revert_token_impersonate_privilege = NULL;
- revert_only_impersonate_privilege = TRUE;
- }
- else
- {
- goto err_privilege_not_held;
- }
-
- /*
- * Now when Impersonate privilege is enabled, try to enable Tcb
- * privilege again. Enabling other privileges for the current
- * thread requires Impersonate privilege, so enabling Tcb again
- * could now pass.
- */
- if (win32_enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
- {
- ret = Func(Arg);
- win32_revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
- goto ret;
- }
- }
-
- /*
- * If enabling Tcb privilege failed then it means that the current
- * thread access token does not have this privilege or does not
- * have permission to adjust privileges.
- *
- * Try to use more privileged token from Local Security Authority
- * Subsystem Service process (lsass.exe) which has Tcb privilege.
- * Retrieving this more privileged token is possible for local
- * administrators (unless it was disabled by local administrators).
- */
-
- lsass_process = win32_find_and_open_process_for_query("lsass.exe");
- if (!lsass_process)
- goto err_privilege_not_held;
-
- /*
- * Open primary lsass.exe process access token with query and duplicate
- * rights. Just these two rights are required for impersonating other
- * primary process token (impersonate right is really not required!).
- */
- lsass_token = win32_open_process_token_with_rights(lsass_process, TOKEN_QUERY | TOKEN_DUPLICATE);
-
- CloseHandle(lsass_process);
-
- if (!lsass_token)
- goto err_privilege_not_held;
-
- /*
- * After successful open of the primary lsass.exe process access token,
- * assign its copy for the current thread.
- */
- if (!win32_change_token(lsass_token, &old_token))
- goto err_privilege_not_held;
-
- revert_to_old_token = TRUE;
-
- ret = Func(Arg);
- if (ret || GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
- goto ret;
-
- /*
- * Now current thread is not using primary process token anymore
- * but is using custom access token. There is no need to revert
- * enabled Tcb privilege as the whole custom access token would
- * be reverted. So there is no need to setup revert method for
- * enabling privilege.
- */
- if (win32_have_privilege(luid_tcb_privilege) ||
- !win32_enable_privilege(luid_tcb_privilege, NULL, NULL))
- goto err_privilege_not_held;
-
- ret = Func(Arg);
- goto ret;
-
-err_privilege_not_held:
- SetLastError(ERROR_PRIVILEGE_NOT_HELD);
- ret = FALSE;
- goto ret;
-
-ret:
- if (revert_to_old_token)
- win32_revert_to_token(old_token);
-
- if (impersonate_privilege_enabled)
- win32_revert_privilege(luid_impersonate_privilege, revert_token_impersonate_privilege, revert_only_impersonate_privilege);
-
- if (lsass_token)
- CloseHandle(lsass_token);
-
- return ret;
-}
-
-/*
* ProcessUserModeIOPL is syscall for NT kernel to change x86 IOPL
* of the current running process to 3.
*
@@ -365,7 +176,7 @@ SetProcessUserModeIOPL(VOID)
Arg[1] = (LPVOID)GetProcAddress(ntdll, "RtlNtStatusToDosError");
/* Call ProcessUserModeIOPL with Tcb privilege. */
- ret = CallFuncWithTcbPrivilege(SetProcessUserModeIOPLFunc, (LPVOID)&Arg);
+ ret = win32_call_func_with_tcb_privilege(SetProcessUserModeIOPLFunc, (LPVOID)&Arg);
FreeLibrary(ntdll);
diff --git a/lib/win32-helpers.c b/lib/win32-helpers.c
index 29ce5d8..bb3d8a0 100644
--- a/lib/win32-helpers.c
+++ b/lib/win32-helpers.c
@@ -19,6 +19,11 @@
#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
#endif
+/* Unfortunately some toolchains do not provide this constant. */
+#ifndef SE_IMPERSONATE_NAME
+#define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege")
+#endif
+
/*
* These psapi functions are available in kernel32.dll library with K32 prefix
* on Windows 7 and higher systems. On older Windows systems these functions are
@@ -981,3 +986,187 @@ win32_open_process_token_with_rights(HANDLE process, DWORD rights)
*/
return NULL;
}
+
+/*
+ * Call supplied function with its argument and if it fails with
+ * ERROR_PRIVILEGE_NOT_HELD then try to enable Tcb privilege and
+ * call function with its argument again.
+ */
+BOOL
+win32_call_func_with_tcb_privilege(BOOL (*function)(LPVOID), LPVOID argument)
+{
+ LUID luid_tcb_privilege;
+ LUID luid_impersonate_privilege;
+
+ HANDLE revert_token_tcb_privilege;
+ BOOL revert_only_tcb_privilege;
+
+ HANDLE revert_token_impersonate_privilege;
+ BOOL revert_only_impersonate_privilege;
+
+ BOOL impersonate_privilege_enabled;
+
+ BOOL revert_to_old_token;
+ HANDLE old_token;
+
+ HANDLE lsass_process;
+ HANDLE lsass_token;
+
+ BOOL ret;
+
+ impersonate_privilege_enabled = FALSE;
+ revert_to_old_token = FALSE;
+ lsass_token = NULL;
+ old_token = NULL;
+
+ /* Call supplied function. */
+ ret = function(argument);
+ if (ret || GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
+ goto ret;
+
+ /*
+ * If function call failed with ERROR_PRIVILEGE_NOT_HELD
+ * error then it means that the current thread token does not have
+ * Tcb privilege enabled. Try to enable it.
+ */
+
+ if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &luid_tcb_privilege))
+ goto err_privilege_not_held;
+
+ /*
+ * If the current thread has already Tcb privilege enabled then there
+ * is some additional unhanded restriction.
+ */
+ if (win32_have_privilege(luid_tcb_privilege))
+ goto err_privilege_not_held;
+
+ /* Try to enable Tcb privilege and try function call again. */
+ if (win32_enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
+ {
+ ret = function(argument);
+ win32_revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
+ goto ret;
+ }
+
+ /*
+ * If enabling of Tcb privilege failed then it means that current thread
+ * does not have this privilege. But current process may have it. So try it
+ * again with primary process access token.
+ */
+
+ /*
+ * If system supports Impersonate privilege (Windows 2000 SP4 or higher) then
+ * all future actions in this function require this Impersonate privilege.
+ * So try to enable it in case it is currently disabled.
+ */
+ if (LookupPrivilegeValue(NULL, SE_IMPERSONATE_NAME, &luid_impersonate_privilege) &&
+ !win32_have_privilege(luid_impersonate_privilege))
+ {
+ /*
+ * If current thread does not have Impersonate privilege enabled
+ * then first try to enable it just for the current thread. If
+ * it is not possible to enable it just for the current thread
+ * then try it to enable globally for whole process (which
+ * affects all process threads). Both actions will be reverted
+ * at the end of this function.
+ */
+ if (win32_enable_privilege(luid_impersonate_privilege, &revert_token_impersonate_privilege, &revert_only_impersonate_privilege))
+ {
+ impersonate_privilege_enabled = TRUE;
+ }
+ else if (win32_enable_privilege(luid_impersonate_privilege, NULL, NULL))
+ {
+ impersonate_privilege_enabled = TRUE;
+ revert_token_impersonate_privilege = NULL;
+ revert_only_impersonate_privilege = TRUE;
+ }
+ else
+ {
+ goto err_privilege_not_held;
+ }
+
+ /*
+ * Now when Impersonate privilege is enabled, try to enable Tcb
+ * privilege again. Enabling other privileges for the current
+ * thread requires Impersonate privilege, so enabling Tcb again
+ * could now pass.
+ */
+ if (win32_enable_privilege(luid_tcb_privilege, &revert_token_tcb_privilege, &revert_only_tcb_privilege))
+ {
+ ret = function(argument);
+ win32_revert_privilege(luid_tcb_privilege, revert_token_tcb_privilege, revert_only_tcb_privilege);
+ goto ret;
+ }
+ }
+
+ /*
+ * If enabling Tcb privilege failed then it means that the current
+ * thread access token does not have this privilege or does not
+ * have permission to adjust privileges.
+ *
+ * Try to use more privileged token from Local Security Authority
+ * Subsystem Service process (lsass.exe) which has Tcb privilege.
+ * Retrieving this more privileged token is possible for local
+ * administrators (unless it was disabled by local administrators).
+ */
+
+ lsass_process = win32_find_and_open_process_for_query("lsass.exe");
+ if (!lsass_process)
+ goto err_privilege_not_held;
+
+ /*
+ * Open primary lsass.exe process access token with query and duplicate
+ * rights. Just these two rights are required for impersonating other
+ * primary process token (impersonate right is really not required!).
+ */
+ lsass_token = win32_open_process_token_with_rights(lsass_process, TOKEN_QUERY | TOKEN_DUPLICATE);
+
+ CloseHandle(lsass_process);
+
+ if (!lsass_token)
+ goto err_privilege_not_held;
+
+ /*
+ * After successful open of the primary lsass.exe process access token,
+ * assign its copy for the current thread.
+ */
+ if (!win32_change_token(lsass_token, &old_token))
+ goto err_privilege_not_held;
+
+ revert_to_old_token = TRUE;
+
+ ret = function(argument);
+ if (ret || GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
+ goto ret;
+
+ /*
+ * Now current thread is not using primary process token anymore
+ * but is using custom access token. There is no need to revert
+ * enabled Tcb privilege as the whole custom access token would
+ * be reverted. So there is no need to setup revert method for
+ * enabling privilege.
+ */
+ if (win32_have_privilege(luid_tcb_privilege) ||
+ !win32_enable_privilege(luid_tcb_privilege, NULL, NULL))
+ goto err_privilege_not_held;
+
+ ret = function(argument);
+ goto ret;
+
+err_privilege_not_held:
+ SetLastError(ERROR_PRIVILEGE_NOT_HELD);
+ ret = FALSE;
+ goto ret;
+
+ret:
+ if (revert_to_old_token)
+ win32_revert_to_token(old_token);
+
+ if (impersonate_privilege_enabled)
+ win32_revert_privilege(luid_impersonate_privilege, revert_token_impersonate_privilege, revert_only_impersonate_privilege);
+
+ if (lsass_token)
+ CloseHandle(lsass_token);
+
+ return ret;
+}
diff --git a/lib/win32-helpers.h b/lib/win32-helpers.h
index e5f4445..c415439 100644
--- a/lib/win32-helpers.h
+++ b/lib/win32-helpers.h
@@ -10,3 +10,4 @@ BOOL win32_change_token(HANDLE new_token, HANDLE *old_token);
VOID win32_revert_to_token(HANDLE token);
HANDLE win32_find_and_open_process_for_query(LPCSTR exe_file);
HANDLE win32_open_process_token_with_rights(HANDLE process, DWORD rights);
+BOOL win32_call_func_with_tcb_privilege(BOOL (*function)(LPVOID), LPVOID argument);