首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MemoryMappedFileSecurity在.NET 6中丢失

MemoryMappedFileSecurity在.NET 6中丢失
EN

Stack Overflow用户
提问于 2022-01-18 15:22:15
回答 2查看 440关注 0票数 1

我有一个使用MemoryMappedFiles进行进程间通信的服务。它已经工作了很多年,并且是在.NET框架4.6.1中开发的。现在是将代码移植到.NET 6的时候了,除了一个问题:内存映射文件的安全ACL,大部分代码都能正常工作。这个论点似乎在.NET 6中消失了。

代码语言:javascript
复制
    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方法中删除。因此,只有以管理员权限运行的进程才能访问内存映射文件。对于非管理进程,从MemoryMappedFileMemoryMappedFile方法引发“拒绝访问”IO异常。

当我创建一个内存映射文件以便非管理进程可以访问时,是否有一种方法来修改安全性?

EN

回答 2

Stack Overflow用户

发布于 2022-01-19 11:50:33

我做了个解决办法。将我需要的调用放在一起,创建具有正确安全性的内存映射文件,并在拥有它的服务中调用它一次。在调用下面的例程之后,我将主线代码更改为使用OpenExisting,以便代码的其余部分可以按预期使用.NET 6库。不太理想,但它解决了问题。

代码语言:javascript
复制
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
        );

    }
}
票数 1
EN

Stack Overflow用户

发布于 2022-07-14 07:44:56

最简单的方法是为每个人设置访问权限:

代码语言:javascript
复制
    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);

然后

代码语言:javascript
复制
            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:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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的用户能够创建全局对象(默认情况下只允许管理员和服务)

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70758093

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档