summaryrefslogtreecommitdiffstats
path: root/input
diff options
context:
space:
mode:
authorJames Ross-Gowan <rossymiles@gmail.com>2016-03-25 21:06:30 +1100
committerJames Ross-Gowan <rossymiles@gmail.com>2016-03-25 21:06:30 +1100
commitef625a78a4784318b72cd44e9703591811e942fc (patch)
tree9488d5bd1e4c2fff41d629fc00f11e294e4a1fd7 /input
parenta76f3e8e468b6962e57fd7dd4c5f487301ea001b (diff)
downloadmpv-ef625a78a4784318b72cd44e9703591811e942fc.tar.bz2
mpv-ef625a78a4784318b72cd44e9703591811e942fc.tar.xz
ipc-win: restrict read access to the IPC pipe
The default security descriptor for named pipes in Windows allows the pipe to be opened for read access by the Everyone group and Anonymous account, as well as low-integrity processes (like web browser renderer processes.) This does not allow commands to be ran, but it does allow events to be received. I don't think any sensitive data is exposed by events, but that may not always be the case and Lua plugins might change this, since they can broadcast their own events with script-message. To be safe, this commit sets a custom security descriptor on the named pipe which only allows access from processes running under the same user account with an integrity level greater than or equal to the one used by mpv.
Diffstat (limited to 'input')
-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)