]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
VGAuth: Add secure VMX RPC support.
authorJohn Wolfe <jwolfe@vmware.com>
Mon, 4 Apr 2022 19:58:41 +0000 (12:58 -0700)
committerJohn Wolfe <jwolfe@vmware.com>
Mon, 4 Apr 2022 19:58:41 +0000 (12:58 -0700)
 - Added some error handling to work around VMX closing a
   port that is being reused.

open-vm-tools/vgauth/common/vmxlog.c
open-vm-tools/vgauth/common/vmxrpc.c
open-vm-tools/vgauth/common/vmxrpc.h

index dc34da4844cf4dffedb92efde6316a1e7c65a4c3..bd0b88ef4ff0122a8771cd69cf1d3fb043464667 100644 (file)
@@ -33,7 +33,7 @@
 static gboolean gDisableVMXLogging = TRUE;
 
 /*
- * Error codes for SendString() and SendRpciPacket()
+ * Error codes for SendLogString()
  */
 #define VMX_RPC_OK       1                    // success
 #define VMX_RPC_UNKNOWN  0                    // RPC disabled or not supported
@@ -97,7 +97,7 @@ SendLogString(const gchar *cmd)
    int ret;
    int retVal = VMX_RPC_OK;
 
-   ret = VMXRPC_SendRpc(cmd, &reply);
+   ret = VMXRPC_SendRpc(cmd, FALSE, &reply);
    if (ret >= 0) {
       if (g_strcmp0(reply, "disabled") == 0 ||
           g_strcmp0(reply, "Unknown command") == 0) {
index e35e26d67e964aa20ca46b2f848c062f2fea883b..b4cd5a66201db0aec96c83066f63e751b3b593eb 100644 (file)
@@ -54,6 +54,9 @@ const int VMX_CID = 0;
 const int RPCI_PORT = 976;
 #define VMADDR_PORT_ANY ((unsigned int) -1)
 
+#define PRIVILEGED_PORT_MAX 1023
+#define PRIVILEGED_PORT_MIN 1
+
 static int gAddressFamily = -1;
 
 /*
@@ -82,6 +85,14 @@ typedef uint64_t uint64;
 typedef unsigned short sa_family_t;
 #endif // _WIN32
 
+#ifdef _WIN32
+#define SYSERR_ECONNRESET        WSAECONNRESET
+#define SYSERR_EADDRINUSE        WSAEADDRINUSE
+#else
+#define SYSERR_ECONNRESET        ECONNRESET
+#define SYSERR_EADDRINUSE        EADDRINUSE
+#endif
+
 
 /*
  * Wrapper for socket errnos
@@ -97,6 +108,20 @@ GetSocketErrCode(void)
 }
 
 
+/*
+ * Wrapper for socket close
+ */
+static void
+Socket_Close(SOCKET fd)
+{
+#ifdef _WIN32
+   closesocket(fd);
+#else
+   close(fd);
+#endif
+}
+
+
 /*
  * start code cut&paste from vmci_sockets.h
  *
@@ -324,23 +349,30 @@ GetAddressFamily(void)
 
 /*
  ******************************************************************************
- * VMXRPC_CreateVMCISocket --                                            */ /**
+ * CreateVMCISocket --                                                   */ /**
  *
  * Creates, binds and connects a socket to the VMX.
  *
+ * @param[in] useSecure   If TRUE, use bind to a reserved port locally to allow
+ *                        for a secure channel.
+ *
  * Returns a new socket that should be close()d or -1 on failure.
  *
  ******************************************************************************
  */
 
 static SOCKET
-VMXRPC_CreateVMCISocket(void)
+CreateVMCISocket(gboolean useSecure)
 {
    struct sockaddr_vm localAddr;
    struct sockaddr_vm addr;
    int ret;
-   SOCKET fd = socket(gAddressFamily, SOCK_STREAM, 0);
+   int errCode;
+   unsigned int localPort = PRIVILEGED_PORT_MAX;
+   SOCKET fd;
 
+again:
+   fd = socket(gAddressFamily, SOCK_STREAM, 0);
    if (fd < 0) {
       g_warning("%s: socket() failed %d\n", __FUNCTION__, GetSocketErrCode());
       return -1;
@@ -353,16 +385,40 @@ VMXRPC_CreateVMCISocket(void)
 #else
    localAddr.svm_cid = -1;
 #endif
-   /*
-    * XXX TODO -- bind (optionally?) to a privileged port
-    */
-   localAddr.svm_port = VMADDR_PORT_ANY;
-   ret = bind(fd, (struct sockaddr *)&localAddr, sizeof localAddr);
-   if (ret != 0) {
-      g_warning("%s: bind() failed %d\n", __FUNCTION__, GetSocketErrCode());
+
+   if (useSecure) {
+      while (localPort >= PRIVILEGED_PORT_MIN) {
+         localAddr.svm_port = localPort;
+         ret = bind(fd, (struct sockaddr *)&localAddr, sizeof localAddr);
+         if (ret != 0) {
+            errCode = GetSocketErrCode();
+            if (errCode == SYSERR_EADDRINUSE) {
+               g_debug("%s: bind() failed w/ ADDRINUSE, trying another port\n",
+                       __FUNCTION__);
+               --localPort;
+               continue; /* Try next port */
+            } else {
+               // unexpected failure, bail
+               g_warning("%s: bind() failed %d\n", __FUNCTION__, errCode);
+               goto err;
+            }
+         }  else {
+            g_debug("%s: bind() worked for port %d\n", __FUNCTION__, localPort);
+            goto bound;
+         }
+      }
+      g_warning("%s: failed to find a bindable port\n", __FUNCTION__);
       goto err;
+   } else {
+      localAddr.svm_port = VMADDR_PORT_ANY;
+      ret = bind(fd, (struct sockaddr *)&localAddr, sizeof localAddr);
+      if (ret != 0) {
+         g_warning("%s: bind() failed %d\n", __FUNCTION__, GetSocketErrCode());
+         goto err;
+      }
    }
 
+bound:
    /* connect to destination */
    memset(&addr, 0, sizeof addr);
    addr.svm_family = gAddressFamily;
@@ -371,17 +427,26 @@ VMXRPC_CreateVMCISocket(void)
 
    ret = connect(fd, (struct sockaddr *)&addr, sizeof addr);
    if (ret < 0) {
+      errCode = GetSocketErrCode();
+      if (errCode == SYSERR_ECONNRESET) {
+         /*
+          * VMX might be slow releasing a port pair
+          * when another client closed the client side end.
+          * Simply try next port.
+          */
+         g_debug("%s: connect() failed with RESET, trying another port\n",
+                 __FUNCTION__);
+         localPort--;
+         Socket_Close(fd);
+         goto again;
+      }
       g_warning("%s: connect() failed %d\n", __FUNCTION__, GetSocketErrCode());
       goto err;
    }
 
    return fd;
 err:
-#ifdef _WIN32
-   closesocket(fd);
-#else
-   close(fd);
-#endif
+   Socket_Close(fd);
 
    return -1;
 }
@@ -433,8 +498,9 @@ VMXRPC_Init(void)
  * Sends RPC packet to the VMX.  Returns any response if retBuf is
  * non-NULL.
  *
- * @param[in] packet      RPC packet.
- * @param[in] packetLen   Length of packet.
+ * @param[in] cmd         RPC command
+ * @param[in] useSecure   If TRUE, use bind to a reserved port locally to allow
+ *                        for a secure channel.
  * @param[out] retBuf     RPC reply.
  *
  * Returns -1 on failure, or the length of the returned reply on success (0 if
@@ -445,6 +511,7 @@ VMXRPC_Init(void)
 
 int
 VMXRPC_SendRpc(const gchar *cmd,
+               gboolean useSecure,
                gchar **retBuf)
 {
    SOCKET sock;
@@ -467,7 +534,7 @@ VMXRPC_SendRpc(const gchar *cmd,
       return -1;
    }
 
-   sock = VMXRPC_CreateVMCISocket();
+   sock = CreateVMCISocket(useSecure);
    if (sock < 0) {
       g_warning("%s: failed to create VMCI socket\n", __FUNCTION__);
       return -1;
@@ -559,7 +626,7 @@ main(int argc, char **argv)
       fprintf(stderr, "%s: needs an RPC arg\n", argv[0]);
       exit(-1);
    }
-   ret = VMXRPC_SendRpc(argv[1], &reply);
+   ret = VMXRPC_SendRpc(argv[1], TRUE, &reply);
    if (ret < 0) {
       fprintf(stderr, "%s: failed to send RPC\n", argv[0]);
       exit(-1);
index 775274c7d16a739b3d353ed12ab8d4f8dd4f7bcd..ce9bcd47c53b962c689f12a34dfe51d7a98f69dd 100644 (file)
@@ -26,7 +26,7 @@
  * Support for RPCs to the VMX.
  */
 
-int VMXRPC_SendRpc(const gchar *cmd, gchar **retBuf);
+int VMXRPC_SendRpc(const gchar *cmd, gboolean useSecure, gchar **retBuf);
 
 int VMXRPC_Init(void);