Skip to content

Commit 81f1f5e

Browse files
steveharterericstjCopilot
authored
Specify a security descriptor when using global Mutex (#110416)
* Specify a security descriptor when using global Mutex * Apply Copilot feedback Co-authored-by: Copilot <[email protected]> * Add System.Threading.AccessControl to ASP.NETCore --------- Co-authored-by: Eric StJohn <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 69dd454 commit 81f1f5e

File tree

6 files changed

+74
-11
lines changed

6 files changed

+74
-11
lines changed

src/libraries/Common/src/System/Diagnostics/NetFrameworkUtils.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.IO;
55
using System.Runtime.CompilerServices;
66
using System.Runtime.InteropServices;
7+
using System.Security.AccessControl;
8+
using System.Security.Principal;
79
using System.Text;
810
using System.Threading;
911
using Microsoft.Win32;
@@ -22,6 +24,13 @@ internal static void EnterMutexWithoutGlobal(string mutexName, ref Mutex mutex)
2224
{
2325
Mutex tmpMutex = new Mutex(false, mutexName, out _);
2426

27+
// Specify a SID in case the mutex has not yet been created; this prevents it from using the SID from the current thread.
28+
// This SID (AuthenticatedUserSid) is the same one used by .NET Framework.
29+
MutexSecurity sec = new MutexSecurity();
30+
SecurityIdentifier authenticatedUserSid = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
31+
sec.AddAccessRule(new MutexAccessRule(authenticatedUserSid, MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Allow));
32+
tmpMutex.SetAccessControl(sec);
33+
2534
SafeWaitForMutex(tmpMutex, ref mutex);
2635
}
2736

src/libraries/NetCoreAppLibrary.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@
224224
Microsoft.Extensions.Primitives;
225225
System.Diagnostics.EventLog;
226226
System.Security.Cryptography.Xml;
227+
System.Threading.AccessControl;
227228
System.Threading.RateLimiting;
228229
</AspNetCoreAppLibrary>
229230
<WindowsDesktopCoreAppLibrary>

src/libraries/System.Diagnostics.EventLog/src/System.Diagnostics.EventLog.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ System.Diagnostics.EventLog</PackageDescription>
137137
ReferenceOutputAssembly="false"
138138
OutputItemType="TfmRuntimeSpecificPackageFile"
139139
PrivateAssets="true" />
140+
<ProjectReference Include="$(LibrariesProjectRoot)System.Threading.AccessControl\src\System.Threading.AccessControl.csproj" />
140141
</ItemGroup>
141142

142143
</Project>

src/libraries/System.Diagnostics.PerformanceCounter/src/System.Diagnostics.PerformanceCounter.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);$(NetCoreAppMinimum)-windows;$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
@@ -139,6 +139,7 @@ System.Diagnostics.PerformanceCounter</PackageDescription>
139139

140140
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
141141
<ProjectReference Include="$(LibrariesProjectRoot)System.Configuration.ConfigurationManager\src\System.Configuration.ConfigurationManager.csproj" />
142+
<ProjectReference Include="$(LibrariesProjectRoot)System.Threading.AccessControl\src\System.Threading.AccessControl.csproj" />
142143
</ItemGroup>
143144

144145
</Project>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Security.AccessControl;
5+
using System.Security.Principal;
6+
using System.Threading;
7+
using Xunit;
8+
9+
namespace System.Diagnostics.Tests
10+
{
11+
public static class MutexTests
12+
{
13+
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInAppContainer))] // Can't create global objects in appcontainer
14+
public static void VerifySecurityIdentifier()
15+
{
16+
string mutexName = $"{Guid.NewGuid():N}";
17+
18+
Mutex mutex = null;
19+
20+
// We can't test with the same global mutex used by performance counters, since the mutex was likely already
21+
// initialized elsewhere and perhaps with with different ACLs, so we use a Guid to create a new mutex and
22+
// then simulate the behavior by calling into EnterMutex() like the performance monitor code does.
23+
#pragma warning disable CS0436 // Type conflicts with imported type
24+
NetFrameworkUtils.EnterMutex(mutexName, ref mutex);
25+
#pragma warning restore CS0436
26+
27+
try
28+
{
29+
// This is the SID that is added by EnterMutex().
30+
SecurityIdentifier authenticatedUserSid = new(WellKnownSidType.AuthenticatedUserSid, null);
31+
32+
MutexSecurity security = mutex.GetAccessControl();
33+
AuthorizationRuleCollection rules = security.GetAccessRules(true, true, typeof(SecurityIdentifier));
34+
Assert.Equal(1, rules.Count);
35+
MutexAccessRule accessRule = (MutexAccessRule)rules[0];
36+
SecurityIdentifier sid = (SecurityIdentifier)accessRule.IdentityReference;
37+
Assert.Equal(authenticatedUserSid, sid);
38+
}
39+
finally
40+
{
41+
if (mutex != null)
42+
{
43+
mutex.ReleaseMutex();
44+
mutex.Close();
45+
}
46+
}
47+
}
48+
}
49+
}
Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetFrameworkCurrent)</TargetFrameworks>
44
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
55
</PropertyGroup>
66
<ItemGroup>
7-
<Compile Include="PerformanceCounterTests.cs" />
8-
<Compile Include="PerformanceCounterCategoryTests.cs" />
9-
<Compile Include="ValidationTests.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
10-
<Compile Include="CounterSampleTests.cs" />
11-
<Compile Include="CounterSampleCalculatorTests.cs" />
12-
<Compile Include="CounterCreationDataTests.cs" />
137
<Compile Include="CounterCreationDataCollectionTests.cs" />
14-
<Compile Include="InstanceDataTests.cs" />
8+
<Compile Include="CounterCreationDataTests.cs" />
9+
<Compile Include="CounterSampleCalculatorTests.cs" />
10+
<Compile Include="CounterSampleTests.cs" />
11+
<Compile Include="PerformanceCounterCategoryTests.cs" />
12+
<Compile Include="PerformanceCounterTests.cs" />
13+
<Compile Include="PerformanceDataTests.cs" />
1514
<Compile Include="Helpers.cs" />
15+
<Compile Include="InstanceDataTests.cs" />
16+
<Compile Include="MutexTests.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
17+
<Compile Include="ValidationTests.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
18+
<Compile Include="$(CommonPath)System\Diagnostics\NetFrameworkUtils.cs" Link="Common\System\Diagnostics\NetFrameworkUtils.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'" />
1619
<Compile Include="$(CommonTestPath)System\ShouldNotBeInvokedException.cs" Link="Common\System\ShouldNotBeInvokedException.cs" />
17-
<Compile Include="PerformanceDataTests.cs" />
1820
</ItemGroup>
1921
<ItemGroup>
2022
<Content Include="provider.man" CopyToOutputDirectory="Always" />
@@ -24,4 +26,4 @@
2426
<!-- Some internal types are needed, so we reference the implementation assembly, rather than the reference assembly. -->
2527
<ProjectReference Include="..\src\System.Diagnostics.PerformanceCounter.csproj" SkipUseReferenceAssembly="true" />
2628
</ItemGroup>
27-
</Project>
29+
</Project>

0 commit comments

Comments
 (0)