From 32f05affdf5d9a62bc4c068a917ab591f0afc870 Mon Sep 17 00:00:00 2001 From: Justin Stenning Date: Tue, 21 Dec 2021 21:09:08 +1100 Subject: [PATCH] waithandle and mmf security in fullfx+openexisting --- SharedMemory/BufferWithLocks.cs | 60 +++++++++++++++++++++++++++++++-- SharedMemory/CircularBuffer.cs | 55 +++++++++++++++++++++--------- SharedMemory/SharedArray.cs | 15 +++++++-- SharedMemory/SharedBuffer.cs | 55 ++++++++++++++++++++++++++++-- 4 files changed, 163 insertions(+), 22 deletions(-) diff --git a/SharedMemory/BufferWithLocks.cs b/SharedMemory/BufferWithLocks.cs index 89f257a..62e41dd 100644 --- a/SharedMemory/BufferWithLocks.cs +++ b/SharedMemory/BufferWithLocks.cs @@ -28,7 +28,11 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +#if NETFULL +using System.Security.AccessControl; using System.Security.Permissions; +using System.Security.Principal; +#endif using System.Text; using System.Threading; @@ -59,6 +63,18 @@ public abstract class BufferWithLocks : SharedBuffer /// protected EventWaitHandle ReadWaitEvent { get; private set; } +#if NETFULL + private static EventWaitHandleSecurity CreateDefaultWaitHandleSecurity() + { + EventWaitHandleSecurity eventWaitHandleSecurity = new EventWaitHandleSecurity(); + eventWaitHandleSecurity.AddAccessRule(new EventWaitHandleAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), + EventWaitHandleRights.FullControl, AccessControlType.Allow)); + return eventWaitHandleSecurity; + } + + private static readonly EventWaitHandleSecurity waitHandleSecurity = CreateDefaultWaitHandleSecurity(); +#endif + #region Constructors /// @@ -70,8 +86,48 @@ public abstract class BufferWithLocks : SharedBuffer protected BufferWithLocks(string name, long bufferSize, bool ownsSharedMemory) : base(name, bufferSize, ownsSharedMemory) { - WriteWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_write"); - ReadWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_read"); +#if NET45 + EventWaitHandle writeWaitEvent; + if (EventWaitHandle.TryOpenExisting(Name + "_evt_write", out writeWaitEvent)) + { + WriteWaitEvent = writeWaitEvent; + } + else + { + WriteWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_write", out _, waitHandleSecurity); + } + EventWaitHandle readWaitEvent; + if (EventWaitHandle.TryOpenExisting(Name + "_evt_read", out readWaitEvent)) + { + ReadWaitEvent = readWaitEvent; + } + else + { + ReadWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_read", out _, waitHandleSecurity); + } +#elif NET40 || NET35 + WriteWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_write", out _, waitHandleSecurity); + ReadWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_read", out _, waitHandleSecurity); +#elif NETCORE + EventWaitHandle writeWaitEvent; + if (EventWaitHandle.TryOpenExisting(Name + "_evt_write", out writeWaitEvent)) + { + WriteWaitEvent = writeWaitEvent; + } + else + { + WriteWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_write"); + } + EventWaitHandle readWaitEvent; + if (EventWaitHandle.TryOpenExisting(Name + "_evt_read", out readWaitEvent)) + { + ReadWaitEvent = readWaitEvent; + } + else + { + ReadWaitEvent = new EventWaitHandle(true, EventResetMode.ManualReset, Name + "_evt_read"); + } +#endif } #endregion diff --git a/SharedMemory/CircularBuffer.cs b/SharedMemory/CircularBuffer.cs index bab2f9d..95cf92b 100644 --- a/SharedMemory/CircularBuffer.cs +++ b/SharedMemory/CircularBuffer.cs @@ -45,17 +45,17 @@ namespace SharedMemory public unsafe class CircularBuffer : SharedBuffer { #region Public/Protected properties - + /// /// The number of nodes within the circular linked-list /// public int NodeCount { get; private set; } - + /// /// The buffer size of each node /// public int NodeBufferSize { get; private set; } - + /// /// Event signaled when data has been written if the reading index has caught up to the writing index /// @@ -76,7 +76,7 @@ protected virtual long NodeHeaderOffset return 0; } } - + /// /// Where the linked-list nodes are located within the buffer /// @@ -120,7 +120,7 @@ protected virtual Node* this[int i] #region Private field members private NodeHeader* _nodeHeader = null; - + #endregion #region Structures @@ -192,7 +192,7 @@ public struct Node /// Represents the offset relative to where the data for this node can be found. /// public long Offset; - + /// /// Represents the index of the current node. /// @@ -214,6 +214,9 @@ public struct Node /// The name of the shared memory to be created /// The number of nodes within the circular linked-list (minimum of 2) /// The buffer size per node in bytes. The total shared memory size will be Marshal.SizeOf(SharedMemory.SharedHeader) + Marshal.SizeOf(CircularBuffer.NodeHeader) + (Marshal.SizeOf(CircularBuffer.Node) * nodeCount) + (bufferSize * nodeCount) +#if !(NET35) + /// Indicates whether to allow opening an existing if already exists. +#endif /// /// The maximum total shared memory size is dependent upon the system and current memory fragmentation. /// The shared memory layout on 32-bit and 64-bit architectures is:
@@ -225,10 +228,22 @@ public struct Node /// ///
///
- public CircularBuffer(string name, int nodeCount, int nodeBufferSize) - : this(name, nodeCount, nodeBufferSize, true) + public CircularBuffer(string name, int nodeCount, int nodeBufferSize +#if !(NET35) + , bool openExisting = false +#endif + ) + : this(name, nodeCount, nodeBufferSize, true +#if !(NET35) + , openExisting +#endif + ) { - Open(); + Open( +#if !(NET35) + openExisting +#endif + ); } /// @@ -236,12 +251,20 @@ public CircularBuffer(string name, int nodeCount, int nodeBufferSize) /// /// The name of an existing previously created with =true public CircularBuffer(string name) - : this(name, 0, 0, false) + : this(name, 0, 0, false +#if !(NET35) + , false +#endif + ) { Open(); } - private CircularBuffer(string name, int nodeCount, int nodeBufferSize, bool ownsSharedMemory) + private CircularBuffer(string name, int nodeCount, int nodeBufferSize, bool ownsSharedMemory +#if !(NET35) + , bool openExisting = false +#endif + ) : base(name, Marshal.SizeOf(typeof(NodeHeader)) + (Marshal.SizeOf(typeof(Node)) * nodeCount) + (nodeCount * (long)nodeBufferSize), ownsSharedMemory) { #region Argument validation @@ -451,10 +474,10 @@ public virtual int Write(byte[] source, int startIndex = 0, int timeout = 1000) // Copy the data int amount = Math.Min(source.Length - startIndex, NodeBufferSize); - + Marshal.Copy(source, startIndex, new IntPtr(BufferStartPtr + node->Offset), amount); node->AmountWritten = amount; - + // Writing is complete, make readable PostNode(node); @@ -645,9 +668,9 @@ protected virtual void ReturnNode(Node* node) Interlocked.CompareExchange(ref _nodeHeader->ReadEnd, node->Next, blockIndex); #pragma warning restore 0420 - // If a writer thread is waiting on "node available" signal the event + // If a writer thread is waiting on "node available" signal the event if (node->Prev == _nodeHeader->WriteStart) - NodeAvailable.Set(); + NodeAvailable.Set(); } } @@ -710,7 +733,7 @@ public virtual int Read(T[] destination, int startIndex = 0, int timeout = 10 /// The number of bytes read /// If the size of is larger than . public virtual int Read(out T destination, int timeout = 1000) - where T: struct + where T : struct { int structSize = Marshal.SizeOf(typeof(T)); if (structSize > NodeBufferSize) diff --git a/SharedMemory/SharedArray.cs b/SharedMemory/SharedArray.cs index a2c1981..d3f16db 100644 --- a/SharedMemory/SharedArray.cs +++ b/SharedMemory/SharedArray.cs @@ -76,13 +76,24 @@ public T this[int index] /// /// The name of the shared memory array to be created. /// The number of elements to make room for within the shared memory array. - public SharedArray(string name, int length) +#if !(NET35) + /// Indicates whether to allow opening an existing if already exists. +#endif + public SharedArray(string name, int length +#if !(NET35) + , bool openExisting = false +#endif + ) : base(name, Marshal.SizeOf(typeof(T)) * length, true) { Length = length; _elementSize = Marshal.SizeOf(typeof(T)); - Open(); + Open( +#if !(NET35) + openExisting +#endif + ); } /// diff --git a/SharedMemory/SharedBuffer.cs b/SharedMemory/SharedBuffer.cs index fff7b9a..c5011fc 100644 --- a/SharedMemory/SharedBuffer.cs +++ b/SharedMemory/SharedBuffer.cs @@ -29,7 +29,12 @@ using System.IO.MemoryMappedFiles; using System.Linq; using System.Runtime.InteropServices; +#if NETFULL +using System.IO; +using System.Security.AccessControl; using System.Security.Permissions; +using System.Security.Principal; +#endif using System.Text; using System.Threading; @@ -191,6 +196,28 @@ protected SharedBuffer(string name, long bufferSize, bool ownsSharedMemory) #region Open / Close +#if NETFULL + private static readonly WellKnownSidType[] defaultAllowedList = { + WellKnownSidType.CreatorOwnerSid, + WellKnownSidType.BuiltinAdministratorsSid, + WellKnownSidType.LocalSystemSid, + WellKnownSidType.LocalServiceSid, + WellKnownSidType.NetworkServiceSid, + WellKnownSidType.WorldSid + }; + + private FileSecurity BuildSecurityDescriptor(IEnumerable allowedList) + { + FileSecurity fileSecurity = new FileSecurity(); + foreach (WellKnownSidType allowed in allowedList) + { + SecurityIdentifier identity = new SecurityIdentifier(allowed, null); + fileSecurity.AddAccessRule(new FileSystemAccessRule(identity, FileSystemRights.FullControl, AccessControlType.Allow)); + } + return fileSecurity; + } +#endif + /// /// Creates a new or opens an existing shared memory buffer with the name of depending on the value of . /// @@ -200,7 +227,11 @@ protected SharedBuffer(string name, long bufferSize, bool ownsSharedMemory) /// If trying to open a new shared memory buffer that does not exist as a consumer of existing buffer. /// If trying to create a new shared memory buffer with a size larger than the logical addressable space. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] - protected bool Open() + protected bool Open( +#if !(NET35) + bool openExisting = false +#endif + ) { Close(); @@ -210,8 +241,28 @@ protected bool Open() if (IsOwnerOfSharedMemory) { // Create a new shared memory mapping +#if NETFULL && !(NET35) + MemoryMappedFileSecurity memoryMappedFileSecurity = new MemoryMappedFileSecurity(); + memoryMappedFileSecurity.SetSecurityDescriptorBinaryForm(BuildSecurityDescriptor(defaultAllowedList).GetSecurityDescriptorBinaryForm()); + if (openExisting) { + Mmf = MemoryMappedFile.CreateOrOpen(Name, SharedMemorySize, MemoryMappedFileAccess.ReadWrite, + MemoryMappedFileOptions.DelayAllocatePages, memoryMappedFileSecurity, HandleInheritability.Inheritable); + } else { + Mmf = MemoryMappedFile.CreateNew(Name, SharedMemorySize, MemoryMappedFileAccess.ReadWrite, + MemoryMappedFileOptions.DelayAllocatePages, memoryMappedFileSecurity, HandleInheritability.Inheritable); + } +#elif NET35 Mmf = MemoryMappedFile.CreateNew(Name, SharedMemorySize); - +#else + if (openExisting) + { + Mmf = MemoryMappedFile.CreateOrOpen(Name, SharedMemorySize); + } + else + { + Mmf = MemoryMappedFile.CreateNew(Name, SharedMemorySize); + } +#endif // Create a view to the entire region of the shared memory View = Mmf.CreateViewAccessor(0, SharedMemorySize, MemoryMappedFileAccess.ReadWrite); View.SafeMemoryMappedViewHandle.AcquirePointer(ref ViewPtr);