From c70bea7a314fa71c8ff44581079c6dd2d090ad63 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 24 Jun 2021 01:52:06 +0200 Subject: [PATCH] ipc: remove windows elevation Signed-off-by: Jason A. Donenfeld --- src/ipc-uapi-windows.h | 101 ++++++++--------------------------------- src/ipc-windows.h | 85 ++++++++-------------------------- 2 files changed, 36 insertions(+), 150 deletions(-) diff --git a/src/ipc-uapi-windows.h b/src/ipc-uapi-windows.h index 4d362d0..8ea4f75 100644 --- a/src/ipc-uapi-windows.h +++ b/src/ipc-uapi-windows.h @@ -14,102 +14,37 @@ static FILE *userspace_interface_file(const char *iface) { - char fname[MAX_PATH], error_message[1024 * 128] = { 0 }; - HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token, pipe_handle = INVALID_HANDLE_VALUE; - PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) }; - PSECURITY_DESCRIPTOR pipe_sd; - PSID pipe_sid; + char fname[MAX_PATH]; + HANDLE pipe_handle; SID expected_sid; - BOOL ret; + DWORD bytes = sizeof(expected_sid); + PSID pipe_sid; + PSECURITY_DESCRIPTOR pipe_sd; + bool equal; int fd; - DWORD last_error = ERROR_SUCCESS, bytes = sizeof(expected_sid); - TOKEN_PRIVILEGES privileges = { - .PrivilegeCount = 1, - .Privileges = {{ .Attributes = SE_PRIVILEGE_ENABLED }} - }; - if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid)) - goto err; if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes)) goto err; - process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (process_snapshot == INVALID_HANDLE_VALUE) - goto err; - for (ret = Process32First(process_snapshot, &entry); ret; last_error = GetLastError(), ret = Process32Next(process_snapshot, &entry)) { - if (strcasecmp(entry.szExeFile, "winlogon.exe")) - continue; - - RevertToSelf(); - if (!ImpersonateSelf(SecurityImpersonation)) - continue; - if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token)) - continue; - if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL)) { - last_error = GetLastError(); - CloseHandle(thread_token); - continue; - } - CloseHandle(thread_token); - - winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID); - if (!winlogon_process) - continue; - if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token)) - continue; - CloseHandle(winlogon_process); - if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token)) { - last_error = GetLastError(); - RevertToSelf(); - continue; - } - CloseHandle(winlogon_token); - if (!SetThreadToken(NULL, duplicated_token)) { - last_error = GetLastError(); - CloseHandle(duplicated_token); - continue; - } - CloseHandle(duplicated_token); - - snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\WireGuard\\%s", iface); - pipe_handle = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - last_error = GetLastError(); - if (pipe_handle == INVALID_HANDLE_VALUE) - continue; - last_error = GetSecurityInfo(pipe_handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pipe_sid, NULL, NULL, NULL, &pipe_sd); - if (last_error != ERROR_SUCCESS) { - CloseHandle(pipe_handle); - continue; - } - last_error = EqualSid(&expected_sid, pipe_sid) ? ERROR_SUCCESS : ERROR_ACCESS_DENIED; - LocalFree(pipe_sd); - if (last_error != ERROR_SUCCESS) { - CloseHandle(pipe_handle); - continue; - } - last_error = ERROR_SUCCESS; - break; - } - RevertToSelf(); - CloseHandle(process_snapshot); - - if (last_error != ERROR_SUCCESS || pipe_handle == INVALID_HANDLE_VALUE) + snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\WireGuard\\%s", iface); + pipe_handle = CreateFileA(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (pipe_handle == INVALID_HANDLE_VALUE) goto err; + if (GetSecurityInfo(pipe_handle, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pipe_sid, NULL, NULL, NULL, &pipe_sd) != ERROR_SUCCESS) + goto err_close; + equal = EqualSid(&expected_sid, pipe_sid); + LocalFree(pipe_sd); + if (!equal) + goto err_close; fd = _open_osfhandle((intptr_t)pipe_handle, _O_RDWR); if (fd == -1) { - last_error = GetLastError(); CloseHandle(pipe_handle); - goto err; + return NULL; } return _fdopen(fd, "r+"); - +err_close: + CloseHandle(pipe_handle); err: - if (last_error == ERROR_SUCCESS) - last_error = GetLastError(); - if (last_error == ERROR_SUCCESS) - last_error = ERROR_ACCESS_DENIED; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_message, sizeof(error_message) - 1, NULL); - fprintf(stderr, "Error: Unable to open IPC handle via SYSTEM impersonation: %ld: %s\n", last_error, error_message); errno = EACCES; return NULL; } diff --git a/src/ipc-windows.h b/src/ipc-windows.h index 2382847..9c72a62 100644 --- a/src/ipc-windows.h +++ b/src/ipc-windows.h @@ -311,66 +311,6 @@ skip:; return handle; } -static BOOL elevated_ioctl(HANDLE handle, DWORD code, void *in_buf, DWORD in_buf_len, void *out_buf, DWORD out_buf_len, DWORD *bytes_returned) -{ - HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token; - PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) }; - TOKEN_PRIVILEGES privileges = { - .PrivilegeCount = 1, - .Privileges = {{ .Attributes = SE_PRIVILEGE_ENABLED }} - }; - SID expected_sid; - DWORD bytes = sizeof(expected_sid); - BOOL ret; - - if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid)) - return FALSE; - if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes)) - return FALSE; - - process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (process_snapshot == INVALID_HANDLE_VALUE) - return FALSE; - for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry)) { - if (strcasecmp(entry.szExeFile, "winlogon.exe")) - continue; - - RevertToSelf(); - if (!ImpersonateSelf(SecurityImpersonation)) - continue; - if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token)) - continue; - if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL)) { - CloseHandle(thread_token); - continue; - } - CloseHandle(thread_token); - - winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, entry.th32ProcessID); - if (!winlogon_process) - continue; - if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token)) - continue; - CloseHandle(winlogon_process); - if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token)) { - RevertToSelf(); - continue; - } - CloseHandle(winlogon_token); - if (!SetThreadToken(NULL, duplicated_token)) { - CloseHandle(duplicated_token); - continue; - } - CloseHandle(duplicated_token); - ret = DeviceIoControl(handle, code, in_buf, in_buf_len, out_buf, out_buf_len, bytes_returned, NULL); - break; - } - - RevertToSelf(); - CloseHandle(process_snapshot); - return ret; -} - static int kernel_get_device(struct wgdevice **device, const char *iface) { WG_IOCTL_INTERFACE *wg_iface; @@ -389,10 +329,10 @@ static int kernel_get_device(struct wgdevice **device, const char *iface) if (!handle) return -errno; - while (!elevated_ioctl(handle, WG_IOCTL_GET, NULL, 0, buf, buf_len, &buf_len)) { + while (!DeviceIoControl(handle, WG_IOCTL_GET, NULL, 0, buf, buf_len, &buf_len, NULL)) { free(buf); if (GetLastError() != ERROR_MORE_DATA) { - errno = EIO; + errno = EACCES; return -errno; } buf = malloc(buf_len); @@ -500,10 +440,10 @@ out: static int kernel_set_device(struct wgdevice *dev) { - WG_IOCTL_INTERFACE *wg_iface; + WG_IOCTL_INTERFACE *wg_iface = NULL; WG_IOCTL_PEER *wg_peer; WG_IOCTL_ALLOWED_IP *wg_aip; - size_t buf_len = sizeof(WG_IOCTL_INTERFACE); + DWORD buf_len = sizeof(WG_IOCTL_INTERFACE); HANDLE handle = kernel_interface_handle(dev->name); struct wgpeer *peer; struct wgallowedip *aip; @@ -514,13 +454,22 @@ static int kernel_set_device(struct wgdevice *dev) return -errno; for_each_wgpeer(dev, peer) { + if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_PEER)) { + errno = EOVERFLOW; + goto out; + } buf_len += sizeof(WG_IOCTL_PEER); - for_each_wgallowedip(peer, aip) + for_each_wgallowedip(peer, aip) { + if (DWORD_MAX - buf_len < sizeof(WG_IOCTL_ALLOWED_IP)) { + errno = EOVERFLOW; + goto out; + } buf_len += sizeof(WG_IOCTL_ALLOWED_IP); + } } wg_iface = calloc(1, buf_len); if (!wg_iface) - return -errno; + goto out; if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) { memcpy(wg_iface->PrivateKey, dev->private_key, sizeof(wg_iface->PrivateKey)); @@ -586,8 +535,10 @@ static int kernel_set_device(struct wgdevice *dev) } wg_iface->PeersCount = peer_count; - if (!elevated_ioctl(handle, WG_IOCTL_SET, NULL, 0, wg_iface, buf_len, &buf_len)) + if (!DeviceIoControl(handle, WG_IOCTL_SET, NULL, 0, wg_iface, buf_len, &buf_len, NULL)) { + errno = EACCES; goto out; + } errno = 0; out: