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; }
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; }