diff options
author | Oded Hanson <odhanson@microsoft.com> | 2018-11-06 18:31:49 +0200 |
---|---|---|
committer | Jan Vorlicek <janvorli@microsoft.com> | 2018-11-06 17:31:49 +0100 |
commit | 5c566d470db2f1be687e6da5f9935960d482bf72 (patch) | |
tree | a7ef4ac46b3da2a6469516432af3f11b68a22fc2 /src/pal | |
parent | b1b424f741af16a5df052ef11609c65d99686435 (diff) | |
download | coreclr-5c566d470db2f1be687e6da5f9935960d482bf72.tar.gz coreclr-5c566d470db2f1be687e6da5f9935960d482bf72.tar.bz2 coreclr-5c566d470db2f1be687e6da5f9935960d482bf72.zip |
Added support for running in a sandbox on Mac (#20735)
* Added support for running in a sandbox on Mac
When running in a sandbox, the Mac operating system will limit access to resources, esp. the file system. Right now both Mutex and SharedMemory in the PAL are accessing the /tmp folder for which Mac does not provide the application permissions to access.
Instead, the sandbox provides the ability to share information between applications by using a shared container folder. This is done by registering the application with an Application Group ID. Using this ID, we can access the shared folder and read/write from it.
Since the .Net runtime can be loaded in multiple ways, we decided that the easiest way to let the runtime know what the application group ID is via an environment variable. Thus, if the NETCOREAPP_SANDBOX_APPLICATION_GROUP_ID environment variable is set (on Mac), the runtime will assume we are sandboxed, and will use the value provided as the application group ID. Note that due to limitations on semaphore file lengths, we will not allow application group IDs longer than 13 characters. This gives us 10 characters for the developer ID, and 3 extra characters for the group name.
When sandbox is disabled (the environment variable is empty) then the folder for Mutex and SharedMemory will continue to be rooted in /tmp. However when the sandbox is enabled, these files will be created under /user/{loginname}/Library/Group Containers/{AppGroupId}/.
Fixes #20473
* Made gApplicationContainerPath a pointer so it does not get automatically deleted by the c runtime
* Made s_runtimeTempDirectoryPath and s_sharedMemoryDirectoryPath pointers so they are not automatically deleted by the c runtime
* Renamed gApplicationContainerPath to gSharedFilesPath
* Renamed NETCOREAPP_SANDBOX_APPLICATION_GROUP_ID to DOTNET_SANDBOX_APPLICATION_GROUP_ID
* Fixed usage of VerifyStringOperation
* Replaced new with InternalNew
* Wrapped Apple specific code with #ifdef
* Added exception handling during close
* Moved VerifyStringOperation macro into SharedMemoryManager
* Moved PathCharString variable declarations before AutoCleanup is declared.
* Fixed initialization functions not to throw
* Renamed CopyPath to BuildSharedFilesPath
* Fixed misc nits
* Fixed implicit conversions from BOOL to bool
* Moved MAX_APPLICATION_GROUP_ID_LENGTH inside ifdef APPLE
* Removed PAL_IsApplicationSandboxed
Diffstat (limited to 'src/pal')
-rw-r--r-- | src/pal/inc/pal.h | 7 | ||||
-rw-r--r-- | src/pal/src/include/pal/palinternal.h | 19 | ||||
-rw-r--r-- | src/pal/src/include/pal/process.h | 8 | ||||
-rw-r--r-- | src/pal/src/include/pal/sharedmemory.h | 57 | ||||
-rw-r--r-- | src/pal/src/include/pal/sharedmemory.inl | 41 | ||||
-rw-r--r-- | src/pal/src/include/pal/stackstring.hpp | 58 | ||||
-rw-r--r-- | src/pal/src/init/pal.cpp | 52 | ||||
-rw-r--r-- | src/pal/src/sharedmemory/sharedmemory.cpp | 148 | ||||
-rw-r--r-- | src/pal/src/synchobj/mutex.cpp | 59 | ||||
-rw-r--r-- | src/pal/src/thread/process.cpp | 31 |
10 files changed, 337 insertions, 143 deletions
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index a7f0ff5d74..2a51d584ad 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 0e37ba84c0..a66ef7e18e 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 <sys/socket.h> +#include <pal/stackstring.hpp> + #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 <typename T> inline diff --git a/src/pal/src/include/pal/process.h b/src/pal/src/include/pal/process.h index f5d8b46de6..4eccc6189f 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 fdc395e3c6..3ea3b71182 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/<fileName> +// {gSharedFilesPath}/.dotnet/shm/global/<fileName> // - Session-scoped shared memory files go in: -// {tmp}/.dotnet/shm/session<sessionId>/<fileName> +// {gSharedFilesPath}/.dotnet/shm/session<sessionId>/<fileName> // - Lock files associated with global shared memory files go in: -// {tmp}/.dotnet/lockfiles/global/<fileName> +// {gSharedFilesPath}/.dotnet/lockfiles/global/<fileName> // - Lock files associated with session-scoped shared memory files go in: -// {tmp}/.dotnet/lockfiles/session<sessionId>/<fileName> +// {gSharedFilesPath}/.dotnet/lockfiles/session<sessionId>/<fileName> #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 @@ public: static void *Alloc(SIZE_T byteCount); - template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, const char (&source)[SourceByteCount]); - template<SIZE_T DestinationByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, LPCSTR source, SIZE_T sourceCharCount); - template<SIZE_T DestinationByteCount> static SIZE_T AppendUInt32String(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, UINT32 value); + template<SIZE_T SuffixByteCount> 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: #endif // _DEBUG public: - static void StaticInitialize(); + static bool StaticInitialize(); static void StaticClose(); public: @@ -257,6 +265,9 @@ public: 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 69b8704b65..3a0c979781 100644 --- a/src/pal/src/include/pal/sharedmemory.inl +++ b/src/pal/src/include/pal/sharedmemory.inl @@ -11,43 +11,12 @@ #include <string.h> -template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount> -SIZE_T SharedMemoryHelpers::CopyString( - char (&destination)[DestinationByteCount], - SIZE_T destinationStartOffset, - const char(&source)[SourceByteCount]) +template<SIZE_T SuffixByteCount> +void SharedMemoryHelpers::BuildSharedFilesPath( + PathCharString& destination, + const char (&suffix)[SuffixByteCount]) { - return CopyString(destination, destinationStartOffset, source, SourceByteCount - 1); -} - -template<SIZE_T DestinationByteCount> -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 DestinationByteCount> -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 1f18d5fe03..89fcd009b2 100644 --- a/src/pal/src/include/pal/stackstring.hpp +++ b/src/pal/src/include/pal/stackstring.hpp @@ -129,6 +129,12 @@ public: return Set(s.m_buffer, s.m_count); } + template<SIZE_T bufferLength> 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 @@ public: return result; } + T * OpenStringBuffer() + { + return m_buffer; + } + //count should not include the terminating null void CloseBuffer(SIZE_T count) { @@ -198,21 +209,38 @@ public: { return Append(s.GetString(), s.GetCount()); } - - BOOL IsEmpty() - { - return 0 == m_buffer[0]; - } - - void Clear() - { - m_count = 0; - NullTerminate(); - } - ~StackString() - { - DeleteBuffer(); - } + + template<SIZE_T bufferLength> 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 dafe43df3a..294f458981 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<PathCharString>(); + 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 46c07143a1..af3934aa61 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 <sys/file.h> #include <sys/mman.h> @@ -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<DWORD>(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<DWORD>(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<DWORD>(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<PathCharString>(); + s_sharedMemoryDirectoryPath = InternalNew<PathCharString>(); + + 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<DWORD>(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<DWORD>(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 bbc3e2d083..a018d9db84 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 19d3c08fc0..0141b07654 100644 --- a/src/pal/src/thread/process.cpp +++ b/src/pal/src/thread/process.cpp @@ -139,6 +139,13 @@ Volatile<LONG> 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 @@ exit: return launched; } +#ifdef __APPLE__ +LPCSTR +PALAPI +PAL_GetApplicationGroupId() +{ + return gApplicationGroupId; +} +#endif // __APPLE__ + /*++ Function: GetProcessIdDisambiguationKey @@ -3945,6 +3961,21 @@ PROCGetProcessStatusExit: 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() { |