如何在服务和用户进程之间共享内存?
我有一组Win32应用程序,它们使用由CreateFileMapping()
和MapViewOfFile()
创建的共享内存段共享信息。其中一个应用是系统服务;其余部分由登录用户启动。在Windows XP上,没有问题。我们将我们的细分市场命名为“Global \ Something”,一切都很顺利。如何在服务和用户进程之间共享内存?
Vista中的额外安全性(并假设为Windows 7)似乎阻止了此架构的运行。普通用户不允许在全局名称空间中创建(Win32错误5)对象。 MSDN表明,如果账户具有“创建全球”特权,那么一切都应该是好的,但实际上似乎并非如此。此外,Vista的“完整性”功能似乎可以防止“低完整性”用户进程访问“高完整性”服务创建的共享内存对象。看起来我应该可以通过一些神奇的SetSecurityDescriptorSacl()
咒语来解决这个问题,但我很难学会说出sacl。
所以问题是:在服务和普通用户进程之间使用共享内存段的正确方法是什么?
为了避免简单回答“关闭UAC”,我们处于一个相当锁定的环境中,这是不可能的。
编辑:服务和用户进程都需要对该段进行读/写访问。
最简单的方法是让您的服务创建共享内存,并在CreateFileMapping中指定一个DACL,以授予常规用户读取共享内存的权限。
普通用户没有创建全局特权,但服务可以具有此特权。如果您必须让您的用户创建共享内存,然后让服务对其进行探测,则可以使用IPC方案,您的用户代码将消息发送到包含文件映射句柄的服务,然后该服务将调用DuplicateHandle以获取参考它。这将需要您的服务以调试权限运行。
创建DACL的最简单方法是使用ConvertStringSecurityDescriptorToSecurityDescriptor,该字符串采用名为SDDL的格式指定ACL。
Writing Secure Code包含了一个关于使用SDDL创建DACL的精彩篇章。
// Error handling removed for brevity
SECURITY_ATTRIBUTES security;
ZeroMemory(&security, sizeof(security));
security.nLength = sizeof(security);
ConvertStringSecurityDescriptorToSecurityDescriptor(
L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GR;;;IU)",
SDDL_REVISION_1,
&security.lpSecurityDescriptor,
NULL);
CreateFileMapping(INVALID_HANDLE_VALUE, &security,
PAGE_READWRITE, sizeHigh, sizeLow, L"Global\\MyObject");
LocalFree(securityDescriptor.lpSecurityDescriptor);
“d:P(A; OICI; GA ;;; SY)(A; OICI; GA ;;; BA)(A; OICI; GR ;;; IU)” 指定DACL。 D:P表示这是一个DACL(而不是SACL,你很少使用SACL),接下来是几个控制谁可以访问的ACE字符串。每个是A(允许)并允许对象并包含继承(OICI)。首先授予系统(SY)和管理员(BA,内置管理员)的所有访问权限(GA - 全部授予)。最后的授予读取(GR)给交互式用户(IU),这是实际登录到会话的用户。
完成此操作后,普通用户应该能够调用OpenFileMapping获取共享映射的句柄,并能够将其映射到其进程中。由于普通用户对该对象的权限有限,因此他们必须确保将其打开并将其映射为只读访问。
如果用户需要write-acccess,则可以将GR替换为GWGR。请注意,这是不安全的 - 当您的服务正在阅读并尝试解析信息时,受限用户将能够修改共享内存,从而导致服务崩溃。
不幸的是,普通用户也必须有写权限 – Clay 2009-05-22 16:55:46