forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request dotnet#111 from carlossanlop/AnonymousPipeServerSt…
…reamAcl Add AnonymousPipeServerStream method that takes an ACL The original corefx PR was already signed off, but the CI did not finish on time before the 5pm deadline: dotnet/corefx#42392 Approved API proposal: dotnet/corefx#41657 We don't currently have a way to create a pipe with a given ACL in .NET Core. We can modify the ACL, but it would be more secure to have the proper ACL on the pipe from the start. This PR adds a new static class and method that can create an AnonymousPipeServerStream taking a PipeSecurity object, reusing code that can already perform this task.
- Loading branch information
Showing
13 changed files
with
328 additions
and
208 deletions.
There are no files selected for viewing
4 changes: 2 additions & 2 deletions
4
src/libraries/System.IO.Pipes.AccessControl/System.IO.Pipes.AccessControl.sln
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
...stem.IO.Pipes.AccessControl/tests/AnonymousPipeTests/AnonymousPipeServerStreamAclTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.AccessControl; | ||
using System.Security.Principal; | ||
using Xunit; | ||
|
||
namespace System.IO.Pipes.Tests | ||
{ | ||
public class AnonymousPipeServerStreamAclTests : PipeServerStreamAclTestBase | ||
{ | ||
private const PipeDirection DefaultPipeDirection = PipeDirection.In; | ||
private const HandleInheritability DefaultInheritability = HandleInheritability.None; | ||
private const int DefaultBufferSize = 1; | ||
|
||
[Fact] | ||
public void Create_NullSecurity() | ||
{ | ||
CreateAndVerifyAnonymousPipe(expectedSecurity: null).Dispose(); | ||
} | ||
|
||
[Fact] | ||
public void Create_NotSupportedPipeDirection() | ||
{ | ||
Assert.Throws<NotSupportedException>(() => | ||
{ | ||
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), PipeDirection.InOut).Dispose(); | ||
}); | ||
} | ||
|
||
[Theory] | ||
[InlineData((PipeDirection)(int.MinValue))] | ||
[InlineData((PipeDirection)0)] | ||
[InlineData((PipeDirection)4)] | ||
[InlineData((PipeDirection)(int.MaxValue))] | ||
public void Create_InvalidPipeDirection(PipeDirection direction) | ||
{ | ||
Assert.Throws<ArgumentOutOfRangeException>(() => | ||
{ | ||
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), direction).Dispose(); | ||
}); | ||
} | ||
|
||
[Theory] | ||
[InlineData((HandleInheritability)(int.MinValue))] | ||
[InlineData((HandleInheritability)(-1))] | ||
[InlineData((HandleInheritability)2)] | ||
[InlineData((HandleInheritability)(int.MaxValue))] | ||
public void Create_InvalidInheritability(HandleInheritability inheritability) | ||
{ | ||
Assert.Throws<ArgumentOutOfRangeException>(() => | ||
{ | ||
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), inheritability: inheritability).Dispose(); | ||
}); | ||
} | ||
|
||
[Theory] | ||
[InlineData(int.MinValue)] | ||
[InlineData(-1)] | ||
public void Create_InvalidBufferSize(int bufferSize) | ||
{ | ||
Assert.Throws<ArgumentOutOfRangeException>(() => | ||
{ | ||
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), bufferSize: bufferSize).Dispose(); | ||
}); | ||
} | ||
|
||
public static IEnumerable<object[]> Create_ValidParameters_MemberData() => | ||
from direction in new[] { PipeDirection.In, PipeDirection.Out } | ||
from inheritability in Enum.GetValues(typeof(HandleInheritability)).Cast<HandleInheritability>() | ||
from bufferSize in new[] { 0, 1 } | ||
select new object[] { direction, inheritability, bufferSize }; | ||
|
||
[Theory] | ||
[MemberData(nameof(Create_ValidParameters_MemberData))] | ||
public void Create_ValidParameters(PipeDirection direction, HandleInheritability inheritability, int bufferSize) | ||
{ | ||
CreateAndVerifyAnonymousPipe(GetBasicPipeSecurity(), direction, inheritability, bufferSize).Dispose(); | ||
} | ||
|
||
public static IEnumerable<object[]> Create_CombineRightsAndAccessControl_MemberData() => | ||
from rights in Enum.GetValues(typeof(PipeAccessRights)).Cast<PipeAccessRights>() | ||
from accessControl in new[] { AccessControlType.Allow, AccessControlType.Deny } | ||
select new object[] { rights, accessControl }; | ||
|
||
// These tests match NetFX behavior | ||
[Theory] | ||
[MemberData(nameof(Create_CombineRightsAndAccessControl_MemberData))] | ||
public void Create_CombineRightsAndAccessControl(PipeAccessRights rights, AccessControlType accessControl) | ||
{ | ||
// These are the two cases that create a valid pipe when using Allow | ||
if ((rights == PipeAccessRights.FullControl || rights == PipeAccessRights.ReadWrite) && | ||
accessControl == AccessControlType.Allow) | ||
{ | ||
VerifyValidSecurity(rights, accessControl); | ||
} | ||
// When creating the PipeAccessRule for the PipeSecurity, the PipeAccessRule constructor calls AccessMaskFromRights, which explicilty removes the Synchronize bit from rights when AccessControlType is Deny | ||
// and rights is not FullControl, so using Synchronize with Deny is not allowed | ||
else if (rights == PipeAccessRights.Synchronize && accessControl == AccessControlType.Deny) | ||
{ | ||
Assert.Throws<ArgumentException>("accessMask", () => | ||
{ | ||
PipeSecurity security = GetPipeSecurity(WellKnownSidType.BuiltinUsersSid, PipeAccessRights.Synchronize, AccessControlType.Deny); | ||
}); | ||
} | ||
// Any other case is not authorized | ||
else | ||
{ | ||
PipeSecurity security = GetPipeSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl); | ||
Assert.Throws<UnauthorizedAccessException>(() => | ||
{ | ||
AnonymousPipeServerStreamAcl.Create(DefaultPipeDirection, DefaultInheritability, DefaultBufferSize, security).Dispose(); | ||
}); | ||
} | ||
} | ||
|
||
[Theory] | ||
[InlineData(PipeAccessRights.ReadWrite | PipeAccessRights.Synchronize, AccessControlType.Allow)] | ||
public void Create_ValidBitwiseRightsSecurity(PipeAccessRights rights, AccessControlType accessControl) | ||
{ | ||
VerifyValidSecurity(rights, accessControl); | ||
} | ||
|
||
private void VerifyValidSecurity(PipeAccessRights rights, AccessControlType accessControl) | ||
{ | ||
PipeSecurity security = GetPipeSecurity(WellKnownSidType.BuiltinUsersSid, rights, accessControl); | ||
CreateAndVerifyAnonymousPipe(security).Dispose(); | ||
} | ||
|
||
private AnonymousPipeServerStream CreateAndVerifyAnonymousPipe( | ||
PipeSecurity expectedSecurity, | ||
PipeDirection direction = DefaultPipeDirection, | ||
HandleInheritability inheritability = DefaultInheritability, | ||
int bufferSize = DefaultBufferSize) | ||
{ | ||
AnonymousPipeServerStream pipe = AnonymousPipeServerStreamAcl.Create(direction, inheritability, bufferSize, expectedSecurity); | ||
Assert.NotNull(pipe); | ||
|
||
if (expectedSecurity != null) | ||
{ | ||
PipeSecurity actualSecurity = pipe.GetAccessControl(); | ||
VerifyPipeSecurity(expectedSecurity, actualSecurity); | ||
} | ||
|
||
return pipe; | ||
} | ||
|
||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
src/libraries/System.IO.Pipes.AccessControl/tests/PipeServerStreamAclTestBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.AccessControl; | ||
using System.Security.Principal; | ||
using Xunit; | ||
|
||
namespace System.IO.Pipes.Tests | ||
{ | ||
public class PipeServerStreamAclTestBase | ||
{ | ||
protected PipeSecurity GetBasicPipeSecurity() | ||
{ | ||
return GetPipeSecurity( | ||
WellKnownSidType.BuiltinUsersSid, | ||
PipeAccessRights.FullControl, | ||
AccessControlType.Allow); | ||
} | ||
|
||
protected PipeSecurity GetPipeSecurity(WellKnownSidType sid, PipeAccessRights rights, AccessControlType accessControl) | ||
{ | ||
var security = new PipeSecurity(); | ||
SecurityIdentifier identity = new SecurityIdentifier(sid, null); | ||
var accessRule = new PipeAccessRule(identity, rights, accessControl); | ||
security.AddAccessRule(accessRule); | ||
return security; | ||
} | ||
|
||
protected void VerifyPipeSecurity(PipeSecurity expectedSecurity, PipeSecurity actualSecurity) | ||
{ | ||
Assert.Equal(typeof(PipeAccessRights), expectedSecurity.AccessRightType); | ||
Assert.Equal(typeof(PipeAccessRights), actualSecurity.AccessRightType); | ||
|
||
List<PipeAccessRule> expectedAccessRules = expectedSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier)) | ||
.Cast<PipeAccessRule>().ToList(); | ||
|
||
List<PipeAccessRule> actualAccessRules = actualSecurity.GetAccessRules(includeExplicit: true, includeInherited: false, typeof(SecurityIdentifier)) | ||
.Cast<PipeAccessRule>().ToList(); | ||
|
||
Assert.Equal(expectedAccessRules.Count, actualAccessRules.Count); | ||
if (expectedAccessRules.Count > 0) | ||
{ | ||
Assert.All(expectedAccessRules, actualAccessRule => | ||
{ | ||
int count = expectedAccessRules.Count(expectedAccessRule => AreAccessRulesEqual(expectedAccessRule, actualAccessRule)); | ||
Assert.True(count > 0); | ||
}); | ||
} | ||
} | ||
|
||
protected bool AreAccessRulesEqual(PipeAccessRule expectedRule, PipeAccessRule actualRule) | ||
{ | ||
return | ||
expectedRule.AccessControlType == actualRule.AccessControlType && | ||
expectedRule.PipeAccessRights == actualRule.PipeAccessRights && | ||
expectedRule.InheritanceFlags == actualRule.InheritanceFlags && | ||
expectedRule.PropagationFlags == actualRule.PropagationFlags; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
src/libraries/System.IO.Pipes/src/MatchingRefApiCompatBaseline.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.