Skip to content

Commit

Permalink
[Wayland DnD] Part2: Open the uinput device file with root permission.
Browse files Browse the repository at this point in the history
The device file /dev/uinput (or /dev/input/uinput) can only be accessed
by root account, so the dndcp plugin may failed to open this device file
if the current user is not root account.

A way to fix this issue is opening this device file with root account,
then pass the file descriptor to the sub task which is started with the
current account. An example for this solution is blockVM file system
device file.

This patch is part of the new feature 'Wayland support in Linux guest'.
  • Loading branch information
oliverkurth committed Apr 24, 2018
1 parent b3899c9 commit aa59d16
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 23 deletions.
2 changes: 2 additions & 0 deletions open-vm-tools/lib/include/vmware/tools/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ typedef struct ToolsAppCtx {
#else
/** The FD to access the VMware blocking fs. -1 if no FD available. */
int blockFD;
/** The FD to access the uinput. -1 if no FD available. */
int uinputFD;
/** The native environment (without any VMware modifications). */
const char **envp;
#endif
Expand Down
13 changes: 11 additions & 2 deletions open-vm-tools/services/vmtoolsd/cmdLine.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 2008-2017 VMware, Inc. All rights reserved.
* Copyright (C) 2008-2018 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
Expand Down Expand Up @@ -260,6 +260,9 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
{ "blockFd", '\0', 0, G_OPTION_ARG_INT, &state->ctx.blockFD,
SU_(cmdline.blockfd, "File descriptor for the VMware blocking fs."),
SU_(cmdline.blockfd.fd, "fd") },
{ "uinputFd", '\0', 0, G_OPTION_ARG_INT, &state->ctx.uinputFD,
SU_(cmdline.uinputfd, "File descriptor for the uinput device."),
SU_(cmdline.uinputfd.fd, "fd") },
#endif
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &state->configFile,
SU_(cmdline.config, "Uses the config file at the given path."),
Expand All @@ -280,6 +283,7 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,

#if !defined(G_PLATFORM_WIN32)
state->ctx.blockFD = -1;
state->ctx.uinputFD = -1;
#endif

/*
Expand Down Expand Up @@ -344,12 +348,17 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
exit(ToolsCoreSignalEvent(state->name, DUMP_STATE_EVENT_NAME_FMT) ? 0 : 1);
}
#else
/* If not running the "vmusr" service, ignore the blockFd parameter. */
/* If not running the "vmusr" service, ignore the blockFd and uinputFd parameter. */
if (!TOOLS_IS_USER_SERVICE(state)) {
if (state->ctx.blockFD >= 0) {
close(state->ctx.blockFD);
}
state->ctx.blockFD = -1;

if (state->ctx.uinputFD >= 0) {
close(state->ctx.uinputFD);
}
state->ctx.uinputFD = -1;
}
#endif

Expand Down
79 changes: 58 additions & 21 deletions open-vm-tools/vmware-user-suid-wrapper/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 2007-2017 VMware, Inc. All rights reserved.
* Copyright (C) 2007-2018 VMware, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
Expand All @@ -20,12 +20,14 @@
/*
* main.c --
*
* This program is run as root to prepare the system for vmware-user. It
* unmounts the vmblock file system, unloads the vmblock module, then
* reloads the module, mounts the file system, and opens a file descriptor
* that vmware-user can use to add and remove blocks. This must all
* happen as root since we cannot allow any random process to add and
* remove blocks in the blocking file system.
* This program is run as root to prepare the system for vmware-user.
* - It unmounts the vmblock file system, unloads the vmblock module, then
* reloads the module, mounts the file system, and opens a file descriptor
* that vmware-user can use to add and remove blocks.
* This must all happen as root since we cannot allow any random process
* to add and remove blocks in the blocking file system.
* - It opens the uinput device file and passes the file descriptor to
* vmware-user.
*/

#if !defined(sun) && !defined(__FreeBSD__) && !defined(__linux__)
Expand Down Expand Up @@ -173,11 +175,16 @@ StartVMwareUser(char *const envp[])
pid_t pid;
uid_t uid;
gid_t gid;
int fd = -1;
int blockFd = -1;
char blockFdStr[8];
int uinputFd = -1;
char uinputFdStr[8];
int ret;
char path[MAXPATHLEN];
char *argv[6];
char *argv[8];
size_t idx = 0;
char *xdgSessionType;
Bool useWayland = FALSE;

if (!BuildExecPath(path, sizeof path)) {
return FALSE;
Expand All @@ -198,15 +205,28 @@ StartVMwareUser(char *const envp[])

/* Child */

xdgSessionType = getenv("XDG_SESSION_TYPE");
if ( (xdgSessionType != NULL)
&& (strstr(xdgSessionType, "wayland") != NULL)) {
useWayland = TRUE;
}

/*
* We know the file system is mounted and want to keep this suid
* root wrapper as small as possible, so here we directly open(2) the
* "device" instead of calling DnD_InitializeBlocking() and bringing along
* a whole host of libs.
*/
fd = open(VMBLOCK_FUSE_DEVICE, VMBLOCK_FUSE_DEVICE_MODE);
if (fd < 0) {
fd = open(VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE);
blockFd = open(VMBLOCK_FUSE_DEVICE, VMBLOCK_FUSE_DEVICE_MODE);
if (blockFd < 0) {
blockFd = open(VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE);
}

if (useWayland) {
uinputFd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (uinputFd < 0) {
uinputFd = open("/dev/input/uinput", O_WRONLY | O_NONBLOCK);
}
}

uid = getuid();
Expand All @@ -215,8 +235,13 @@ StartVMwareUser(char *const envp[])
if ((setreuid(uid, uid) != 0) ||
(setregid(gid, gid) != 0)) {
Error("could not drop privileges: %s\n", strerror(errno));
if (fd != -1) {
close(fd);
if (blockFd != -1) {
close(blockFd);
}
if (useWayland) {
if (uinputFd != -1) {
close(uinputFd);
}
}
return FALSE;
}
Expand All @@ -231,17 +256,29 @@ StartVMwareUser(char *const envp[])
argv[idx++] = "-n";
argv[idx++] = "vmusr";

if (fd < 0) {
if (blockFd < 0) {
Error("could not open %s\n", VMBLOCK_DEVICE);
} else {
char fdStr[8];

ret = snprintf(fdStr, sizeof fdStr, "%d", fd);
if (ret == 0 || ret >= sizeof fdStr) {
Error("could not parse file descriptor (%d)\n", fd);
ret = snprintf(blockFdStr, sizeof blockFdStr, "%d", blockFd);
if (ret == 0 || ret >= sizeof blockFdStr) {
Error("could not parse file descriptor (%d)\n", blockFd);
} else {
argv[idx++] = "--blockFd";
argv[idx++] = fdStr;
argv[idx++] = blockFdStr;
}
}

if (useWayland) {
if (uinputFd < 0) {
Error("could not open uinput device\n");
} else {
ret = snprintf(uinputFdStr, sizeof uinputFdStr, "%d", uinputFd);
if (ret == 0 || ret >= sizeof uinputFdStr) {
Error("could not parse uinput file descriptor (%d)\n", uinputFd);
} else {
argv[idx++] = "--uinputFd";
argv[idx++] = uinputFdStr;
}
}
}

Expand Down

0 comments on commit aa59d16

Please sign in to comment.