Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 1e647b1

Browse files
odhansondanmoseley
authored andcommitted
[release/2.2] Added support for running in a sandbox on Mac (#20735) (#20906)
* 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 * Verify the application group container directory exists in Mac Sandbox (#20916) * Verify the application group container directory exists in Mac Sandbox Added an additional check to verify that the shared files directory based on the application group ID exists when running in a Mac sandbox. If it doesn't then the initialization will fail. As part of this change, also refactored the logic the sets the shared file path into a separate method. * Changed bool to BOOL
1 parent b0fcdd8 commit 1e647b1

File tree

10 files changed

+366
-143
lines changed

10 files changed

+366
-143
lines changed

src/pal/inc/pal.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,13 @@ BOOL
442442
PALAPI
443443
PAL_NotifyRuntimeStarted(VOID);
444444

445+
#ifdef __APPLE__
446+
PALIMPORT
447+
LPCSTR
448+
PALAPI
449+
PAL_GetApplicationGroupId();
450+
#endif // __APPLE__
451+
445452
static const int MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH = MAX_PATH;
446453

447454
PALIMPORT

src/pal/src/include/pal/palinternal.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,8 @@ function_name() to call the system's implementation
614614
we'll catch any definition conflicts */
615615
#include <sys/socket.h>
616616

617+
#include <pal/stackstring.hpp>
618+
617619
#if !HAVE_INFTIM
618620
#define INFTIM -1
619621
#endif // !HAVE_INFTIM
@@ -623,6 +625,8 @@ function_name() to call the system's implementation
623625
#undef assert
624626
#define assert (Use__ASSERTE_instead_of_assert) assert
625627

628+
#define string_countof(a) (sizeof(a) / sizeof(a[0]) - 1)
629+
626630
#ifndef __ANDROID__
627631
#define TEMP_DIRECTORY_PATH "/tmp/"
628632
#else
@@ -633,6 +637,16 @@ function_name() to call the system's implementation
633637

634638
#define PROCESS_PIPE_NAME_PREFIX ".dotnet-pal-processpipe"
635639

640+
#ifdef __APPLE__
641+
#define APPLICATION_CONTAINER_BASE_PATH_SUFFIX "/Library/Group Containers/"
642+
643+
// Not much to go with, but Max semaphore length on Mac is 31 characters. In a sandbox, the semaphore name
644+
// must be prefixed with an application group ID. This will be 10 characters for developer ID and extra 2
645+
// characters for group name. For example ABCDEFGHIJ.MS. We still need some characters left
646+
// for the actual semaphore names.
647+
#define MAX_APPLICATION_GROUP_ID_LENGTH 13
648+
#endif // __APPLE__
649+
636650
#ifdef __cplusplus
637651
extern "C"
638652
{
@@ -656,6 +670,11 @@ typedef enum _TimeConversionConstants
656670
bool
657671
ReadMemoryValueFromFile(const char* filename, size_t* val);
658672

673+
#ifdef __APPLE__
674+
bool
675+
GetApplicationContainerFolder(PathCharString& buffer, const char *applicationGroupId, int applicationGroupIdLength);
676+
#endif // __APPLE__
677+
659678
/* This is duplicated in utilcode.h for CLR, with cooler type-traits */
660679
template <typename T>
661680
inline

src/pal/src/include/pal/process.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Revision History:
2424
#define _PAL_PROCESS_H_
2525

2626
#include "pal/palinternal.h"
27+
#include "pal/stackstring.hpp"
2728

2829
#ifdef __cplusplus
2930
extern "C"
@@ -43,6 +44,13 @@ extern DWORD gSID;
4344

4445
extern LPWSTR pAppDir;
4546

47+
// The Mac sandbox application group ID (if exists) and container (shared) path
48+
#ifdef __APPLE__
49+
extern LPCSTR gApplicationGroupId;
50+
extern int gApplicationGroupIdLength;
51+
#endif // __APPLE__
52+
extern PathCharString *gSharedFilesPath;
53+
4654
/*++
4755
Function:
4856
PROCGetProcessIDFromHandle

src/pal/src/include/pal/sharedmemory.h

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,45 @@
1515
#define _countof(a) (sizeof(a) / sizeof(a[0]))
1616
#endif // !_countof
1717

18-
// The temporary folder is used for storing shared memory files and their lock files.
19-
// The location of the temporary folder varies (e.g. /data/local/tmp on Android)
20-
// and is set in TEMP_DIRECTORY_PATH. TEMP_DIRECTORY_PATH ends with '/'
18+
// The folder used for storing shared memory files and their lock files is defined in
19+
// the gSharedFilesPath global variable. The value of the variable depends on which
20+
// OS is being used, and if the application is running in a sandbox in Mac.
21+
// gSharedFilesPath ends with '/'
2122
// - Global shared memory files go in:
22-
// {tmp}/.dotnet/shm/global/<fileName>
23+
// {gSharedFilesPath}/.dotnet/shm/global/<fileName>
2324
// - Session-scoped shared memory files go in:
24-
// {tmp}/.dotnet/shm/session<sessionId>/<fileName>
25+
// {gSharedFilesPath}/.dotnet/shm/session<sessionId>/<fileName>
2526
// - Lock files associated with global shared memory files go in:
26-
// {tmp}/.dotnet/lockfiles/global/<fileName>
27+
// {gSharedFilesPath}/.dotnet/lockfiles/global/<fileName>
2728
// - Lock files associated with session-scoped shared memory files go in:
28-
// {tmp}/.dotnet/lockfiles/session<sessionId>/<fileName>
29+
// {gSharedFilesPath}/.dotnet/lockfiles/session<sessionId>/<fileName>
2930

3031
#define SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT (_MAX_FNAME - 1)
31-
#define SHARED_MEMORY_MAX_NAME_CHAR_COUNT (_countof("Global\\") - 1 + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT)
32+
#define SHARED_MEMORY_MAX_NAME_CHAR_COUNT (string_countof("Global\\") + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT)
3233

33-
#define SHARED_MEMORY_TEMP_DIRECTORY_PATH TEMP_DIRECTORY_PATH
34-
#define SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH TEMP_DIRECTORY_PATH ".dotnet"
35-
36-
#define SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH TEMP_DIRECTORY_PATH ".dotnet/shm"
37-
#define SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH TEMP_DIRECTORY_PATH ".dotnet/lockfiles"
38-
static_assert_no_msg(_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) >= _countof(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH));
34+
#define SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_NAME ".dotnet"
35+
#define SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_NAME ".dotnet/shm"
36+
#define SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME ".dotnet/lockfiles"
37+
static_assert_no_msg(_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME) >= _countof(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_NAME));
3938

4039
#define SHARED_MEMORY_GLOBAL_DIRECTORY_NAME "global"
4140
#define SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX "session"
4241
static_assert_no_msg(_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) >= _countof(SHARED_MEMORY_GLOBAL_DIRECTORY_NAME));
4342

44-
#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE TEMP_DIRECTORY_PATH ".coreclr.XXXXXX"
43+
#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE ".coreclr.XXXXXX"
4544

4645
#define SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT (10)
4746

47+
// Note that this Max size does not include the prefix folder path size which is unknown (in the case of sandbox) until runtime
4848
#define SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT \
4949
( \
50-
_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) - 1 + \
50+
string_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_NAME) + \
5151
1 /* path separator */ + \
52-
_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) - 1 + \
52+
string_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) + \
5353
SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT + \
5454
1 /* path separator */ + \
5555
SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT \
5656
)
57-
static_assert_no_msg(SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1 /* null terminator */ <= MAX_LONGPATH);
5857

5958
class AutoFreeBuffer
6059
{
@@ -107,9 +106,9 @@ class SharedMemoryHelpers
107106

108107
static void *Alloc(SIZE_T byteCount);
109108

110-
template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, const char (&source)[SourceByteCount]);
111-
template<SIZE_T DestinationByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, LPCSTR source, SIZE_T sourceCharCount);
112-
template<SIZE_T DestinationByteCount> static SIZE_T AppendUInt32String(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, UINT32 value);
109+
template<SIZE_T SuffixByteCount> static void BuildSharedFilesPath(PathCharString& destination, const char (&suffix)[SuffixByteCount]);
110+
static void BuildSharedFilesPath(PathCharString& destination, const char *suffix, int suffixByteCount);
111+
static bool AppendUInt32String(PathCharString& destination, UINT32 value);
113112

114113
static bool EnsureDirectoryExists(const char *path, bool isGlobalLockAcquired, bool createIfNotExist = true, bool isSystemDirectory = false);
115114
private:
@@ -126,6 +125,12 @@ class SharedMemoryHelpers
126125

127126
static bool TryAcquireFileLock(int fileDescriptor, int operation);
128127
static void ReleaseFileLock(int fileDescriptor);
128+
129+
static void VerifyStringOperation(bool success);
130+
static void VerifyStringOperation(BOOL success)
131+
{
132+
VerifyStringOperation(success != FALSE);
133+
}
129134
};
130135

131136
class SharedMemoryId
@@ -147,7 +152,7 @@ class SharedMemoryId
147152
bool Equals(SharedMemoryId *other) const;
148153

149154
public:
150-
SIZE_T AppendSessionDirectoryName(char (&path)[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1], SIZE_T pathCharCount) const;
155+
bool AppendSessionDirectoryName(PathCharString& path) const;
151156
};
152157

153158
enum class SharedMemoryType : UINT8
@@ -238,6 +243,9 @@ class SharedMemoryManager
238243
static CRITICAL_SECTION s_creationDeletionProcessLock;
239244
static int s_creationDeletionLockFileDescriptor;
240245

246+
static PathCharString* s_runtimeTempDirectoryPath;
247+
static PathCharString* s_sharedMemoryDirectoryPath;
248+
241249
private:
242250
static SharedMemoryProcessDataHeader *s_processDataHeaderListHead;
243251

@@ -248,7 +256,7 @@ class SharedMemoryManager
248256
#endif // _DEBUG
249257

250258
public:
251-
static void StaticInitialize();
259+
static bool StaticInitialize();
252260
static void StaticClose();
253261

254262
public:
@@ -257,6 +265,9 @@ class SharedMemoryManager
257265
static void AcquireCreationDeletionFileLock();
258266
static void ReleaseCreationDeletionFileLock();
259267

268+
public:
269+
static bool CopySharedMemoryBasePath(PathCharString& destination);
270+
260271
#ifdef _DEBUG
261272
public:
262273
static bool IsCreationDeletionProcessLockAcquired();

src/pal/src/include/pal/sharedmemory.inl

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,12 @@
1111

1212
#include <string.h>
1313

14-
template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount>
15-
SIZE_T SharedMemoryHelpers::CopyString(
16-
char (&destination)[DestinationByteCount],
17-
SIZE_T destinationStartOffset,
18-
const char(&source)[SourceByteCount])
14+
template<SIZE_T SuffixByteCount>
15+
void SharedMemoryHelpers::BuildSharedFilesPath(
16+
PathCharString& destination,
17+
const char (&suffix)[SuffixByteCount])
1918
{
20-
return CopyString(destination, destinationStartOffset, source, SourceByteCount - 1);
21-
}
22-
23-
template<SIZE_T DestinationByteCount>
24-
SIZE_T SharedMemoryHelpers::CopyString(
25-
char (&destination)[DestinationByteCount],
26-
SIZE_T destinationStartOffset,
27-
LPCSTR source,
28-
SIZE_T sourceCharCount)
29-
{
30-
_ASSERTE(destinationStartOffset < DestinationByteCount);
31-
_ASSERTE(sourceCharCount < DestinationByteCount - destinationStartOffset);
32-
_ASSERTE(strlen(source) == sourceCharCount);
33-
34-
memcpy_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, source, sourceCharCount + 1);
35-
return destinationStartOffset + sourceCharCount;
36-
}
37-
38-
template<SIZE_T DestinationByteCount>
39-
SIZE_T SharedMemoryHelpers::AppendUInt32String(
40-
char (&destination)[DestinationByteCount],
41-
SIZE_T destinationStartOffset,
42-
UINT32 value)
43-
{
44-
_ASSERTE(destination != nullptr);
45-
_ASSERTE(destinationStartOffset < DestinationByteCount);
46-
47-
int valueCharCount =
48-
sprintf_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, "%u", value);
49-
_ASSERTE(valueCharCount > 0);
50-
return destinationStartOffset + valueCharCount;
19+
BuildSharedFilesPath(destination, suffix, SuffixByteCount - 1);
5120
}
5221

5322
#endif // !_PAL_SHARED_MEMORY_INL_

src/pal/src/include/pal/stackstring.hpp

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ class StackString
129129
return Set(s.m_buffer, s.m_count);
130130
}
131131

132+
template<SIZE_T bufferLength> BOOL Set(const T (&buffer)[bufferLength])
133+
{
134+
// bufferLength includes terminator character
135+
return Set(buffer, bufferLength - 1);
136+
}
137+
132138
SIZE_T GetCount() const
133139
{
134140
return m_count;
@@ -157,6 +163,11 @@ class StackString
157163
return result;
158164
}
159165

166+
T * OpenStringBuffer()
167+
{
168+
return m_buffer;
169+
}
170+
160171
//count should not include the terminating null
161172
void CloseBuffer(SIZE_T count)
162173
{
@@ -198,21 +209,38 @@ class StackString
198209
{
199210
return Append(s.GetString(), s.GetCount());
200211
}
201-
202-
BOOL IsEmpty()
203-
{
204-
return 0 == m_buffer[0];
205-
}
206-
207-
void Clear()
208-
{
209-
m_count = 0;
210-
NullTerminate();
211-
}
212-
~StackString()
213-
{
214-
DeleteBuffer();
215-
}
212+
213+
template<SIZE_T bufferLength> BOOL Append(const T (&buffer)[bufferLength])
214+
{
215+
// bufferLength includes terminator character
216+
return Append(buffer, bufferLength - 1);
217+
}
218+
219+
BOOL Append(T ch)
220+
{
221+
SIZE_T endpos = m_count;
222+
if (!Resize(m_count + 1))
223+
return FALSE;
224+
225+
m_buffer[endpos] = ch;
226+
NullTerminate();
227+
return TRUE;
228+
}
229+
230+
BOOL IsEmpty()
231+
{
232+
return 0 == m_buffer[0];
233+
}
234+
235+
void Clear()
236+
{
237+
m_count = 0;
238+
NullTerminate();
239+
}
240+
~StackString()
241+
{
242+
DeleteBuffer();
243+
}
216244
};
217245

218246
#if _DEBUG

0 commit comments

Comments
 (0)