free(buffer);
buffer = NULL;
- if (errno != ENAMETOOLONG) {
+ if (errno != ERANGE) {
break;
}
}
+#if defined(VMX86_SERVER)
+/*
+ *----------------------------------------------------------------------------
+ *
+ * FileVMFSGetCanonicalPath --
+ *
+ * Given an absolute pathname of a VM directory, return its canonical
+ * pathname.
+ *
+ * Canonical name for a VM directory has a special significance only for
+ * the case of NFS config VVols where the absolute pathname of VM directory
+ * could be an NFS PE based path.
+ * f.e. the VM directory on an NFS config VVol could have the absolute
+ * pathname /vmfs/volumes/nfs_pe_2/vvol36/meta_vvol36/, whereas the
+ * canonical name would be the one containing the VVol container name,
+ * f.e. /vmfs/volumes/vvol:26acd2ae55ea49c3-87dd47a44e4f327/rfc4122.d140c97a-7208-474e-95c7-a4ee6cac7f15/
+ * Both pathnames refer to the same directory (using bind mount), but
+ * canonical pathname is important as it is used in many places to identify
+ * object-backed storage from regular filesystem-backed storage.
+ *
+ * It can also correctly handle cases where 'absVMDirName' is not the
+ * config-vvol directory but is a sub-directory inside the config-vvol
+ * directory. It will climb up one directory at a time looking for an
+ * NFS config VVol. The max number of directory components it'll check
+ * is MAX_SUBDIR_LEVEL.
+ *
+ * Note:
+ * 'absVMDirName' should not have extra slashes in the name. This will
+ * be true if we have gotten it from Posix_RealPath or friends.
+ *
+ * Results:
+ * Returns a unicode string containing the canonical pathname to use.
+ * For VM directories not on NFS config VVol, this will be the same as
+ * absVMDirName.
+ * Caller has to free the returned unicode string using Unicode_Free.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Unicode
+FileVMFSGetCanonicalPath(ConstUnicode absVMDirName) // IN
+{
+ /*
+ * Max directory level that we will climb looking for an NFS config VVol.
+ * Don't set it very high or else we will hurt the common case.
+ */
+#define MAX_SUBDIR_LEVEL 1
+
+ struct statfs statfs_buf;
+ VVol_IoctlArgs args;
+ VVolGetNFSCanonicalPathArgs *getCanonArgs = NULL;
+ int ctrlfd = -1;
+ int searchDepth = MAX_SUBDIR_LEVEL;
+ /*
+ * Directory that we are currently verifying. This starts as
+ * absVMDirName and then keeps climbing to the parent one level
+ * at a time, till we exhaust searchDepth or we get a successful
+ * translation, indicating that we have hit an NFS config vvol
+ * directory, or we run outside the NFS filesystem.
+ */
+ Unicode currDir = NULL;
+ /*
+ * This holds the path fragment after the NFS config VVol. This will be
+ * non-empty only in the case when absVMDirName refers to some subdir
+ * inside the NFS config VVol directory. We keep collecting the path
+ * components as we change currDir one level at a time.
+ */
+ Unicode dirPath = NULL;
+ Unicode canonPath = NULL; /* result */
+
+ /*
+ * absVMDirName should start with /vmfs/volumes/.
+ */
+ if (!Unicode_StartsWith(absVMDirName, VCFS_MOUNT_PATH)) {
+ goto use_same_path;
+ }
+
+ /*
+ * Only NFS config vvols can have a canonical name different from the
+ * absolute pathname provided. This will do the validity check also.
+ */
+ if (Posix_Statfs(absVMDirName, &statfs_buf) != 0 ||
+ (statfs_buf.f_type != NFSCLIENT_FSTYPENUM &&
+ statfs_buf.f_type != NFS41CLIENT_FSTYPENUM)) {
+ goto use_same_path;
+ }
+
+ /*
+ * The most likely reason this will fail is if the VVol control node is
+ * not present which means VVol module is not loaded. We can not translate
+ * the pathname in that case.
+ */
+ ctrlfd = Posix_Open(VVOL_NAMESPACE_CONTROL_NODE, O_RDONLY);
+ if (ctrlfd < 0) {
+ goto use_same_path;
+ }
+
+ /*
+ * If the user has passed a filename (instead of a dirname) we
+ * cannot pass it as-is to the ioctl as it works on a directory
+ * name.
+ */
+ if (!File_IsDirectory(absVMDirName)) {
+ File_GetPathName(absVMDirName, &currDir, &dirPath);
+ ASSERT(currDir);
+ ASSERT(dirPath);
+ }
+
+ /*
+ * VM directory is on an NFS fileystem. It could be a regular NFS filesystem
+ * backed storage or an NFS config VVol. We need to check.
+ */
+ getCanonArgs = Util_SafeCalloc(1, sizeof(*getCanonArgs));
+
+ args.type = VVOL_GET_NFS_CANONICAL_PATH;
+ args.data = (uint64)(VA) getCanonArgs;
+ args.length = sizeof(*getCanonArgs);
+
+ /*
+ * Start searching for the NFS config VVol starting from absVMDirName
+ * (or currDir, if absVMDirName is not a directory).
+ * In most case this will be the NFS config VVol directory, but we also
+ * support cases where absVMDirName refers to a subdir inside the NFS
+ * config VVol directory.
+ */
+ do {
+ Unicode pathname, basename;
+
+ Unicode_CopyBytes(getCanonArgs->absNFSPath,
+ currDir ? : absVMDirName,
+ sizeof(getCanonArgs->absNFSPath),
+ NULL, STRING_ENCODING_UTF8);
+
+ if (ioctl(ctrlfd, IOCTLCMD_VMFS_VVOL, &args) == 0) {
+ /*
+ * ioctl successful. currDir refers to an NFS config VVol directory.
+ * getCanonArgs->canonPath contains the canonical path to use.
+ * This is the fastpath.
+ */
+ break;
+ } else if (errno != ENOENT) {
+ /*
+ * ENOENT indicates that the kernel did not find a matching bind
+ * mount. In that case we try climbing up one level and test that
+ * for an NFS config VVol.
+ */
+ goto use_same_path;
+ }
+
+ if (searchDepth == 0) {
+ goto use_same_path;
+ }
+ /*
+ * Try the next level dir.
+ */
+ File_GetPathName(currDir ? : absVMDirName, &pathname, &basename);
+ Unicode_Free(currDir);
+ currDir = pathname;
+ /*
+ * Update dirPath that we eventually need to append to get the full path.
+ */
+ if (dirPath == NULL) {
+ dirPath = basename;
+ } else {
+ Unicode tmpDirPath = Unicode_Join(basename, DIRSEPS, dirPath, NULL);
+ Unicode_Free(basename);
+ Unicode_Free(dirPath);
+ dirPath = tmpDirPath;
+ }
+ /*
+ * If we have fallen off the NFS filesystem no need to search further,
+ * we can never find the config VVol.
+ */
+ if (Posix_Statfs(currDir, &statfs_buf) != 0 ||
+ (statfs_buf.f_type != NFSCLIENT_FSTYPENUM &&
+ statfs_buf.f_type != NFS41CLIENT_FSTYPENUM)) {
+ goto use_same_path;
+ }
+ } while (searchDepth-- > 0);
+
+ canonPath = Unicode_Format("%s%s", getCanonArgs->canonPath, dirPath ? : "");
+
+done:
+ close(ctrlfd);
+ free(getCanonArgs);
+ Unicode_Free(currDir);
+ Unicode_Free(dirPath);
+ ASSERT(canonPath != NULL);
+ return canonPath;
+
+use_same_path:
+ ASSERT(canonPath == NULL);
+ canonPath = Unicode_Alloc(absVMDirName, STRING_ENCODING_DEFAULT);
+ goto done;
+}
+#endif
+
+
/*
*----------------------------------------------------------------------
*
{
Unicode cwd;
Unicode ret;
+#if defined(VMX86_SERVER)
+ Unicode canonPath;
+#endif
if ((pathName != NULL) && File_IsFullPath(pathName)) {
cwd = NULL;
Unicode_Free(cwd);
+#if defined(VMX86_SERVER)
+ /*
+ * NFS config-VVols introduce a special type of in-kernel link called the
+ * bind mount. Posix_RealPath() doesn't resolve that. We need to resolve
+ * it explicitly.
+ * We don't want to store PE based path in any file. All configuration
+ * files should contain canonical path only.
+ */
+ canonPath = FileVMFSGetCanonicalPath(ret);
+ Unicode_Free(ret);
+
+ return canonPath;
+#else
return ret;
+#endif
}
Unicode pattern;
Unicode tmpDir = NULL;
Unicode *fileList = NULL;
-
+
/*
* We always use the pattern PRODUCT-USER-xxxx when creating
* alternative safe temp directories, so check for ones with
* those names and the appropriate permissions.
*/
-
+
pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName);
if (pattern == NULL) {
return NULL;
char *tmpDir = NULL;
while (TRUE) {
- unsigned int suffix;
-
- /*
- * We use a crypographically strong random number which is overkill
- * for this purpose but makes it slightly more likely that we will
- * create an unused name than if we had simply tried suffixes in
- * numeric order.
+ /*
+ * We use a random number that makes it more likely that we will create
+ * an unused name than if we had simply tried suffixes in numeric order.
*/
- if (!Random_Crypto(sizeof(suffix), &suffix)) {
- Warning("%s: Call to Random_Crypto failed.\n", __FUNCTION__);
- break;
- }
-
tmpDir = Str_Asprintf(NULL, "%s%s%s-%s-%u", baseTmpDir, DIRSEPS,
- PRODUCT_GENERIC_NAME_LOWER, userName, suffix);
-
+ PRODUCT_GENERIC_NAME_LOWER, userName,
+ FileSimpleRandom());
+
if (!tmpDir) {
Warning("%s: Out of memory error.\n", __FUNCTION__);
break;
}
-
+
if (FileAcceptableSafeTmpDir(tmpDir, userId)) {
break;
}
-
+
if (++curDirIter > MAX_DIR_ITERS) {
Warning("%s: Failed to create a safe temporary directory, path "
"\"%s\". The maximum number of attempts was exceeded.\n",
tmpDir = NULL;
break;
}
-
+
free(tmpDir);
tmpDir = NULL;
}
*
* Return a safe temporary directory (i.e. a temporary directory which
* is not prone to symlink attacks, because it is only writable by the
- * current effective user). Guaranteed to return the same directory
- * every time it is called during the lifetime of the current process
- * (unless that directory is deleted while the process is running).
+ * current effective user).
+ *
+ * Guaranteed to return the same directory every time it is
+ * called during the lifetime of the current process, for the
+ * current effective user ID. (Barring the user manually deleting
+ * or renaming the directory.)
*
* Results:
* The allocated directory path on success.
/* We don't have a useable temporary dir, create one. */
baseTmpDir = FileGetTmpDir(useConf);
-
+
if (!baseTmpDir) {
Warning("%s: FileGetTmpDir failed.\n", __FUNCTION__);
goto exit;
}
-
+
userName = FileGetUserName(userId);
-
+
if (!userName) {
Warning("%s: FileGetUserName failed, using numeric ID "
"as username instead.\n", __FUNCTION__);
-
+
/* Fallback on just using the userId as the username. */
userName = Str_Asprintf(NULL, "uid-%d", userId);
-
+
if (!userName) {
Warning("%s: Str_Asprintf error.\n", __FUNCTION__);
goto exit;
}
}
-
+
tmpDir = Str_Asprintf(NULL, "%s%s%s-%s", baseTmpDir, DIRSEPS,
PRODUCT_GENERIC_NAME_LOWER, userName);
-
+
if (!tmpDir) {
Warning("%s: Out of memory error.\n", __FUNCTION__);
goto exit;
HgfsServerSessionReceive(HgfsPacket *packet, // IN: Hgfs Packet
void *clientData) // IN: session info
{
- HgfsTransportSessionInfo *transportSession = (HgfsTransportSessionInfo *)clientData;
+ HgfsTransportSessionInfo *transportSession = clientData;
HgfsInternalStatus status;
HgfsInputParam *input = NULL;
static void
HgfsServerSessionDisconnect(void *clientData) // IN: session context
{
- HgfsTransportSessionInfo *transportSession = (HgfsTransportSessionInfo *)clientData;
+ HgfsTransportSessionInfo *transportSession = clientData;
DblLnkLst_Links *curr, *next;
LOG(8, ("%s: entered\n", __FUNCTION__));
static void
HgfsServerSessionClose(void *clientData) // IN: session context
{
- HgfsTransportSessionInfo *transportSession = (HgfsTransportSessionInfo *)clientData;
+ HgfsTransportSessionInfo *transportSession = clientData;
ASSERT(transportSession);
ASSERT(transportSession->state == HGFS_SESSION_STATE_CLOSED);
HgfsServerSessionSendComplete(HgfsPacket *packet, // IN/OUT: Hgfs packet
void *clientData) // IN: session info
{
- HgfsTransportSessionInfo *transportSession =
- (HgfsTransportSessionInfo *)clientData;
+ HgfsTransportSessionInfo *transportSession = clientData;
if (packet->guestInitiated) {
HSPU_PutMetaPacket(packet, transportSession);
HgfsServerSessionInvalidateObjects(void *clientData, // IN:
DblLnkLst_Links *shares) // IN: List of new shares
{
- HgfsTransportSessionInfo *transportSession =
- (HgfsTransportSessionInfo *)clientData;
+ HgfsTransportSessionInfo *transportSession = clientData;
DblLnkLst_Links *curr;
ASSERT(transportSession);
uint32
HgfsServerSessionInvalidateInactiveSessions(void *clientData) // IN:
{
- HgfsTransportSessionInfo *transportSession =
- (HgfsTransportSessionInfo *)clientData;
+ HgfsTransportSessionInfo *transportSession = clientData;
uint32 numActiveSessionsLeft = 0;
DblLnkLst_Links shares, *curr, *next;
void *clientData) // IN: From request
{
HgfsReplyServerLockChange *reply;
- ServerLockData *lockData;
+ ServerLockData *lockData = clientData;
+
ASSERT(packetIn);
ASSERT(clientData);
return;
}
reply = (HgfsReplyServerLockChange *)packetIn;
- lockData = (ServerLockData *)clientData;
/*
* XXX: It should be safe to ignore the status and id from the actual
LOGLEVEL_VAR(inputdevtap), \
LOGLEVEL_VAR(objlib), \
LOGLEVEL_VAR(vsanobj), \
+ LOGLEVEL_VAR(vvolbe), \
LOGLEVEL_VAR(svgadevtap), \
LOGLEVEL_VAR(masReceipt), /* lib/masReceipt */ \
LOGLEVEL_VAR(serviceImpl), /* lib/serviceImpl */ \
#include "vm_basic_types.h"
-Bool
-Random_Crypto(unsigned int size, // IN
- void *buffer); // OUT
+Bool Random_Crypto(size_t size,
+ void *buffer);
/*
* High quality - research grade - random number generator.
typedef struct rqContext rqContext;
-rqContext *
-Random_QuickSeed(uint32 seed);
+rqContext *Random_QuickSeed(uint32 seed);
-uint32
-Random_Quick(rqContext *context);
+uint32 Random_Quick(rqContext *context);
/*
- * Simple multiplicative conguential RNG.
+ * Simple multiplicative congruential RNG.
*/
-int
-Random_Simple(int seed);
+int Random_Simple(int seed);
#endif /* __RANDOM_H__ */
#ifdef __GNUC__
#ifndef sun
-static INLINE_SINGLE_CALLER uintptr_t
-GetFrameAddr(void)
-{
- uintptr_t bp;
-#if !(__GNUC__ == 4 && (__GNUC_MINOR__ == 0 || __GNUC_MINOR__ == 1))
- bp = (uintptr_t)__builtin_frame_address(0);
-#else
- /*
- * We use this assembly hack due to a bug discovered in gcc 4.1.1.
- * The bug was fixed in 4.2.0; assume it originated with 4.0.
- * PR147638, PR554369.
- */
- __asm__ __volatile__(
-# if defined(VM_X86_64)
- "movq %%rbp, %0\n"
-# else
- "movl %%ebp, %0\n"
-# endif
- : "=g" (bp));
-#endif
- return bp;
-}
-
-
/*
- * Returns the frame pointer of the calling function.
- * Equivalent to __builtin_frame_address(1).
+ * A bug in __builtin_frame_address was discovered in gcc 4.1.1, and
+ * fixed in 4.2.0; assume it originated in 4.0. PR 147638 and 554369.
*/
-static INLINE_SINGLE_CALLER uintptr_t
-GetCallerFrameAddr(void)
-{
- return *(uintptr_t*)GetFrameAddr();
-}
+#if !(__GNUC__ == 4 && (__GNUC_MINOR__ == 0 || __GNUC_MINOR__ == 1))
+#define GetFrameAddr() __builtin_frame_address(0)
+#endif
#endif // sun
#endif // __GNUC__
syndrome = Atomic_Read(&syndromeMem);
if (syndrome == 0) {
- uint32 retries = 25;
-
- /*
- * Do not assume that the source of bits from the host OS are sane.
- * Perhaps its random bits service is not working or always returns
- * zero or something is misconfigured. Only perform a small number
- * of retries attempting to appropriate the required bits.
- */
-
- do {
- /* Only changes syndrome on success. No need to check for errors */
- Random_Crypto(sizeof syndrome, &syndrome);
-
- if (syndrome != 0) {
- break;
- }
- } while (retries--);
-
- /*
- * If the source was unable to provide the appropriate bits, switch
- * to plan B.
- */
-
- if (syndrome == 0) {
#if defined(_WIN32)
- syndrome = GetTickCount();
+ syndrome = GetTickCount();
#else
- syndrome = time(NULL) & 0xFFFFFFFF;
+ syndrome = time(NULL) & 0xFFFFFFFF;
#endif
- }
/*
* Protect against a total failure.
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#if defined(_WIN32)
# include <windows.h>
#include "vmware.h"
#include "random.h"
+#include "util.h"
#if defined(_WIN32)
*/
static Bool
-RandomBytesWin32(unsigned int size, // IN:
- void *buffer) // OUT:
+RandomBytesWin32(size_t size, // IN:
+ void *buffer) // OUT:
{
HCRYPTPROV csp;
+ if (size != (DWORD) size) {
+ return FALSE;
+ }
+
if (CryptAcquireContext(&csp, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT) == FALSE) {
return FALSE;
}
- if (CryptGenRandom(csp, size, buffer) == FALSE) {
+ if (CryptGenRandom(csp, (DWORD) size, buffer) == FALSE) {
CryptReleaseContext(csp, 0);
return FALSE;
}
*/
static Bool
-RandomBytesPosix(const char *name, // IN:
- unsigned int size, // IN:
- void *buffer) // OUT:
+RandomBytesPosix(const char *name, // IN:
+ size_t size, // IN:
+ void *buffer) // OUT:
{
int fd = open(name, O_RDONLY);
if (fd == -1) {
+ Log("%s: failed to open %s: %s\n", __FUNCTION__, name, strerror(errno));
return FALSE;
}
- /* Although /dev/urandom does not block, it can return short reads. */
+ /*
+ * Although /dev/urandom does not block, it can return short reads. That
+ * said, reads returning nothing should not happen. Just in case, track
+ * those any that do appear.
+ */
while (size > 0) {
ssize_t bytesRead = read(fd, buffer, size);
if ((bytesRead == 0) || ((bytesRead == -1) && (errno != EINTR))) {
close(fd);
+ if (bytesRead == 0) {
+ Log("%s: zero length read while reading from %s\n",
+ __FUNCTION__, name);
+ } else {
+ Log("%s: %"FMTSZ"u byte read failed while reading from %s: %s\n",
+ __FUNCTION__, size, name, strerror(errno));
+ }
+
return FALSE;
}
}
if (close(fd) == -1) {
- return FALSE;
+ Log("%s: failed to close %s: %s\n", __FUNCTION__, name, strerror(errno));
}
return TRUE;
*/
Bool
-Random_Crypto(unsigned int size, // IN:
- void *buffer) // OUT:
+Random_Crypto(size_t size, // IN:
+ void *buffer) // OUT:
{
#if defined(_WIN32)
return RandomBytesWin32(size, buffer);
0x512C0C03, 0xEA857CCD, 0x4CC1D30F, 0x8891A8A1, 0xA6B7AADB
};
- rs = (struct rqContext *) malloc(sizeof *rs);
+ rs = (struct rqContext *) Util_SafeMalloc(sizeof *rs);
if (rs != NULL) {
uint32 i;
ETH_VMWARE_FRAME_TYPE_BEACON = 1,
ETH_VMWARE_FRAME_TYPE_COLOR = 2,
ETH_VMWARE_FRAME_TYPE_ECHO = 3,
+ ETH_VMWARE_FRAME_TYPE_LLC = 4, // XXX: Just re-use COLOR?
};
typedef
#define VMNET_CAP_SELF_TEST 0x100000000000UL /* Self-test capability */
#define VMNET_CAP_PAUSE_PARAMS 0x200000000000UL /* Pause frame parameter adjusting */
#define VMNET_CAP_RESTART_NEG 0x400000000000UL /* Ability to restart negotiation of link speed/duplexity */
+#define VMNET_CAP_LRO 0x800000000000UL /* Hardware supported LRO */
#define VMNET_CAP_LEGACY 0x8000000000000000UL /* Uplink is compatible with vmklinux drivers */
#endif // _VMNET_DEF_H_