diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index a7f0ff5d74f5..2a51d584ad56 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -442,6 +442,13 @@ BOOL PALAPI PAL_NotifyRuntimeStarted(VOID); +#ifdef __APPLE__ +PALIMPORT +LPCSTR +PALAPI +PAL_GetApplicationGroupId(); +#endif // __APPLE__ + static const int MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH = MAX_PATH; PALIMPORT diff --git a/src/pal/src/include/pal/palinternal.h b/src/pal/src/include/pal/palinternal.h index 0e37ba84c0e4..a66ef7e18edb 100644 --- a/src/pal/src/include/pal/palinternal.h +++ b/src/pal/src/include/pal/palinternal.h @@ -622,6 +622,8 @@ function_name() to call the system's implementation we'll catch any definition conflicts */ #include +#include + #if !HAVE_INFTIM #define INFTIM -1 #endif // !HAVE_INFTIM @@ -631,6 +633,8 @@ function_name() to call the system's implementation #undef assert #define assert (Use__ASSERTE_instead_of_assert) assert +#define string_countof(a) (sizeof(a) / sizeof(a[0]) - 1) + #ifndef __ANDROID__ #define TEMP_DIRECTORY_PATH "/tmp/" #else @@ -641,6 +645,16 @@ function_name() to call the system's implementation #define PROCESS_PIPE_NAME_PREFIX ".dotnet-pal-processpipe" +#ifdef __APPLE__ +#define APPLICATION_CONTAINER_BASE_PATH_SUFFIX "/Library/Group Containers/" + +// Not much to go with, but Max semaphore length on Mac is 31 characters. In a sandbox, the semaphore name +// must be prefixed with an application group ID. This will be 10 characters for developer ID and extra 2 +// characters for group name. For example ABCDEFGHIJ.MS. We still need some characters left +// for the actual semaphore names. +#define MAX_APPLICATION_GROUP_ID_LENGTH 13 +#endif // __APPLE__ + #ifdef __cplusplus extern "C" { @@ -664,6 +678,11 @@ typedef enum _TimeConversionConstants bool ReadMemoryValueFromFile(const char* filename, size_t* val); +#ifdef __APPLE__ +bool +GetApplicationContainerFolder(PathCharString& buffer, const char *applicationGroupId, int applicationGroupIdLength); +#endif // __APPLE__ + /* This is duplicated in utilcode.h for CLR, with cooler type-traits */ template inline diff --git a/src/pal/src/include/pal/process.h b/src/pal/src/include/pal/process.h index f5d8b46de660..4eccc6189f8a 100644 --- a/src/pal/src/include/pal/process.h +++ b/src/pal/src/include/pal/process.h @@ -24,6 +24,7 @@ Revision History: #define _PAL_PROCESS_H_ #include "pal/palinternal.h" +#include "pal/stackstring.hpp" #ifdef __cplusplus extern "C" @@ -43,6 +44,13 @@ extern DWORD gSID; extern LPWSTR pAppDir; +// The Mac sandbox application group ID (if exists) and container (shared) path +#ifdef __APPLE__ +extern LPCSTR gApplicationGroupId; +extern int gApplicationGroupIdLength; +#endif // __APPLE__ +extern PathCharString *gSharedFilesPath; + /*++ Function: PROCGetProcessIDFromHandle diff --git a/src/pal/src/include/pal/sharedmemory.h b/src/pal/src/include/pal/sharedmemory.h index fdc395e3c6df..3ea3b711826c 100644 --- a/src/pal/src/include/pal/sharedmemory.h +++ b/src/pal/src/include/pal/sharedmemory.h @@ -15,46 +15,45 @@ #define _countof(a) (sizeof(a) / sizeof(a[0])) #endif // !_countof -// The temporary folder is used for storing shared memory files and their lock files. -// The location of the temporary folder varies (e.g. /data/local/tmp on Android) -// and is set in TEMP_DIRECTORY_PATH. TEMP_DIRECTORY_PATH ends with '/' +// The folder used for storing shared memory files and their lock files is defined in +// the gSharedFilesPath global variable. The value of the variable depends on which +// OS is being used, and if the application is running in a sandbox in Mac. +// gSharedFilesPath ends with '/' // - Global shared memory files go in: -// {tmp}/.dotnet/shm/global/ +// {gSharedFilesPath}/.dotnet/shm/global/ // - Session-scoped shared memory files go in: -// {tmp}/.dotnet/shm/session/ +// {gSharedFilesPath}/.dotnet/shm/session/ // - Lock files associated with global shared memory files go in: -// {tmp}/.dotnet/lockfiles/global/ +// {gSharedFilesPath}/.dotnet/lockfiles/global/ // - Lock files associated with session-scoped shared memory files go in: -// {tmp}/.dotnet/lockfiles/session/ +// {gSharedFilesPath}/.dotnet/lockfiles/session/ #define SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT (_MAX_FNAME - 1) -#define SHARED_MEMORY_MAX_NAME_CHAR_COUNT (_countof("Global\\") - 1 + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT) +#define SHARED_MEMORY_MAX_NAME_CHAR_COUNT (string_countof("Global\\") + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT) -#define SHARED_MEMORY_TEMP_DIRECTORY_PATH TEMP_DIRECTORY_PATH -#define SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH TEMP_DIRECTORY_PATH ".dotnet" - -#define SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH TEMP_DIRECTORY_PATH ".dotnet/shm" -#define SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH TEMP_DIRECTORY_PATH ".dotnet/lockfiles" -static_assert_no_msg(_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) >= _countof(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH)); +#define SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_NAME ".dotnet" +#define SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_NAME ".dotnet/shm" +#define SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME ".dotnet/lockfiles" +static_assert_no_msg(_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME) >= _countof(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_NAME)); #define SHARED_MEMORY_GLOBAL_DIRECTORY_NAME "global" #define SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX "session" static_assert_no_msg(_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) >= _countof(SHARED_MEMORY_GLOBAL_DIRECTORY_NAME)); -#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE TEMP_DIRECTORY_PATH ".coreclr.XXXXXX" +#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE ".coreclr.XXXXXX" #define SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT (10) +// Note that this Max size does not include the prefix folder path size which is unknown (in the case of sandbox) until runtime #define SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT \ ( \ - _countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) - 1 + \ + string_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME) + \ 1 /* path separator */ + \ - _countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) - 1 + \ + string_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) + \ SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT + \ 1 /* path separator */ + \ SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT \ ) -static_assert_no_msg(SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1 /* null terminator */ <= MAX_LONGPATH); class AutoFreeBuffer { @@ -107,9 +106,9 @@ class SharedMemoryHelpers static void *Alloc(SIZE_T byteCount); - template static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, const char (&source)[SourceByteCount]); - template static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, LPCSTR source, SIZE_T sourceCharCount); - template static SIZE_T AppendUInt32String(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, UINT32 value); + template static void BuildSharedFilesPath(PathCharString& destination, const char (&suffix)[SuffixByteCount]); + static void BuildSharedFilesPath(PathCharString& destination, const char *suffix, int suffixByteCount); + static bool AppendUInt32String(PathCharString& destination, UINT32 value); static bool EnsureDirectoryExists(const char *path, bool isGlobalLockAcquired, bool createIfNotExist = true, bool isSystemDirectory = false); private: @@ -126,6 +125,12 @@ class SharedMemoryHelpers static bool TryAcquireFileLock(int fileDescriptor, int operation); static void ReleaseFileLock(int fileDescriptor); + + static void VerifyStringOperation(bool success); + static void VerifyStringOperation(BOOL success) + { + VerifyStringOperation(success != FALSE); + } }; class SharedMemoryId @@ -147,7 +152,7 @@ class SharedMemoryId bool Equals(SharedMemoryId *other) const; public: - SIZE_T AppendSessionDirectoryName(char (&path)[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1], SIZE_T pathCharCount) const; + bool AppendSessionDirectoryName(PathCharString& path) const; }; enum class SharedMemoryType : UINT8 @@ -238,6 +243,9 @@ class SharedMemoryManager static CRITICAL_SECTION s_creationDeletionProcessLock; static int s_creationDeletionLockFileDescriptor; + static PathCharString* s_runtimeTempDirectoryPath; + static PathCharString* s_sharedMemoryDirectoryPath; + private: static SharedMemoryProcessDataHeader *s_processDataHeaderListHead; @@ -248,7 +256,7 @@ class SharedMemoryManager #endif // _DEBUG public: - static void StaticInitialize(); + static bool StaticInitialize(); static void StaticClose(); public: @@ -257,6 +265,9 @@ class SharedMemoryManager static void AcquireCreationDeletionFileLock(); static void ReleaseCreationDeletionFileLock(); +public: + static bool CopySharedMemoryBasePath(PathCharString& destination); + #ifdef _DEBUG public: static bool IsCreationDeletionProcessLockAcquired(); diff --git a/src/pal/src/include/pal/sharedmemory.inl b/src/pal/src/include/pal/sharedmemory.inl index 69b8704b65f4..3a0c9797819c 100644 --- a/src/pal/src/include/pal/sharedmemory.inl +++ b/src/pal/src/include/pal/sharedmemory.inl @@ -11,43 +11,12 @@ #include -template -SIZE_T SharedMemoryHelpers::CopyString( - char (&destination)[DestinationByteCount], - SIZE_T destinationStartOffset, - const char(&source)[SourceByteCount]) +template +void SharedMemoryHelpers::BuildSharedFilesPath( + PathCharString& destination, + const char (&suffix)[SuffixByteCount]) { - return CopyString(destination, destinationStartOffset, source, SourceByteCount - 1); -} - -template -SIZE_T SharedMemoryHelpers::CopyString( - char (&destination)[DestinationByteCount], - SIZE_T destinationStartOffset, - LPCSTR source, - SIZE_T sourceCharCount) -{ - _ASSERTE(destinationStartOffset < DestinationByteCount); - _ASSERTE(sourceCharCount < DestinationByteCount - destinationStartOffset); - _ASSERTE(strlen(source) == sourceCharCount); - - memcpy_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, source, sourceCharCount + 1); - return destinationStartOffset + sourceCharCount; -} - -template -SIZE_T SharedMemoryHelpers::AppendUInt32String( - char (&destination)[DestinationByteCount], - SIZE_T destinationStartOffset, - UINT32 value) -{ - _ASSERTE(destination != nullptr); - _ASSERTE(destinationStartOffset < DestinationByteCount); - - int valueCharCount = - sprintf_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, "%u", value); - _ASSERTE(valueCharCount > 0); - return destinationStartOffset + valueCharCount; + BuildSharedFilesPath(destination, suffix, SuffixByteCount - 1); } #endif // !_PAL_SHARED_MEMORY_INL_ diff --git a/src/pal/src/include/pal/stackstring.hpp b/src/pal/src/include/pal/stackstring.hpp index 1f18d5fe0382..89fcd009b2cf 100644 --- a/src/pal/src/include/pal/stackstring.hpp +++ b/src/pal/src/include/pal/stackstring.hpp @@ -129,6 +129,12 @@ class StackString return Set(s.m_buffer, s.m_count); } + template BOOL Set(const T (&buffer)[bufferLength]) + { + // bufferLength includes terminator character + return Set(buffer, bufferLength - 1); + } + SIZE_T GetCount() const { return m_count; @@ -157,6 +163,11 @@ class StackString return result; } + T * OpenStringBuffer() + { + return m_buffer; + } + //count should not include the terminating null void CloseBuffer(SIZE_T count) { @@ -198,21 +209,38 @@ class StackString { return Append(s.GetString(), s.GetCount()); } - - BOOL IsEmpty() - { - return 0 == m_buffer[0]; - } - - void Clear() - { - m_count = 0; - NullTerminate(); - } - ~StackString() - { - DeleteBuffer(); - } + + template BOOL Append(const T (&buffer)[bufferLength]) + { + // bufferLength includes terminator character + return Append(buffer, bufferLength - 1); + } + + BOOL Append(T ch) + { + SIZE_T endpos = m_count; + if (!Resize(m_count + 1)) + return FALSE; + + m_buffer[endpos] = ch; + NullTerminate(); + return TRUE; + } + + BOOL IsEmpty() + { + return 0 == m_buffer[0]; + } + + void Clear() + { + m_count = 0; + NullTerminate(); + } + ~StackString() + { + DeleteBuffer(); + } }; #if _DEBUG diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp index dafe43df3ae6..294f45898133 100644 --- a/src/pal/src/init/pal.cpp +++ b/src/pal/src/init/pal.cpp @@ -355,6 +355,52 @@ Initialize( gPID = getpid(); gSID = getsid(gPID); + // The gSharedFilesPath is allocated dynamically so its destructor does not get + // called unexpectedly during cleanup + gSharedFilesPath = InternalNew(); + if (gSharedFilesPath == nullptr) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + +#ifdef __APPLE__ + // Store application group Id. It will be null if not set + gApplicationGroupId = getenv("DOTNET_SANDBOX_APPLICATION_GROUP_ID"); + + if (nullptr != gApplicationGroupId) + { + // Verify the length of the application group ID + gApplicationGroupIdLength = strlen(gApplicationGroupId); + if (gApplicationGroupIdLength > MAX_APPLICATION_GROUP_ID_LENGTH) + { + SetLastError(ERROR_BAD_LENGTH); + goto done; + } + + // In sandbox, all IPC files (locks, pipes) should be written to the application group + // container. There will be no write permissions to TEMP_DIRECTORY_PATH + if (!GetApplicationContainerFolder(*gSharedFilesPath, gApplicationGroupId, gApplicationGroupIdLength)) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto done; + } + + // Verify the size of the path won't exceed maximum allowed size + if (gSharedFilesPath->GetCount() + SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1 /* null terminator */ > MAX_LONGPATH) + { + SetLastError(ERROR_FILENAME_EXCED_RANGE); + } + } + else +#endif // __APPLE__ + { + gSharedFilesPath->Set(TEMP_DIRECTORY_PATH); + + // We can verify statically the non sandboxed case, since the size is known during compile time + static_assert_no_msg(string_countof(TEMP_DIRECTORY_PATH) + SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1 /* null terminator */ <= MAX_LONGPATH); + } + fFirstTimeInit = true; InitializeDefaultStackSize(); @@ -393,7 +439,11 @@ Initialize( // we use large numbers of threads or have many open files. } - SharedMemoryManager::StaticInitialize(); + if (!SharedMemoryManager::StaticInitialize()) + { + ERROR("Shared memory static initialization failed!\n"); + goto CLEANUP0; + } /* initialize the shared memory infrastructure */ if (!SHMInitialize()) diff --git a/src/pal/src/sharedmemory/sharedmemory.cpp b/src/pal/src/sharedmemory/sharedmemory.cpp index 46c07143a19a..af3934aa6133 100644 --- a/src/pal/src/sharedmemory/sharedmemory.cpp +++ b/src/pal/src/sharedmemory/sharedmemory.cpp @@ -9,6 +9,7 @@ #include "pal/malloc.hpp" #include "pal/thread.hpp" #include "pal/virtual.h" +#include "pal/process.h" #include #include @@ -135,8 +136,10 @@ bool SharedMemoryHelpers::EnsureDirectoryExists( return true; } - char tempPath[] = SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE; - if (mkdtemp(tempPath) == nullptr) + PathCharString tempPath; + BuildSharedFilesPath(tempPath, SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE); + + if (mkdtemp(tempPath.OpenStringBuffer()) == nullptr) { throw SharedMemoryException(static_cast(SharedMemoryError::IO)); } @@ -164,7 +167,7 @@ bool SharedMemoryHelpers::EnsureDirectoryExists( if (isSystemDirectory) { - // For system directories (such as SHARED_MEMORY_TEMP_DIRECTORY_PATH), require sufficient permissions only for the + // For system directories (such as TEMP_DIRECTORY_PATH), require sufficient permissions only for the // current user. For instance, "docker run --mount ..." to mount /tmp to some directory on the host mounts the // destination directory with the same permissions as the source directory, which may not include some permissions for // other users. In the docker container, other user permissions are typically not relevant and relaxing the permissions @@ -177,9 +180,9 @@ bool SharedMemoryHelpers::EnsureDirectoryExists( throw SharedMemoryException(static_cast(SharedMemoryError::IO)); } - // For non-system directories (such as SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH), require sufficient permissions for all - // users and try to update them if requested to create the directory, so that shared memory files may be shared by all - // processes on the system. + // For non-system directories (such as gSharedFilesPath/SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_NAME), + // require sufficient permissions for all users and try to update them if requested to create the directory, so that + // shared memory files may be shared by all processes on the system. if ((statInfo.st_mode & PermissionsMask_AllUsers_ReadWriteExecute) == PermissionsMask_AllUsers_ReadWriteExecute) { return true; @@ -388,6 +391,34 @@ void SharedMemoryHelpers::ReleaseFileLock(int fileDescriptor) } while (flockResult != 0 && errno == EINTR); } +void SharedMemoryHelpers::BuildSharedFilesPath(PathCharString& destination, const char *suffix, int suffixCharCount) +{ + _ASSERTE(strlen(suffix) == suffixCharCount); + + VerifyStringOperation(destination.Set(*gSharedFilesPath)); + VerifyStringOperation(destination.Append(suffix, suffixCharCount)); +} + +bool SharedMemoryHelpers::AppendUInt32String( + PathCharString& destination, + UINT32 value) +{ + char int32String[16]; + + int valueCharCount = + sprintf_s(int32String, sizeof(int32String), "%u", value); + _ASSERTE(valueCharCount > 0); + return destination.Append(int32String, valueCharCount) != FALSE; +} + +void SharedMemoryHelpers::VerifyStringOperation(bool success) +{ + if (!success) + { + throw SharedMemoryException(static_cast(SharedMemoryError::OutOfMemory)); + } +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SharedMemoryId @@ -471,22 +502,17 @@ bool SharedMemoryId::Equals(SharedMemoryId *other) const strcmp(GetName(), other->GetName()) == 0; } -SIZE_T SharedMemoryId::AppendSessionDirectoryName( - char (&path)[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1], - SIZE_T pathCharCount) const +bool SharedMemoryId::AppendSessionDirectoryName(PathCharString& path) const { if (IsSessionScope()) { - pathCharCount = SharedMemoryHelpers::CopyString(path, pathCharCount, SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX); - pathCharCount = SharedMemoryHelpers::AppendUInt32String(path, pathCharCount, GetCurrentSessionId()); + return path.Append(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) != FALSE + && SharedMemoryHelpers::AppendUInt32String(path, GetCurrentSessionId()); } else { - pathCharCount = SharedMemoryHelpers::CopyString(path, pathCharCount, SHARED_MEMORY_GLOBAL_DIRECTORY_NAME); + return path.Append(SHARED_MEMORY_GLOBAL_DIRECTORY_NAME) != FALSE; } - - _ASSERTE(pathCharCount <= SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT); - return pathCharCount; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -538,12 +564,13 @@ SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::CreateOrOpen( *createdRef = false; } + PathCharString filePath; SharedMemoryId id(name); struct AutoCleanup { bool m_acquiredCreationDeletionFileLock; - char *m_filePath; + PathCharString *m_filePath; SIZE_T m_sessionDirectoryPathCharCount; bool m_createdFile; int m_fileDescriptor; @@ -592,14 +619,14 @@ SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::CreateOrOpen( if (m_createdFile) { _ASSERTE(m_filePath != nullptr); - unlink(m_filePath); + unlink(*m_filePath); } if (m_sessionDirectoryPathCharCount != 0) { - _ASSERTE(m_filePath != nullptr); - m_filePath[m_sessionDirectoryPathCharCount] = '\0'; - rmdir(m_filePath); + _ASSERTE(*m_filePath != nullptr); + m_filePath->CloseBuffer(m_sessionDirectoryPathCharCount); + rmdir(*m_filePath); } if (m_acquiredCreationDeletionFileLock) @@ -623,21 +650,21 @@ SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::CreateOrOpen( autoCleanup.m_acquiredCreationDeletionFileLock = true; // Create the session directory - char filePath[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1]; - SIZE_T filePathCharCount = SharedMemoryHelpers::CopyString(filePath, 0, SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH); - filePath[filePathCharCount++] = '/'; - filePathCharCount = id.AppendSessionDirectoryName(filePath, filePathCharCount); + SharedMemoryHelpers::VerifyStringOperation(SharedMemoryManager::CopySharedMemoryBasePath(filePath)); + SharedMemoryHelpers::VerifyStringOperation(filePath.Append('/')); + SharedMemoryHelpers::VerifyStringOperation(id.AppendSessionDirectoryName(filePath)); if (!SharedMemoryHelpers::EnsureDirectoryExists(filePath, true /* isGlobalLockAcquired */, createIfNotExist)) { _ASSERTE(!createIfNotExist); return nullptr; } - autoCleanup.m_filePath = filePath; - autoCleanup.m_sessionDirectoryPathCharCount = filePathCharCount; + autoCleanup.m_filePath = &filePath; + autoCleanup.m_sessionDirectoryPathCharCount = filePath.GetCount(); // Create or open the shared memory file - filePath[filePathCharCount++] = '/'; - filePathCharCount = SharedMemoryHelpers::CopyString(filePath, filePathCharCount, id.GetName(), id.GetNameCharCount()); + SharedMemoryHelpers::VerifyStringOperation(filePath.Append('/')); + SharedMemoryHelpers::VerifyStringOperation(filePath.Append(id.GetName(), id.GetNameCharCount())); + bool createdFile; int fileDescriptor = SharedMemoryHelpers::CreateOrOpenFile(filePath, createIfNotExist, &createdFile); if (fileDescriptor == -1) @@ -919,16 +946,25 @@ void SharedMemoryProcessDataHeader::Close() return; } - // Delete the shared memory file, and the session directory if it's not empty - char path[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1]; - SIZE_T sessionDirectoryPathCharCount = SharedMemoryHelpers::CopyString(path, 0, SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH); - path[sessionDirectoryPathCharCount++] = '/'; - sessionDirectoryPathCharCount = m_id.AppendSessionDirectoryName(path, sessionDirectoryPathCharCount); - path[sessionDirectoryPathCharCount++] = '/'; - SharedMemoryHelpers::CopyString(path, sessionDirectoryPathCharCount, m_id.GetName(), m_id.GetNameCharCount()); - unlink(path); - path[sessionDirectoryPathCharCount] = '\0'; - rmdir(path); + try + { + // Delete the shared memory file, and the session directory if it's not empty + PathCharString path; + SharedMemoryHelpers::VerifyStringOperation(SharedMemoryManager::CopySharedMemoryBasePath(path)); + SharedMemoryHelpers::VerifyStringOperation(path.Append('/')); + SharedMemoryHelpers::VerifyStringOperation(m_id.AppendSessionDirectoryName(path)); + SharedMemoryHelpers::VerifyStringOperation(path.Append('/')); + + SIZE_T sessionDirectoryPathCharCount = path.GetCount(); + SharedMemoryHelpers::VerifyStringOperation(path.Append(m_id.GetName(), m_id.GetNameCharCount())); + unlink(path); + path.CloseBuffer(sessionDirectoryPathCharCount); + rmdir(path); + } + catch (SharedMemoryException) + { + // Ignore the error, just don't release shared data + } } SharedMemoryId *SharedMemoryProcessDataHeader::GetId() @@ -998,15 +1034,36 @@ CRITICAL_SECTION SharedMemoryManager::s_creationDeletionProcessLock; int SharedMemoryManager::s_creationDeletionLockFileDescriptor = -1; SharedMemoryProcessDataHeader *SharedMemoryManager::s_processDataHeaderListHead = nullptr; +PathCharString* SharedMemoryManager::s_runtimeTempDirectoryPath; +PathCharString* SharedMemoryManager::s_sharedMemoryDirectoryPath; #ifdef _DEBUG SIZE_T SharedMemoryManager::s_creationDeletionProcessLockOwnerThreadId = SharedMemoryHelpers::InvalidThreadId; SIZE_T SharedMemoryManager::s_creationDeletionFileLockOwnerThreadId = SharedMemoryHelpers::InvalidThreadId; #endif // _DEBUG -void SharedMemoryManager::StaticInitialize() +bool SharedMemoryManager::StaticInitialize() { InitializeCriticalSection(&s_creationDeletionProcessLock); + + s_runtimeTempDirectoryPath = InternalNew(); + s_sharedMemoryDirectoryPath = InternalNew(); + + if (s_runtimeTempDirectoryPath && s_sharedMemoryDirectoryPath) + { + try + { + SharedMemoryHelpers::BuildSharedFilesPath(*s_runtimeTempDirectoryPath, SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_NAME); + SharedMemoryHelpers::BuildSharedFilesPath(*s_sharedMemoryDirectoryPath, SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_NAME); + + return true; + } + catch (SharedMemoryException) + { + // Ignore and let function fail + } + } + return false; } void SharedMemoryManager::StaticClose() @@ -1056,7 +1113,7 @@ void SharedMemoryManager::AcquireCreationDeletionFileLock() if (s_creationDeletionLockFileDescriptor == -1) { if (!SharedMemoryHelpers::EnsureDirectoryExists( - SHARED_MEMORY_TEMP_DIRECTORY_PATH, + *gSharedFilesPath, false /* isGlobalLockAcquired */, false /* createIfNotExist */, true /* isSystemDirectory */)) @@ -1064,12 +1121,12 @@ void SharedMemoryManager::AcquireCreationDeletionFileLock() throw SharedMemoryException(static_cast(SharedMemoryError::IO)); } SharedMemoryHelpers::EnsureDirectoryExists( - SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH, + *s_runtimeTempDirectoryPath, false /* isGlobalLockAcquired */); SharedMemoryHelpers::EnsureDirectoryExists( - SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH, + *s_sharedMemoryDirectoryPath, false /* isGlobalLockAcquired */); - s_creationDeletionLockFileDescriptor = SharedMemoryHelpers::OpenDirectory(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH); + s_creationDeletionLockFileDescriptor = SharedMemoryHelpers::OpenDirectory(*s_sharedMemoryDirectoryPath); if (s_creationDeletionLockFileDescriptor == -1) { throw SharedMemoryException(static_cast(SharedMemoryError::IO)); @@ -1161,3 +1218,8 @@ SharedMemoryProcessDataHeader *SharedMemoryManager::FindProcessDataHeader(Shared } return nullptr; } + +bool SharedMemoryManager::CopySharedMemoryBasePath(PathCharString& destination) +{ + return destination.Set(*s_sharedMemoryDirectoryPath) != FALSE; +} diff --git a/src/pal/src/synchobj/mutex.cpp b/src/pal/src/synchobj/mutex.cpp index bbc3e2d0835d..a018d9db84c9 100644 --- a/src/pal/src/synchobj/mutex.cpp +++ b/src/pal/src/synchobj/mutex.cpp @@ -1069,13 +1069,17 @@ SharedMemoryProcessDataHeader *NamedMutexProcessData::CreateOrOpen( _ASSERTE(name != nullptr); _ASSERTE(createIfNotExist || !acquireLockIfCreated); +#if !NAMED_MUTEX_USE_PTHREAD_MUTEX + PathCharString lockFilePath; +#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX + struct AutoCleanup { bool m_acquiredCreationDeletionProcessLock; bool m_acquiredCreationDeletionFileLock; SharedMemoryProcessDataHeader *m_processDataHeader; #if !NAMED_MUTEX_USE_PTHREAD_MUTEX - char *m_lockFilePath; + PathCharString *m_lockFilePath; SIZE_T m_sessionDirectoryPathCharCount; bool m_createdLockFile; int m_lockFileDescriptor; @@ -1109,14 +1113,14 @@ SharedMemoryProcessDataHeader *NamedMutexProcessData::CreateOrOpen( if (m_createdLockFile) { _ASSERTE(m_lockFilePath != nullptr); - unlink(m_lockFilePath); + unlink(*m_lockFilePath); } if (m_sessionDirectoryPathCharCount != 0) { _ASSERTE(m_lockFilePath != nullptr); - m_lockFilePath[m_sessionDirectoryPathCharCount] = '\0'; - rmdir(m_lockFilePath); + m_lockFilePath->CloseBuffer(m_sessionDirectoryPathCharCount); + rmdir(*m_lockFilePath); } } #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX @@ -1179,29 +1183,26 @@ SharedMemoryProcessDataHeader *NamedMutexProcessData::CreateOrOpen( { #if !NAMED_MUTEX_USE_PTHREAD_MUTEX // Create the lock files directory - char lockFilePath[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1]; - SIZE_T lockFilePathCharCount = - SharedMemoryHelpers::CopyString(lockFilePath, 0, SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH); + SharedMemoryHelpers::BuildSharedFilesPath(lockFilePath, SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME); if (created) { SharedMemoryHelpers::EnsureDirectoryExists(lockFilePath, true /* isGlobalLockAcquired */); } // Create the session directory - lockFilePath[lockFilePathCharCount++] = '/'; SharedMemoryId *id = processDataHeader->GetId(); - lockFilePathCharCount = id->AppendSessionDirectoryName(lockFilePath, lockFilePathCharCount); + SharedMemoryHelpers::VerifyStringOperation(lockFilePath.Append('/')); + SharedMemoryHelpers::VerifyStringOperation(id->AppendSessionDirectoryName(lockFilePath)); if (created) { SharedMemoryHelpers::EnsureDirectoryExists(lockFilePath, true /* isGlobalLockAcquired */); - autoCleanup.m_lockFilePath = lockFilePath; - autoCleanup.m_sessionDirectoryPathCharCount = lockFilePathCharCount; + autoCleanup.m_lockFilePath = &lockFilePath; + autoCleanup.m_sessionDirectoryPathCharCount = lockFilePath.GetCount(); } // Create or open the lock file - lockFilePath[lockFilePathCharCount++] = '/'; - lockFilePathCharCount = - SharedMemoryHelpers::CopyString(lockFilePath, lockFilePathCharCount, id->GetName(), id->GetNameCharCount()); + SharedMemoryHelpers::VerifyStringOperation(lockFilePath.Append('/')); + SharedMemoryHelpers::VerifyStringOperation(lockFilePath.Append(id->GetName(), id->GetNameCharCount())); int lockFileDescriptor = SharedMemoryHelpers::CreateOrOpenFile(lockFilePath, created); if (lockFileDescriptor == -1) { @@ -1316,17 +1317,25 @@ void NamedMutexProcessData::Close(bool isAbruptShutdown, bool releaseSharedData) return; } - // Delete the lock file, and the session directory if it's not empty - char path[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1]; - SIZE_T sessionDirectoryPathCharCount = SharedMemoryHelpers::CopyString(path, 0, SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH); - path[sessionDirectoryPathCharCount++] = '/'; - SharedMemoryId *id = m_processDataHeader->GetId(); - sessionDirectoryPathCharCount = id->AppendSessionDirectoryName(path, sessionDirectoryPathCharCount); - path[sessionDirectoryPathCharCount++] = '/'; - SharedMemoryHelpers::CopyString(path, sessionDirectoryPathCharCount, id->GetName(), id->GetNameCharCount()); - unlink(path); - path[sessionDirectoryPathCharCount] = '\0'; - rmdir(path); + try + { + // Delete the lock file, and the session directory if it's not empty + PathCharString path; + SharedMemoryHelpers::BuildSharedFilesPath(path, SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME); + SharedMemoryId *id = m_processDataHeader->GetId(); + SharedMemoryHelpers::VerifyStringOperation(path.Append('/')); + SharedMemoryHelpers::VerifyStringOperation(id->AppendSessionDirectoryName(path)); + SharedMemoryHelpers::VerifyStringOperation(path.Append('/')); + SIZE_T sessionDirectoryPathCharCount = path.GetCount(); + SharedMemoryHelpers::VerifyStringOperation(path.Append(id->GetName(), id->GetNameCharCount())); + unlink(path); + path.CloseBuffer(sessionDirectoryPathCharCount); + rmdir(path); + } + catch (SharedMemoryException) + { + // Ignore the error, just don't release shared data + } #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX } diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp index 19d3c08fc047..0141b076541b 100644 --- a/src/pal/src/thread/process.cpp +++ b/src/pal/src/thread/process.cpp @@ -139,6 +139,13 @@ Volatile terminator = 0; DWORD gPID = (DWORD) -1; DWORD gSID = (DWORD) -1; +// Application group ID for this process +#ifdef __APPLE__ +LPCSTR gApplicationGroupId = nullptr; +int gApplicationGroupIdLength = 0; +#endif // __APPLE__ +PathCharString* gSharedFilesPath = nullptr; + // The lowest common supported semaphore length, including null character // NetBSD-7.99.25: 15 characters // MacOSX 10.11: 31 -- Core 1.0 RC2 compatibility @@ -1983,6 +1990,15 @@ PAL_NotifyRuntimeStarted() return launched; } +#ifdef __APPLE__ +LPCSTR +PALAPI +PAL_GetApplicationGroupId() +{ + return gApplicationGroupId; +} +#endif // __APPLE__ + /*++ Function: GetProcessIdDisambiguationKey @@ -3945,6 +3961,21 @@ PROCGetProcessStatus( return palError; } +#ifdef __APPLE__ +bool GetApplicationContainerFolder(PathCharString& buffer, const char *applicationGroupId, int applicationGroupIdLength) +{ + const char *homeDir = getpwuid(getuid())->pw_dir; + int homeDirLength = strlen(homeDir); + + // The application group container folder is defined as: + // /user/{loginname}/Library/Group Containers/{AppGroupId}/ + return buffer.Set(homeDir, homeDirLength) + && buffer.Append(APPLICATION_CONTAINER_BASE_PATH_SUFFIX) + && buffer.Append(applicationGroupId, applicationGroupIdLength) + && buffer.Append('/'); +} +#endif // __APPLE__ + #ifdef _DEBUG void PROCDumpThreadList() {