summaryrefslogtreecommitdiffstats
path: root/input/ipc-win.c
diff options
context:
space:
mode:
Diffstat (limited to 'input/ipc-win.c')
-rw-r--r--input/ipc-win.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/input/ipc-win.c b/input/ipc-win.c
index 3c5f3832aa..b0010cba7d 100644
--- a/input/ipc-win.c
+++ b/input/ipc-win.c
@@ -16,6 +16,7 @@
*/
#include <windows.h>
+#include <sddl.h>
#include "config.h"
@@ -50,6 +51,88 @@ struct client_arg {
OVERLAPPED write_ol;
};
+// Get a string SID representing the current user. Must be freed by LocalFree.
+static char *get_user_sid(void)
+{
+ char *ssid = NULL;
+ TOKEN_USER *info = NULL;
+ HANDLE t;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &t))
+ goto done;
+
+ DWORD info_len;
+ if (!GetTokenInformation(t, TokenUser, NULL, 0, &info_len) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto done;
+
+ info = talloc_size(NULL, info_len);
+ if (!GetTokenInformation(t, TokenUser, info, info_len, &info_len))
+ goto done;
+ if (!info->User.Sid)
+ goto done;
+
+ ConvertSidToStringSidA(info->User.Sid, &ssid);
+done:
+ if (t)
+ CloseHandle(t);
+ talloc_free(info);
+ return ssid;
+}
+
+// Get a string SID for the process integrity level. Must be freed by LocalFree.
+static char *get_integrity_sid(void)
+{
+ char *ssid = NULL;
+ TOKEN_MANDATORY_LABEL *info = NULL;
+ HANDLE t;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &t))
+ goto done;
+
+ DWORD info_len;
+ if (!GetTokenInformation(t, TokenIntegrityLevel, NULL, 0, &info_len) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto done;
+
+ info = talloc_size(NULL, info_len);
+ if (!GetTokenInformation(t, TokenIntegrityLevel, info, info_len, &info_len))
+ goto done;
+ if (!info->Label.Sid)
+ goto done;
+
+ ConvertSidToStringSidA(info->Label.Sid, &ssid);
+done:
+ if (t)
+ CloseHandle(t);
+ talloc_free(info);
+ return ssid;
+}
+
+// Create a security descriptor that only grants access to processes running
+// under the current user at the current integrity level or higher
+static PSECURITY_DESCRIPTOR create_restricted_sd(void)
+{
+ char *user_sid = get_user_sid();
+ char *integrity_sid = get_integrity_sid();
+ if (!user_sid || !integrity_sid)
+ return NULL;
+
+ char *sddl = talloc_asprintf(NULL,
+ "O:%s" // Set the owner to user_sid
+ "D:(A;;GRGW;;;%s)" // Grant GENERIC_{READ,WRITE} access to user_sid
+ "S:(ML;;NRNWNX;;;%s)", // Disallow read, write and execute permissions
+ // to integrity levels below integrity_sid
+ user_sid, user_sid, integrity_sid);
+ LocalFree(user_sid);
+ LocalFree(integrity_sid);
+
+ PSECURITY_DESCRIPTOR sd = NULL;
+ ConvertStringSecurityDescriptorToSecurityDescriptorA(sddl, SDDL_REVISION_1,
+ &sd, NULL);
+ talloc_free(sddl);
+
+ return sd;
+}
+
static void wakeup_cb(void *d)
{
HANDLE event = d;
@@ -275,6 +358,15 @@ static void *ipc_thread(void *p)
mpthread_set_name("ipc named pipe listener");
MP_VERBOSE(arg, "Starting IPC master\n");
+ SECURITY_ATTRIBUTES sa = {
+ .nLength = sizeof sa,
+ .lpSecurityDescriptor = create_restricted_sd(),
+ };
+ if (!sa.lpSecurityDescriptor) {
+ MP_ERR(arg, "Couldn't create security descriptor");
+ goto done;
+ }
+
OVERLAPPED ol = { .hEvent = CreateEventW(NULL, TRUE, TRUE, NULL) };
if (!ol.hEvent) {
MP_ERR(arg, "Couldn't create event");
@@ -282,7 +374,7 @@ static void *ipc_thread(void *p)
}
server = CreateNamedPipeW(arg->path, mode | FILE_FLAG_FIRST_PIPE_INSTANCE,
- state, PIPE_UNLIMITED_INSTANCES, bufsiz, bufsiz, 0, NULL);
+ state, PIPE_UNLIMITED_INSTANCES, bufsiz, bufsiz, 0, &sa);
if (server == INVALID_HANDLE_VALUE) {
MP_ERR(arg, "Couldn't create first pipe instance: %s\n",
mp_LastError_to_str());
@@ -333,7 +425,7 @@ static void *ipc_thread(void *p)
// closes the handle and there are no active instances of the pipe
client = server;
server = CreateNamedPipeW(arg->path, mode, state,
- PIPE_UNLIMITED_INSTANCES, bufsiz, bufsiz, 0, NULL);
+ PIPE_UNLIMITED_INSTANCES, bufsiz, bufsiz, 0, &sa);
if (server == INVALID_HANDLE_VALUE) {
MP_ERR(arg, "Couldn't create additional pipe instance: %s\n",
mp_LastError_to_str());
@@ -345,6 +437,8 @@ static void *ipc_thread(void *p)
}
done:
+ if (sa.lpSecurityDescriptor)
+ LocalFree(sa.lpSecurityDescriptor);
if (client != INVALID_HANDLE_VALUE)
CloseHandle(client);
if (server != INVALID_HANDLE_VALUE)