wg: windows: enforce named pipe ownership and use protected prefix

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2019-08-30 13:51:27 -06:00
parent 4154476d89
commit 959937672a
2 changed files with 40 additions and 22 deletions

View file

@ -96,7 +96,7 @@ static int add_next_to_inflatable_buffer(struct inflatable_buffer *buffer)
} }
#ifndef WINCOMPAT #ifndef WINCOMPAT
static FILE *userspace_interface_file(const char *interface) static FILE *userspace_interface_file(const char *iface)
{ {
struct stat sbuf; struct stat sbuf;
struct sockaddr_un addr = { .sun_family = AF_UNIX }; struct sockaddr_un addr = { .sun_family = AF_UNIX };
@ -104,9 +104,9 @@ static FILE *userspace_interface_file(const char *interface)
FILE *f = NULL; FILE *f = NULL;
errno = EINVAL; errno = EINVAL;
if (strchr(interface, '/')) if (strchr(iface, '/'))
goto out; goto out;
ret = snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, interface); ret = snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, iface);
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = stat(addr.sun_path, &sbuf); ret = stat(addr.sun_path, &sbuf);
@ -140,15 +140,15 @@ out:
return f; return f;
} }
static bool userspace_has_wireguard_interface(const char *interface) static bool userspace_has_wireguard_interface(const char *iface)
{ {
struct stat sbuf; struct stat sbuf;
struct sockaddr_un addr = { .sun_family = AF_UNIX }; struct sockaddr_un addr = { .sun_family = AF_UNIX };
int fd, ret; int fd, ret;
if (strchr(interface, '/')) if (strchr(iface, '/'))
return false; return false;
if (snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, interface) < 0) if (snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, iface) < 0)
return false; return false;
if (stat(addr.sun_path, &sbuf) < 0) if (stat(addr.sun_path, &sbuf) < 0)
return false; return false;
@ -288,7 +288,7 @@ static int userspace_set_device(struct wgdevice *dev)
num; \ num; \
}) })
static int userspace_get_device(struct wgdevice **out, const char *interface) static int userspace_get_device(struct wgdevice **out, const char *iface)
{ {
struct wgdevice *dev; struct wgdevice *dev;
struct wgpeer *peer = NULL; struct wgpeer *peer = NULL;
@ -302,14 +302,14 @@ static int userspace_get_device(struct wgdevice **out, const char *interface)
if (!dev) if (!dev)
return -errno; return -errno;
f = userspace_interface_file(interface); f = userspace_interface_file(iface);
if (!f) if (!f)
return -errno; return -errno;
fprintf(f, "get=1\n\n"); fprintf(f, "get=1\n\n");
fflush(f); fflush(f);
strncpy(dev->name, interface, IFNAMSIZ - 1); strncpy(dev->name, iface, IFNAMSIZ - 1);
dev->name[IFNAMSIZ - 1] = '\0'; dev->name[IFNAMSIZ - 1] = '\0';
while (getline(&key, &line_buffer_len, f) > 0) { while (getline(&key, &line_buffer_len, f) > 0) {
@ -889,7 +889,7 @@ static void coalesce_peers(struct wgdevice *device)
} }
} }
static int kernel_get_device(struct wgdevice **device, const char *interface) static int kernel_get_device(struct wgdevice **device, const char *iface)
{ {
int ret = 0; int ret = 0;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
@ -908,7 +908,7 @@ try_again:
} }
nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); nlh = mnlg_msg_prepare(nlg, WG_CMD_GET_DEVICE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, interface); mnl_attr_put_strz(nlh, WGDEVICE_A_IFNAME, iface);
if (mnlg_socket_send(nlg, nlh) < 0) { if (mnlg_socket_send(nlg, nlh) < 0) {
ret = -errno; ret = -errno;
goto out; goto out;
@ -963,14 +963,14 @@ cleanup:
return buffer.buffer; return buffer.buffer;
} }
int ipc_get_device(struct wgdevice **dev, const char *interface) int ipc_get_device(struct wgdevice **dev, const char *iface)
{ {
#ifdef __linux__ #ifdef __linux__
if (userspace_has_wireguard_interface(interface)) if (userspace_has_wireguard_interface(iface))
return userspace_get_device(dev, interface); return userspace_get_device(dev, iface);
return kernel_get_device(dev, interface); return kernel_get_device(dev, iface);
#else #else
return userspace_get_device(dev, interface); return userspace_get_device(dev, iface);
#endif #endif
} }

View file

@ -5,18 +5,23 @@
#include <windows.h> #include <windows.h>
#include <tlhelp32.h> #include <tlhelp32.h>
#include <accctrl.h>
#include <aclapi.h>
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <fcntl.h> #include <fcntl.h>
static FILE *userspace_interface_file(const char *interface) static FILE *userspace_interface_file(const char *iface)
{ {
char fname[MAX_PATH], error_message[1024 * 128] = { 0 }; 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; HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token, pipe_handle = INVALID_HANDLE_VALUE;
PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) }; PROCESSENTRY32 entry = { .dwSize = sizeof(PROCESSENTRY32) };
PSECURITY_DESCRIPTOR pipe_sd;
PSID pipe_sid;
SID expected_sid;
BOOL ret; BOOL ret;
int fd; int fd;
DWORD last_error = ERROR_SUCCESS; DWORD last_error = ERROR_SUCCESS, bytes = sizeof(expected_sid);
TOKEN_PRIVILEGES privileges = { TOKEN_PRIVILEGES privileges = {
.PrivilegeCount = 1, .PrivilegeCount = 1,
.Privileges = {{ .Attributes = SE_PRIVILEGE_ENABLED }} .Privileges = {{ .Attributes = SE_PRIVILEGE_ENABLED }}
@ -24,6 +29,8 @@ static FILE *userspace_interface_file(const char *interface)
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid)) if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid))
goto err; goto err;
if (!CreateWellKnownSid(WinLocalSystemSid, NULL, &expected_sid, &bytes))
goto err;
process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (process_snapshot == INVALID_HANDLE_VALUE) if (process_snapshot == INVALID_HANDLE_VALUE)
@ -63,13 +70,24 @@ static FILE *userspace_interface_file(const char *interface)
} }
CloseHandle(duplicated_token); CloseHandle(duplicated_token);
snprintf(fname, sizeof(fname), "\\\\.\\pipe\\WireGuard\\%s", interface); snprintf(fname, sizeof(fname), "\\\\.\\pipe\\ProtectedPrefix\\Administrators\\WireGuard\\%s", iface);
pipe_handle = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); pipe_handle = CreateFile(fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
last_error = GetLastError(); last_error = GetLastError();
if (pipe_handle != INVALID_HANDLE_VALUE) { if (pipe_handle == INVALID_HANDLE_VALUE)
last_error = ERROR_SUCCESS; continue;
break; 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(); RevertToSelf();
CloseHandle(process_snapshot); CloseHandle(process_snapshot);