]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
[Wayland DnD] Part2: Open the uinput device file with root permission.
authorOliver Kurth <okurth@vmware.com>
Tue, 24 Apr 2018 00:08:18 +0000 (17:08 -0700)
committerOliver Kurth <okurth@vmware.com>
Tue, 24 Apr 2018 00:08:18 +0000 (17:08 -0700)
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'.

open-vm-tools/lib/include/vmware/tools/plugin.h
open-vm-tools/services/vmtoolsd/cmdLine.c
open-vm-tools/vmware-user-suid-wrapper/main.c

index 17f7cfd7944554530e474ad17faeb6c3b3e08a13..76b07c572bcbbcf06d3d2fa729ac41c394b5127f 100644 (file)
@@ -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
index ee40b2611c7aab256f7e6cb8be243cbba84a856b..17ac5a11225a2f67c0fd4d6648e9001841cb1fd5 100644 (file)
@@ -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
@@ -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."),
@@ -280,6 +283,7 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
 
 #if !defined(G_PLATFORM_WIN32)
    state->ctx.blockFD = -1;
+   state->ctx.uinputFD = -1;
 #endif
 
    /*
@@ -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
 
index 2e4cabf22143733a84f8822d0356cc3ebde020be..e9d7e50843601d59358168bcefd53f8cd4e79a9f 100644 (file)
@@ -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
 /*
  * 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__)
@@ -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;
@@ -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();
@@ -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;
    }
@@ -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;
+         }
       }
    }