Skip to content

Commit

Permalink
✨ Implement the workaround for memory mapped file security.
Browse files Browse the repository at this point in the history
  • Loading branch information
hexawyz committed Jan 19, 2025
1 parent 96e7b11 commit 9f13498
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<PackageReference Update="System.Security.AccessControl" Version="6.0.1" />
<PackageReference Update="System.ServiceModel.Primitives" Version="8.1.1" />
<PackageReference Update="System.Threading.Channels" Version="9.0.0" />
<PackageReference Update="System.Threading.AccessControl" Version="9.0.1" />
<PackageReference Update="coverlet.collector" Version="6.0.2" />
<PackageReference Update="Grpc.AspNetCore.Server" Version="2.67.0" />
<PackageReference Update="Grpc.Net.Client" Version="2.67.0" />
Expand Down
4 changes: 4 additions & 0 deletions src/Exo/Core/Exo.Memory/Exo.Memory.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Threading.AccessControl" />
</ItemGroup>

</Project>
41 changes: 36 additions & 5 deletions src/Exo/Core/Exo.Memory/SharedMemory.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
using System.IO.MemoryMappedFiles;
using System.Security.AccessControl;
using System.Security.Cryptography;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;

namespace Exo.Memory;

public sealed class SharedMemory : IDisposable
{
private static readonly string DefaultPrefix = GetAcceptablePrefix();
private static readonly bool CanCreateGlobalSharedMemory = DetectCreateGlobalPrivilege();
private static string DefaultPrefix => CanCreateGlobalSharedMemory ? @"Global\" : @"Local\";

private static string GetAcceptablePrefix()
private static bool DetectCreateGlobalPrivilege()
{
var seCreateGlobalPrivilege = NativeMethods.GetPrivilegeValue(NativeMethods.SeCreateGlobalPrivilege);
foreach (var privilege in NativeMethods.GetProcessPrivileges())
{
if (privilege.Luid == seCreateGlobalPrivilege) return @"Global\";
if (privilege.Luid == seCreateGlobalPrivilege && (privilege.Attributes & NativeMethods.PrivilegeAttributes.Enabled) != 0) return true;
}
return @"Local\";
return false;
}

public static SharedMemory Create(string prefix, ulong length)
Expand All @@ -33,7 +37,34 @@ public static SharedMemory Create(string prefix, ulong length)
RandomNumberGenerator.GetHexString(span[(DefaultPrefix.Length + prefix.Length)..], true);
}
);
return new(name, MemoryMappedFile.CreateNew(name, (long)length, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.None), length);
var memoryMappedFile = MemoryMappedFile.CreateNew(name, (long)length, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, HandleInheritability.None);
// When creating a memory mapped file in the GLobal namespace, we want to adjust the privileges to allow non privileged clients to access it.
if (CanCreateGlobalSharedMemory)
{
// This is a dirty workaround to override security of the memory mapped file, as security for memory mapped files has not been ported to .NET Core ☹️
// Found here: https://github.com/dotnet/runtime/issues/48793#issuecomment-2299577613
using (var mutex = new Mutex())
{
mutex.SafeWaitHandle.Close();
mutex.SafeWaitHandle = new SafeWaitHandle(memoryMappedFile.SafeMemoryMappedFileHandle.DangerousGetHandle(), false);

#pragma warning disable CA1416 // Validate platform compatibility
var security = mutex.GetAccessControl();
security.AddAccessRule
(
new MutexAccessRule
(
new SecurityIdentifier(WellKnownSidType.InteractiveSid, null),
// Read + Write
(MutexRights)6,
AccessControlType.Allow
)
);
mutex.SetAccessControl(security);
#pragma warning restore CA1416 // Validate platform compatibility
}
}
return new(name, memoryMappedFile, length);
}

public static SharedMemory Open(string name, ulong length, MemoryMappedFileAccess access)
Expand Down
3 changes: 3 additions & 0 deletions src/Exo/Ui/Exo.Settings.Ui/ViewModels/ImagesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ private async Task AddImageAsync(CancellationToken cancellationToken)
NotifyPropertyChanged(ChangedProperty.LoadedImageData);
_addImageCommand.NotifyCanExecuteChanged();
}
catch (Exception ex)
{
}
finally
{
IsNotBusy = true;
Expand Down

0 comments on commit 9f13498

Please sign in to comment.