wg: windows: enforce named pipe ownership and use protected prefix
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
4154476d89
commit
959937672a
32
src/ipc.c
32
src/ipc.c
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,14 +70,25 @@ 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)
|
||||||
|
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;
|
last_error = ERROR_SUCCESS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
RevertToSelf();
|
RevertToSelf();
|
||||||
CloseHandle(process_snapshot);
|
CloseHandle(process_snapshot);
|
||||||
|
|
||||||
|
|
Reference in New Issue