我有一个使用MemoryMappedFiles进行进程间通信的服务。它已经工作了很多年,并且是在.NET框架4.6.1中开发的。现在是将代码移植到.NET 6的时候了,除了一个问题:内存映射文件的安全ACL,大部分代码都能正常工作。这个论点似乎在.NET 6中消失了。
fs = new FileStream(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
FileSecurity fSec = File.GetAccessControl(FileName);
fSec.AddAccessRule(new FileSystemAccessRule("everyone", FileSystemRights.FullControl, AccessControlType.Allow));
File.SetAccessControl(FileName, fSec);
if (fs.Length == 0)
fs.SetLength(_SectionSize);
long fLen = fs.Length;
MemoryMappedFileSecurity security = new MemoryMappedFileSecurity();
security.AddAccessRule(new AccessRule<MemoryMappedFileRights>("everyone", MemoryMappedFileRights.FullControl, AccessControlType.Allow));
//Name = @"Global\DCCCache"; // "Global\" when running as a service so session 0 stuff available to everyone
_MMFHandle = MemoryMappedFile.CreateFromFile(fs, Name, _SectionSize, MemoryMappedFileAccess.ReadWrite, security, HandleInheritability.Inheritable, false);
_VAHandle = _MMFHandle.CreateViewAccessor();这一切工作,并允许非管理用户进程访问内存映射文件。.NET 6将安全参数从.CreateFromFile方法中删除。因此,只有以管理员权限运行的进程才能访问内存映射文件。对于非管理进程,从MemoryMappedFile的MemoryMappedFile方法引发“拒绝访问”IO异常。
当我创建一个内存映射文件以便非管理进程可以访问时,是否有一种方法来修改安全性?
发布于 2022-01-19 11:50:33
我做了个解决办法。将我需要的调用放在一起,创建具有正确安全性的内存映射文件,并在拥有它的服务中调用它一次。在调用下面的例程之后,我将主线代码更改为使用OpenExisting,以便代码的其余部分可以按预期使用.NET 6库。不太理想,但它解决了问题。
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace MMFService {
internal class MMFNet6Shim : IDisposable {
private bool win32Result = false;
private int cbSid = SECURITY_MAX_SID_SIZE;
private SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES();
private SafeMemoryMappedFileHandle hFile;
private const int SDDL_REVISION_1 = 1;
private const int SECURITY_MAX_SID_SIZE = 68;
private const int PAGE_READWRITE = 0x04;
private const int FILE_MAP_WRITE = 0X02;
public MMFNet6Shim(FileStream fs, string DBName) {
win32Result = ConvertStringSecurityDescriptorToSecurityDescriptor("D:(A;OICI;GA;;;WD)", SDDL_REVISION_1, out securityAttributes.lpSecurityDescriptor, IntPtr.Zero);
if (!win32Result)
throw new Exception("ConvertStringSecurityDescriptorToSecurityDescriptor", new Win32Exception(Marshal.GetLastWin32Error()));
securityAttributes.nLength = Marshal.SizeOf(securityAttributes);
securityAttributes.bInheritHandle = false;
long fLen = fs.Length;
hFile = CreateFileMapping(fs.SafeFileHandle, ref securityAttributes, PAGE_READWRITE, 0, Convert.ToInt32(fLen), DBName);
if (hFile.IsInvalid)
throw new Exception("CreateFileMapping", new Win32Exception(Marshal.GetLastWin32Error()));
}
public void Dispose() {
if(!hFile.IsInvalid)
hFile.Close();
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor
(
[In] string StringSecurityDescriptor,
[In] int StringSDRevision,
[Out] out IntPtr SecurityDescriptor,
[Out] IntPtr SecurityDescriptorSize
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalFree([In] IntPtr hMem);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeMemoryMappedFileHandle CreateFileMapping(
[In] SafeFileHandle hFile,
[In][Optional] ref SECURITY_ATTRIBUTES lpAttributes,
[In] int flProtect,
[In] int dwMaximumSizeHigh,
[In] int dwMaximumSizeLow,
[In][Optional] string lpName
);
}
}发布于 2022-07-14 07:44:56
最简单的方法是为每个人设置访问权限:
using System.Runtime.InteropServices;
[DllImport("advapi32.dll", EntryPoint = "SetSecurityInfo", CallingConvention = CallingConvention.Winapi,
SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
private static extern uint SetSecurityInfoByHandle(SafeHandle handle, uint objectType, uint securityInformation,
byte[]? owner, byte[]? group, byte[]? dacl, byte[]? sacl);然后
mmfile = MemoryMappedFile.CreateNew("Global\\jdfghdfghsd", requiredsize, MemoryMappedFileAccess.ReadWrite);
if (SetSecurityInfoByHandle(mmfile.SafeMemoryMappedFileHandle, 1, 4, null, null, null, null) != 0)
throw new Exception("MemoryMappedFile set security failed");如果需要,请设置自定义访问权限,请参阅SetSecurityInfo帮助
所以,示例应用程序:
App1:
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
[DllImport("advapi32.dll", EntryPoint = "SetSecurityInfo", CallingConvention = CallingConvention.Winapi,
SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
static extern uint SetSecurityInfoByHandle(SafeHandle handle, uint objectType, uint securityInformation,
byte[]? owner, byte[]? group, byte[]? dacl, byte[]? sacl);
var mmfile = MemoryMappedFile.CreateNew("Global\\dsfgsdfsdf", 4, MemoryMappedFileAccess.ReadWrite);
if (SetSecurityInfoByHandle(mmfile.SafeMemoryMappedFileHandle, 1, 4, null, null, null, null) != 0)
throw new Exception("Access rights set up failed");
mmfile.CreateViewAccessor(0, 4).Write(0, 234);
Console.ReadLine();App2:
using System.IO.MemoryMappedFiles;
Console.WriteLine(MemoryMappedFile.OpenExisting("Global\\dsfgsdfsdf", MemoryMappedFileRights.ReadWrite).CreateViewAccessor(0, 4).ReadInt32(0));
Console.ReadLine();运行app1,然后运行app2。它应该排放234。然后按Enter键输入app1。确保运行app1的用户能够创建全局对象(默认情况下只允许管理员和服务)
https://stackoverflow.com/questions/70758093
复制相似问题