vmware / open-vm-tools

Official repository of VMware open-vm-tools project
http://sourceforge.net/projects/open-vm-tools/
2.21k stars 419 forks source link

vmware-hostd crashes on unrecognized Linux distribution #31

Open drvink opened 8 years ago

drvink commented 8 years ago

While this is probably a Workstation bug, it's possible to work around it by patching vmtoolsd, so I thought I'd make a report here so that it can be forwarded to the right place. (BTW, you might want to indicate in the readme on the master branch that this repo isn't dead, because it looks like the code hasn't been touched for two years unless you click around and notice that there's been activity in the branches.)

I reported this on the VMware forum:

When running a VM as a shared VM on Workstation 11, vmware-hostd crashes repeatedly if vmtoolsd is running in the guest and the distribution isn't recognized by vmware-hostd. This causes all shared VMs to disappear from the GUI, though they will continue to run if they are already running. Stopping vmtoolsd and restarting the shared VM service makes the VMs reappear, but if you restart vmtoolsd, the service will crash again. This happens for me with Arch Linux 64-bit and vmtoolsd from open-vm-tools; probably it is an issue on many other distributions too. Here is the relevant line from the hostd log file:

2015-01-06T16:52:51.141+09:00 [07580 error 'Default' opID=17217a18] Unable to convert Vigor value 'Arch-64' of type 'char const *' to VIM type 'enum Vim::Vm::GuestOsDescriptor::GuestOsIdentifier'

The patch in that thread is a hack to prevent vmtoolsd from providing the information that ultimately makes vmware-hostd crash. In case someone sees this thread hoping for a quick fix, here's an updated one for 9.10.2 (cd to open-vm-tools-stable-9.10.2/open-vm-tools and apply with patch -p2):

--- open-vm-tools-stable-9.10.2/open-vm-tools/lib/misc/hostinfoPosix.c.old  2015-06-17 06:49:24.000000000 +0900
+++ open-vm-tools-stable-9.10.2/open-vm-tools/lib/misc/hostinfoPosix.c  2015-07-22 00:26:59.716488677 +0900
@@ -457,387 +457,6 @@
 }

-#if !defined __APPLE__ && !defined USERWORLD
-/*
- *-----------------------------------------------------------------------------
- *
- * HostinfoGetOSShortName --
- *
- *      Returns distro information based on .vmx format (distroShort).
- *
- * Return value:
- *      Overwrited the short name if we recognise the OS.
- *      Otherwise leave the short name as it is.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-HostinfoGetOSShortName(char *distro,         // IN: full distro name
-                       char *distroShort,    // OUT: short distro name
-                       int distroShortSize)  // IN: size of short distro name
-
-{
-   char *distroLower = NULL;  /* Lower case distro name */
-
-   distroLower = calloc(strlen(distro) + 1, sizeof *distroLower);
-
-   if (distroLower == NULL) {
-      Warning("%s: could not allocate memory\n", __FUNCTION__);
-
-      return;
-   }
-
-   Str_Strcpy(distroLower, distro, distroShortSize);
-   distroLower = Str_ToLower(distroLower);
-
-   if (strstr(distroLower, "red hat")) {
-      if (strstr(distroLower, "enterprise")) {
-
-         /*
-          * Looking for "release x" here instead of "x" as there could be
-          * build version which can be misleading. For example Red Hat
-          * Enterprise Linux ES release 4 (Nahant Update 3)
-          */
-
-         int release = 0;
-         char *releaseStart = strstr(distroLower, "release");
-
-         if (releaseStart) {
-            sscanf(releaseStart, "release %d", &release);
-            if (release > 0) {
-               snprintf(distroShort, distroShortSize, STR_OS_RED_HAT_EN"%d",
-                        release);
-            }
-         }
-
-         if (release <= 0) {
-            Warning("%s: could not read Red Hat Enterprise release version\n",
-                  __FUNCTION__);
-            Str_Strcpy(distroShort, STR_OS_RED_HAT_EN, distroShortSize);
-         }
-
-      } else {
-         Str_Strcpy(distroShort, STR_OS_RED_HAT, distroShortSize);
-      }
-   } else if (strstr(distroLower, "opensuse")) {
-      Str_Strcpy(distroShort, STR_OS_OPENSUSE, distroShortSize);
-   } else if (strstr(distroLower, "suse")) {
-      if (strstr(distroLower, "enterprise")) {
-         if (strstr(distroLower, "server 12") ||
-             strstr(distroLower, "desktop 12")) {
-            Str_Strcpy(distroShort, STR_OS_SLES_12, distroShortSize);
-         } else if (strstr(distroLower, "server 11") ||
-                    strstr(distroLower, "desktop 11")) {
-            Str_Strcpy(distroShort, STR_OS_SLES_11, distroShortSize);
-         } else if (strstr(distroLower, "server 10") ||
-                    strstr(distroLower, "desktop 10")) {
-            Str_Strcpy(distroShort, STR_OS_SLES_10, distroShortSize);
-         } else {
-            Str_Strcpy(distroShort, STR_OS_SLES, distroShortSize);
-         }
-      } else if (strstr(distroLower, "sun")) {
-         Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
-      } else if (strstr(distroLower, "novell")) {
-         Str_Strcpy(distroShort, STR_OS_NOVELL, distroShortSize);
-      } else {
-         Str_Strcpy(distroShort, STR_OS_SUSE, distroShortSize);
-      }
-   } else if (strstr(distroLower, "mandrake")) {
-      Str_Strcpy(distroShort, STR_OS_MANDRAKE, distroShortSize);
-   } else if (strstr(distroLower, "turbolinux")) {
-      Str_Strcpy(distroShort, STR_OS_TURBO, distroShortSize);
-   } else if (strstr(distroLower, "sun")) {
-      Str_Strcpy(distroShort, STR_OS_SUN_DESK, distroShortSize);
-   } else if (strstr(distroLower, "annvix")) {
-      Str_Strcpy(distroShort, STR_OS_ANNVIX, distroShortSize);
-   } else if (strstr(distroLower, "arch")) {
-      Str_Strcpy(distroShort, STR_OS_ARCH, distroShortSize);
-   } else if (strstr(distroLower, "arklinux")) {
-      Str_Strcpy(distroShort, STR_OS_ARKLINUX, distroShortSize);
-   } else if (strstr(distroLower, "asianux server 3") ||
-              strstr(distroLower, "asianux client 3")) {
-      Str_Strcpy(distroShort, STR_OS_ASIANUX_3, distroShortSize);
-   } else if (strstr(distroLower, "asianux server 4") ||
-              strstr(distroLower, "asianux client 4")) {
-      Str_Strcpy(distroShort, STR_OS_ASIANUX_4, distroShortSize);
-   } else if (strstr(distroLower, "asianux server 5") ||
-              strstr(distroLower, "asianux client 5")) {
-      Str_Strcpy(distroShort, STR_OS_ASIANUX_5, distroShortSize);
-   } else if (strstr(distroLower, "aurox")) {
-      Str_Strcpy(distroShort, STR_OS_AUROX, distroShortSize);
-   } else if (strstr(distroLower, "black cat")) {
-      Str_Strcpy(distroShort, STR_OS_BLACKCAT, distroShortSize);
-   } else if (strstr(distroLower, "cobalt")) {
-      Str_Strcpy(distroShort, STR_OS_COBALT, distroShortSize);
-   } else if (StrUtil_StartsWith(distroLower, "centos")) {
-      Str_Strcpy(distroShort, STR_OS_CENTOS, distroShortSize);
-   } else if (strstr(distroLower, "conectiva")) {
-      Str_Strcpy(distroShort, STR_OS_CONECTIVA, distroShortSize);
-   } else if (strstr(distroLower, "debian")) {
-      if (strstr(distroLower, "4.0")) {
-         Str_Strcpy(distroShort, STR_OS_DEBIAN_4, distroShortSize);
-      } else if (strstr(distroLower, "5.0")) {
-         Str_Strcpy(distroShort, STR_OS_DEBIAN_5, distroShortSize);
-      } else if (strstr(distroLower, "6.0")) {
-         Str_Strcpy(distroShort, STR_OS_DEBIAN_6, distroShortSize);
-      } else if (strstr(distroLower, "7.")) {
-         Str_Strcpy(distroShort, STR_OS_DEBIAN_7, distroShortSize);
-      } else if (strstr(distroLower, "8.")) {
-         Str_Strcpy(distroShort, STR_OS_DEBIAN_8, distroShortSize);
-      }
-   } else if (StrUtil_StartsWith(distroLower, "enterprise linux") ||
-              StrUtil_StartsWith(distroLower, "oracle")) {
-      /*
-       * [root@localhost ~]# lsb_release -sd
-       * "Enterprise Linux Enterprise Linux Server release 5.4 (Carthage)"
-       *
-       * Not sure why they didn't brand their releases as "Oracle Enterprise
-       * Linux". Oh well. It's fixed in 6.0, though.
-       */
-      Str_Strcpy(distroShort, STR_OS_ORACLE, distroShortSize);
-   } else if (strstr(distroLower, "fedora")) {
-      Str_Strcpy(distroShort, STR_OS_FEDORA, distroShortSize);
-   } else if (strstr(distroLower, "gentoo")) {
-      Str_Strcpy(distroShort, STR_OS_GENTOO, distroShortSize);
-   } else if (strstr(distroLower, "immunix")) {
-      Str_Strcpy(distroShort, STR_OS_IMMUNIX, distroShortSize);
-   } else if (strstr(distroLower, "linux-from-scratch")) {
-      Str_Strcpy(distroShort, STR_OS_LINUX_FROM_SCRATCH, distroShortSize);
-   } else if (strstr(distroLower, "linux-ppc")) {
-      Str_Strcpy(distroShort, STR_OS_LINUX_PPC, distroShortSize);
-   } else if (strstr(distroLower, "mandriva")) {
-      Str_Strcpy(distroShort, STR_OS_MANDRIVA, distroShortSize);
-   } else if (strstr(distroLower, "mklinux")) {
-      Str_Strcpy(distroShort, STR_OS_MKLINUX, distroShortSize);
-   } else if (strstr(distroLower, "pld")) {
-      Str_Strcpy(distroShort, STR_OS_PLD, distroShortSize);
-   } else if (strstr(distroLower, "slackware")) {
-      Str_Strcpy(distroShort, STR_OS_SLACKWARE, distroShortSize);
-   } else if (strstr(distroLower, "sme server")) {
-      Str_Strcpy(distroShort, STR_OS_SMESERVER, distroShortSize);
-   } else if (strstr(distroLower, "tiny sofa")) {
-      Str_Strcpy(distroShort, STR_OS_TINYSOFA, distroShortSize);
-   } else if (strstr(distroLower, "ubuntu")) {
-      Str_Strcpy(distroShort, STR_OS_UBUNTU, distroShortSize);
-   } else if (strstr(distroLower, "ultra penguin")) {
-      Str_Strcpy(distroShort, STR_OS_ULTRAPENGUIN, distroShortSize);
-   } else if (strstr(distroLower, "united linux")) {
-      Str_Strcpy(distroShort, STR_OS_UNITEDLINUX, distroShortSize);
-   } else if (strstr(distroLower, "va linux")) {
-      Str_Strcpy(distroShort, STR_OS_VALINUX, distroShortSize);
-   } else if (strstr(distroLower, "yellow dog")) {
-      Str_Strcpy(distroShort, STR_OS_YELLOW_DOG, distroShortSize);
-   }
-
-   free(distroLower);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * HostinfoReadDistroFile --
- *
- *      Look for a distro version file /etc/xxx-release.
- *      Once found, read the file in and figure out which distribution.
- *
- * Return value:
- *      Returns TRUE on success and FALSE on failure.
- *      Returns distro information verbatium from /etc/xxx-release (distro).
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HostinfoReadDistroFile(char *filename,  // IN: distro version file name
-                       int distroSize,  // IN: size of OS distro name buffer
-                       char *distro)    // OUT: full distro name
-{
-   int fd = -1;
-   int buf_sz;
-   struct stat st;
-   Bool ret = FALSE;
-   char *distroOrig = NULL;
-   char distroPart[DISTRO_BUF_SIZE];
-   char *tmpDistroPos = NULL;
-   int i = 0;
-
-   /* It's OK for the file to not exist, don't warn for this.  */
-   if ((fd = Posix_Open(filename, O_RDONLY)) == -1) {
-      return FALSE;
-   }
-
-   if (fstat(fd, &st)) {
-      Warning("%s: could not stat the file %s: %d\n", __FUNCTION__, filename,
-           errno);
-      goto out;
-   }
-
-   if (st.st_size == 0) {
-      Warning("%s: Cannot work with empty file.\n", __FUNCTION__);
-      goto out;
-   }
-
-   buf_sz = st.st_size;
-   if (buf_sz >= distroSize) {
-      Warning("%s: input buffer too small\n", __FUNCTION__);
-      goto out;
-   }
-   distroOrig = calloc(distroSize, sizeof *distroOrig);
-
-   if (distroOrig == NULL) {
-      Warning("%s: could not allocate memory\n", __FUNCTION__);
-      goto out;
-   }
-
-   if (read(fd, distroOrig, buf_sz) != buf_sz) {
-      Warning("%s: could not read file %s: %d\n", __FUNCTION__, filename,
-              errno);
-      goto out;
-   }
-
-   distroOrig[buf_sz - 1] = '\0';
-
-   /*
-    * For the case where we do have a release file in the LSB format,
-    * but there is no LSB module, let's parse the LSB file for possible fields.
-    */
-
-   distro[0] = '\0';
-
-   for (i = 0; lsbFields[i].name != NULL; i++) {
-      tmpDistroPos = strstr(distroOrig, lsbFields[i].name);
-      if (tmpDistroPos) {
-         sscanf(tmpDistroPos, lsbFields[i].scanstring, distroPart);
-         if (distroPart[0] == '"') {
-            char *tmpMakeNull = NULL;
-
-            tmpDistroPos += strlen(lsbFields[i].name) + 1;
-            tmpMakeNull = strchr(tmpDistroPos + 1 , '"');
-            if (tmpMakeNull) {
-               *tmpMakeNull = '\0';
-               Str_Strcat(distro, tmpDistroPos, distroSize);
-               *tmpMakeNull = '"' ;
-            }
-         } else {
-            Str_Strcat(distro, distroPart, distroSize);
-         }
-         Str_Strcat(distro, " ", distroSize);
-      }
-   }
-
-   if (distro[0] == '\0') {
-      /* Copy original string. What we got wasn't LSB compliant. */
-      Str_Strcpy(distro, distroOrig, distroSize);
-   }
-
-   ret = TRUE;
-
-out:
-   if (fd != -1) {
-      close(fd);
-   }
-   free(distroOrig);
-
-   return ret;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * HostinfoGetCmdOutput --
- *
- *      Run a cmd & get its cmd line output
- *
- * Results:
- *      An allocated string or NULL if an error occurred.
- *
- * Side effects:
- * The cmd is run.
- *
- *----------------------------------------------------------------------
- */
-
-static char *
-HostinfoGetCmdOutput(const char *cmd)  // IN:
-{
-   Bool isSuperUser = FALSE;
-   DynBuf db;
-   FILE *stream;
-   char *out = NULL;
-
-   /*
-    * Attempt to lower privs, because we use popen and an attacker
-    * may control $PATH.
-    */
-   if (vmx86_linux && Id_IsSuperUser()) {
-      Id_EndSuperUser(getuid());
-      isSuperUser = TRUE;
-   }
-
-   DynBuf_Init(&db);
-
-   stream = Posix_Popen(cmd, "r");
-   if (stream == NULL) {
-      Warning("Unable to get output of command \"%s\"\n", cmd);
-
-      goto exit;
-   }
-
-   for (;;) {
-      char *line = NULL;
-      size_t size;
-
-      switch (StdIO_ReadNextLine(stream, &line, 0, &size)) {
-      case StdIO_Error:
-         goto closeIt;
-         break;
-
-      case StdIO_EOF:
-         break;
-
-      case StdIO_Success:
-         break;
-
-      default:
-         NOT_IMPLEMENTED();
-      }
-
-      if (line == NULL) {
-         break;
-      }
-
-      /* size does -not- include the NUL terminator. */
-      DynBuf_Append(&db, line, size + 1);
-      free(line);
-   }
-
-   if (DynBuf_Get(&db)) {
-      out = (char *) DynBuf_AllocGet(&db);
-   }
-
- closeIt:
-   pclose(stream);
-
- exit:
-   DynBuf_Destroy(&db);
-
-   if (isSuperUser) {
-      Id_BeginSuperUser();
-   }
-   return out;
-}
-#endif // !defined __APPLE__ && !defined USERWORLD
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -947,7 +566,6 @@
       char distro[DISTRO_BUF_SIZE];
       char distroShort[DISTRO_BUF_SIZE];
       static int const distroSize = sizeof distro;
-      char *lsbOutput;
       int majorVersion;

       /*
@@ -970,61 +588,6 @@
          Str_Strcpy(distroShort, STR_OS_OTHER_3X, distroSize);
       }

-      /*
-       * Try to get OS detailed information from the lsb_release command.
-       */
-
-      lsbOutput = HostinfoGetCmdOutput("/usr/bin/lsb_release -sd 2>/dev/null");
-      if (!lsbOutput) {
-         int i;
-
-         /*
-          * Try to get more detailed information from the version file.
-          */
-
-         for (i = 0; distroArray[i].filename != NULL; i++) {
-            if (HostinfoReadDistroFile(distroArray[i].filename, distroSize,
-                                       distro)) {
-               break;
-            }
-         }
-
-         /*
-          * If we failed to read every distro file, exit now, before calling
-          * strlen on the distro buffer (which wasn't set).
-          */
-
-         if (distroArray[i].filename == NULL) {
-            Warning("%s: Error: no distro file found\n", __FUNCTION__);
-
-            return FALSE;
-         }
-      } else {
-         char *lsbStart = lsbOutput;
-         char *quoteEnd = NULL;
-
-         if (lsbStart[0] == '"') {
-            lsbStart++;
-            quoteEnd = strchr(lsbStart, '"');
-            if (quoteEnd) {
-               *quoteEnd = '\0';
-            }
-         }
-         Str_Strcpy(distro, lsbStart, distroSize);
-         free(lsbOutput);
-      }
-
-      HostinfoGetOSShortName(distro, distroShort, distroSize);
-
-      if (strlen(distro) + strlen(osNameFull) + 2 > sizeof osNameFull) {
-         Warning("%s: Error: buffer too small\n", __FUNCTION__);
-
-         return FALSE;
-      }
-
-      Str_Strcat(osNameFull, " ", sizeof osNameFull);
-      Str_Strcat(osNameFull, distro, sizeof osNameFull);
-
       if (strlen(distroShort) + 1 > sizeof osName) {
          Warning("%s: Error: buffer too small\n", __FUNCTION__);
ravindravmw commented 8 years ago

Thanks for the report. I have reported an internal bug to track it.

Could you please help with details of the Linux distro that we can use to reproduce this issue ourselves? This will also be helpful to test/verify any fixes we make for this.

drvink commented 8 years ago

I'm seeing this on a 64-bit Arch install. Arch doesn't explicitly make releases, so I can't direct you to a specific version to try, but an up-to-date install should allow you to reproduce the issue. If there are any other details you need to know, please specify and I'll be happy to provide them.

rubin55 commented 8 years ago

Hey, I just ran into this using a NetBSD 6.1 VM with openvmtools installed.

cormite commented 8 years ago

I can confirm I see the same issue in ESXi (build 2809209): Unable to convert Vigor value 'Gentoo-64' of type 'char const*' to VIM type 'Vim::Vm::GuestOsDescriptor::GuestOsIdentifier'

flynmooney commented 6 years ago

Centos 6 & 7. OracleLinux 6 & 7. ESX 6.0 (5572656)

a13xchan commented 6 years ago

I figured out that somehow the vmx file on vmware was being configured to use a guestOS only compatible with 6.5 when running ESXi hosts 4,5 or 6 (not 6.5). i reconfigured the vmx to fix this issue, open vm tools had no further issues reporting. the vmx can be reloaded without vm shutdown

xaaron commented 6 years ago

I was able to resolve this on Arch Linux (Antergos) by doing the following. I did not have my server name and IP nor the localhost defined in /etc/hosts. Verify that the /etc/hosts file is written correctly and has entries similar to

127.0.0.1 localhost localhost.local 10.0.0.1 myHostname myHostname.myDomain

splitbrained commented 6 years ago

@a13xchan what was the setting in the VMX file that you changed?

a13xchan commented 6 years ago

@splitbrained for me and cent os it was the guestOS field in the vmx. I ran at the time vSphere 6 and had yet to upgrade to 6.5 all the cent os vms i created for some strange reason had the guest os set to centos6-64 which is an unsupported guest os config in vSphere 6. centos6-64 is used in 6.5. I changed this to guestOS = "centos-64" which is supported in vSphere 6 and this corrected it.

I corrected it also on a few other linux distro who was configured as guestOS = ... to something not supported by that version of vSphere. There is a difference to what you configure in the vmx file to what the tools detects as the running OS.

This will obviously if you run tools/scripts to make sure that the guestos matches the actual guest os detected by tools flag up inconsistencies but it will not spam the log files/ syslog with "Unable to convert Vigor ...".