2009-05-22 151 views
5

我有一组Win32应用程序,它们使用由CreateFileMapping()MapViewOfFile()创建的共享内存段共享信息。其中一个应用是系统服务;其余部分由登录用户启动。在Windows XP上,没有问题。我们将我们的细分市场命名为“Global \ Something”,一切都很顺利。如何在服务和用户进程之间共享内存?

Vista中的额外安全性(并假设为Windows 7)似乎阻止了此架构的运行。普通用户不允许在全局名称空间中创建(Win32错误5)对象。 MSDN表明,如果账户具有“创建全球”特权,那么一切都应该是好的,但实际上似乎并非如此。此外,Vista的“完整性”功能似乎可以防止“低完整性”用户进程访问“高完整性”服务创建的共享内存对象。看起来我应该可以通过一些神奇的SetSecurityDescriptorSacl()咒语来解决这个问题,但我很难学会说出sacl。

所以问题是:在服务和普通用户进程之间使用共享内存段的正确方法是什么?

为了避免简单回答“关闭UAC”,我们处于一个相当锁定的环境中,这是不可能的。

编辑:服务和用户进程都需要对该段进行读/写访问。

回答

9

最简单的方法是让您的服务创建共享内存,并在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。请注意,这是不安全的 - 当您的服务正在阅读并尝试解析信息时,受限用户将能够修改共享内存,从而导致服务崩溃。

+1

不幸的是,普通用户也必须有写权限 – Clay 2009-05-22 16:55:46

相关问题