Example #1
0
static HgfsSuperInfo *
HgfsInitSuperInfo(HgfsMountInfo *mountInfo) // IN: Passed down from the user
{
   HgfsSuperInfo *si = NULL;
   int result = 0;
   int len;
   char *tmpName;
   Bool hostValid;

   si = kmalloc(sizeof *si, GFP_KERNEL);
   if (!si) {
      result = -ENOMEM;
      goto out2;
   }

   /*
    * If the mounter specified a uid or gid, we will prefer them over any uid
    * or gid given to us by the server.
    */
   si->uidSet = mountInfo->uidSet;
   if (si->uidSet) {
      si->uid = mountInfo->uid;
   } else {
      si->uid = current_uid();
   }
   si->gidSet = mountInfo->gidSet;
   if (si->gidSet) {
      si->gid = mountInfo->gid;
   } else {
      si->gid = current_gid();
   }
   si->fmask = mountInfo->fmask;
   si->dmask = mountInfo->dmask;
   si->ttl = mountInfo->ttl * HZ; // in ticks

   /*
    * We don't actually care about this field (though we may care in the
    * future). For now, just make sure it is set to ".host" as a sanity check.
    *
    * We can't call getname() directly because on certain kernels we can't call
    * putname() directly.  For more details, see the change description of
    * change 464782 or the second comment in bug 159623, which fixed the same
    * problem for vmblock.
    */
   tmpName = compat___getname();
   if (!tmpName) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: could not obtain "
              "memory for filename\n"));
      result = -ENOMEM;
      goto out2;
   }

   len = strncpy_from_user(tmpName, mountInfo->shareNameHost, PATH_MAX);
   if (len < 0 || len >= PATH_MAX) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
              "on host string failed\n"));
      result = len < 0 ? len : -ENAMETOOLONG;
      goto out;
   }

   hostValid = strcmp(tmpName, ".host") == 0;
   if (!hostValid) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: host string is "
              "invalid\n"));
      result = -EINVAL;
      goto out;
   }

   /*
    * Perform a simple sanity check on the directory portion: it must begin
    * with forward slash.
    */
   len = strncpy_from_user(tmpName, mountInfo->shareNameDir, PATH_MAX);
   if (len < 0 || len >= PATH_MAX) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
              "on dir string failed\n"));
      result = len < 0 ? len : -ENAMETOOLONG;
      goto out;
   }

   if (*tmpName != '/') {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: dir string is "
              "invalid\n"));
      result = -EINVAL;
      goto out;
   }

   /*
    * The SELinux audit subsystem will delay the putname() of a string until
    * the end of a system call so that it may be audited at any point. At that
    * time, it also unconditionally calls putname() on every string allocated
    * by getname().
    *
    * This means we can't safely retain strings allocated by getname() beyond
    * the syscall boundary. So after getting the string, use kstrdup() to
    * duplicate it, and store that (audit-safe) result in the SuperInfo struct.
    */
   si->shareName = compat_kstrdup(tmpName, GFP_KERNEL);
   if (si->shareName == NULL) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: kstrdup on "
              "dir string failed\n"));
      result = -ENOMEM;
      goto out;
   }
   si->shareNameLen = strlen(si->shareName);

  out:
   compat___putname(tmpName);
  out2:
   if (result) {
      /* If we failed, si->shareName couldn't have been allocated. */
      kfree(si);
      si = ERR_PTR(result);
   }
   return si;
}
Example #2
0
static HgfsSuperInfo *
HgfsInitSuperInfo(void *rawData,            // IN: Passed down from the user
                  uint32 mountInfoVersion)  // IN: version
{
   HgfsSuperInfo *si = NULL;
   int result = 0;
   int len;
   char *tmpName = NULL;
   Bool hostValid;
   uint32 mntFlags = 0;
   uint32 ttl = 0;
   uid_t uid = 0;
   gid_t gid = 0;
   mode_t fmask = 0;
   mode_t dmask = 0;
   const char *shareHost;
   const char *shareDir;

   si = kmalloc(sizeof *si, GFP_KERNEL);
   if (!si) {
      result = -ENOMEM;
      goto out_error_si;
   }
   memset(si, 0, sizeof *si);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
   result = bdi_setup_and_register(&si->bdi, HGFS_NAME);
   if (result) {
      LOG(6, (KERN_DEBUG "VMware hgfs: %s: initialize backing device info"
              "failed. (%d)\n", __func__, result));
      goto out_error_si;
   }
#endif

   result = HgfsGetMountInfo(rawData,
                             mountInfoVersion,
                             &mntFlags,
                             &ttl,
                             &uid,
                             &gid,
                             &fmask,
                             &dmask,
                             &shareHost,
                             &shareDir);
   if (result < 0) {
      LOG(6, (KERN_DEBUG LGPFX "%s: error: get mount info %d\n", __func__, result));
      goto out_error_last;
   }

   /*
    * Initialize with the default flags.
    */
   si->mntFlags = mntFlags;

   si->uid = current_uid();
   if ((si->mntFlags & HGFS_MNT_SET_UID) != 0) {
      kuid_t mntUid = make_kuid(current_user_ns(), uid);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
      if (uid_valid(mntUid))
#endif
         si->uid = mntUid;
   }

   si->gid = current_gid();
   if ((si->mntFlags & HGFS_MNT_SET_GID) != 0) {
      kgid_t mntGid = make_kgid(current_user_ns(), gid);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
      if (gid_valid(mntGid))
#endif
         si->gid = mntGid;
   }
   si->fmask = fmask;
   si->dmask = dmask;
   si->ttl = ttl * HZ; // in ticks

   /*
    * We don't actually care about this field (though we may care in the
    * future). For now, just make sure it is set to ".host" as a sanity check.
    *
    * We can't call getname() directly because on certain kernels we can't call
    * putname() directly.  For more details, see the change description of
    * change 464782 or the second comment in bug 159623, which fixed the same
    * problem for vmblock.
    */
   tmpName = compat___getname();
   if (!tmpName) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: could not obtain "
              "memory for filename\n"));
      result = -ENOMEM;
      goto out_error_last;
   }

   len = strncpy_from_user(tmpName, shareHost, PATH_MAX);
   if (len < 0 || len >= PATH_MAX) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
              "on host string failed\n"));
      result = len < 0 ? len : -ENAMETOOLONG;
      goto out_error_last;
   }

   hostValid = strcmp(tmpName, ".host") == 0;
   if (!hostValid) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: host string is "
              "invalid\n"));
      result = -EINVAL;
      goto out_error_last;
   }

   /*
    * Perform a simple sanity check on the directory portion: it must begin
    * with forward slash.
    */
   len = strncpy_from_user(tmpName, shareDir, PATH_MAX);
   if (len < 0 || len >= PATH_MAX) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: strncpy_from_user "
              "on dir string failed\n"));
      result = len < 0 ? len : -ENAMETOOLONG;
      goto out_error_last;
   }

   if (*tmpName != '/') {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: dir string is "
              "invalid\n"));
      result = -EINVAL;
      goto out_error_last;
   }

   /*
    * The SELinux audit subsystem will delay the putname() of a string until
    * the end of a system call so that it may be audited at any point. At that
    * time, it also unconditionally calls putname() on every string allocated
    * by getname().
    *
    * This means we can't safely retain strings allocated by getname() beyond
    * the syscall boundary. So after getting the string, use kstrdup() to
    * duplicate it, and store that (audit-safe) result in the SuperInfo struct.
    */
   si->shareName = compat_kstrdup(tmpName, GFP_KERNEL);
   if (si->shareName == NULL) {
      LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInitSuperInfo: kstrdup on "
              "dir string failed\n"));
      result = -ENOMEM;
      goto out_error_last;
   }
   si->shareNameLen = strlen(si->shareName);

out_error_last:
   if (tmpName) {
      compat___putname(tmpName);
   }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
   if (result) {
      bdi_destroy(&si->bdi);
   }
#endif
out_error_si:
   if (result) {
      kfree(si);
      si = ERR_PTR(result);
   }

   return si;
}