MSDN Kernel-Mode Driver Architecture学习笔记(3)——Device Objects and Device Stacks (4)

随学随记,暂时未经编程验证 Written by HOOK_TTG(Jamie Jiang)

 

8、            安全的设备对象

本节讲述如何让一个驱动程序的设备对象不被未授权访问。

1)         控制对设备的访问

对设备的访问由由一个安全描述符(它包含一个ACL=访问控制等级)控制。在设备对象被创建或者设置到注册表的时候,设备对象的安全描述符会被指定。

控制WDM驱动程序的设备访问

WDM驱动程序(除了某些总线驱动程序)创建一个设备对象,即插即用管理器为设备确定一个安全描述符。操作次序如下:

1.         PnP管理器调用驱动程序的AddDevice例程。

2.         驱动程序的AddDevice例程调用IoCreateDevice来创建设备对象,并将此设备对象附到设备对象栈上。

3.         PnP管理器更新这个新近创建的设备对象的安全描述符。

对于WDM驱动程序,PnP管理器为设备对象确定安全描述符就像下面这样。

1.         如果设备有一个设置在注册表中的安全描述符,它将被应用于设备栈中的每个设备。

2.         否则,如果设备的安装类有一个设置在注册表中的安全描述符,它将被应用于设备栈中的每个对象。

3.         再否则,PnP管理器保留每个设备对象的默认安全描述符不变。这种情况下,设备栈的默认安全描述符将视设备类型和PDO的设备特性而定。

对于大多数的设备类型和特性,默认的安全描述符将给予管理员完全访问权(GENERIC_ALL),并且给予每个人读取、写入和执行访问(GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE)权限。

如果被以原始模式操作,PnP管理器将不能确定设备对象的安全描述符。如果那样的话,总线驱动程序必须提供一个安全描述符。

控制WDM总线驱动程序的设备访问

WDM总线驱动程序必须为每个支持模式操作的设备的PDO提供一个安全描述符。使用IoCreateDeviceSecure创建一个带安全描述符的设备对象。

如果总线驱动程序不能使用原始模式操作设备,那么它就没必要提供一个安全描述符。就像上面描述的那样,PnP管理器确定安全描述符。总线驱动程序可以提供一个安全描述符,如果它必须要确保它的PDOs具有比默认描述符更严厉的安全设置的话。总线驱动程序指定的任何描述符都会被设置在注册表中的安全设置覆盖掉。

控制非WDM驱动程序的设备访问

WDM驱动程序必须为任何它创建的命名设备对象制定一个默认的安全描述符和类GUID

使用IoCreateDeviceSecure例程来创建明明设备对象并未那个设备指定默认的安全描述符和类GUID。安全描述符被使用一个SDDL的子集定义。更多信息,参看MSDN SDDL for Device Objects

系统为指定的类GUID使用任何注册表中安全设定值覆盖掉默认的安全描述符。驱动程序必须为设备制定一个唯一的GUID。使用GuidGen功能来生成一个唯一的GUID。(GuidGen包含在微软的Windows SDK中。)

 

2)         控制对设备命名空间的访问

Windows驱动程序模型(WDM)中,每个设备对象都有一个相关联的namespace(命名空间)。设备的命名空间中的名字是以设备的名字开始的路径。对于一个被命名为“/Device/DeviceName”的设备,它的命名空间由任意“/Device/DeviceName/FileName”格式的名字的组成。(对于一个文件系统,FileName是文件系统中一个实际的文件名字。)

WDM驱动程序接收关于设备的命名空间中所有名字的打开请求。驱动程序对待对于“/Device/DeviceName”的打开请求,就像对待对设备对象本身的打开一样。如果驱动程序实现了在设备的命名空间中的打开请求,那么它对待“/Device/DeviceName/FileName”的打开请求,就像打开设备对象的命名空间(“file”是指哪里由驱动程序确定)中一个“file(文件)”一样。

大多数驱动程序没有实现对在设备命名空间中的打开操作的支持,但是所有的驱动程序必须提供安全检查来阻止对设备命名空间的未授权访问。默认情况下,对设备命名空间内文件打开请求是否执行安全检查取决于驱动程序——操作系统不检查设备对象ACL.

如果设备对象被设置了FILE_DEVICE_SECURE_OPEN特性,那么系统会将这个设备对象的安全描述符提供给设备命名空间中的所有文件打开请求。驱动程序可以在使用IoCreateDevice或者IoCreateDeviceSecure创建设备对象的时候设置FILE_DEVICE_SECURE_OPEN。对于WDM驱动程序,FILE_DEVICE_SECURE_OPEN还可以被放置在注册表中。对于使用IoCreateDeviceSecure创建的非WDM驱动程序的设备对象也可以将其特性设置在注册表中。

对于不支持命名空间的设备驱动程序,必须使用下面两种方法的一种来确保设备命名空间内的文件打开请求被正确处理:

l  如果驱动程序的设备对象具有FILE_DEVICE_SECURE_OPEN设备特性设置,驱动程序则可以把设备命名空间中的任何打开请求当作设备对象的打开请求。

l  驱动程序可以忽略任何IRP_MJ_CREATE请求而制定一个长度不为0IrpSp->FIleObject->FileName参数。在这种情况下,当设备命名空间的所有文件打开请求被驱动程序忽略时,那么设备的打开请求将受系统的ACL检查支配。(支持独占打开操作的驱动程序必须使用这个选项。)

支持命名空间的设备驱动程序还可以使用两个方法使设备命名空间中的文件打开请求是安全的。

l  驱动程序的设备对象具有FILE_DEVICE_SECURE_OPEN设备特性设置。这就确保了设备的安全设定一律的适用于设备的命名空间。(驱动程序在DispatchCreate例程中实现对命名空间的支持。)

l  驱动程序在DispatchCreate例程中检查任何(file name)文件名的ACLs。(即使在这种情况下,驱动程序页应该设置FILE_DEVICE_SECURE_OPEN特性,除非到设备命名空间的打开操作可以有比设备对象还弱的安全设定。

FILE_DEVICE_SECURE_OPEN特性被设置在栈顶,因此过滤设备对象在附加到栈上后必须复制紧邻低一层的设备对象的Characteristics成员。

3)         用于设备对象的SDDL

安全描述符定义语言(SDDL)被用来描述安全描述符。对于设备对象的安全可以由一个位于INF文件中的SDDL指定,或者由传递给IoCreateDeviceSecure的参数指定。

尽管INF文件支持SDDL的所有内容,但是只有这个语言的一个子集被IoCreateDeviceSecure例程支持。这个子集在这里定义。

用于设备对象的SDDL字符串是这样的格式,“D:P”开始,后跟一个或者多个格式为“(A;;Access;;;SID)”格式的表达式。SID值指定了一个安全标识符,确定Access值适用于谁(例如,一个用户或者组)。Access值指定了给予SID的访问权限。

AccessSID的值如下:

Access

指定一个ACCESS_MASK值确定允许的访问。这个值可以写成一个十六进制的值,格式为“0xhex”,或者一个双字母符号代码序列来表示访问权限。

下列代码可以用来表示一般的访问权。

 

Code

Generic access right

GA

GENERIC_ALL

GR

GENERIC_READ

GW

GENERIC_WRITE

GX

GENERIC_EXECUTE

 

下列代码用来表示特殊访问权。

 

Code

Specific access right

RC

READ_CONTROL

SD

DELETE

WD

WRITE_DAC

WO

WRITE_OWNER

 

要注意的是,GENERIC_ALL准许上面两表列出的所有权限,包括改变ACL的能力。

SID

指定被准许指定访问的SIDSIDs代表帐户、别名、组或者计算机。

下面的SIDs代表机器上的账号。

 

SID 

Description

SY

System

表示操作系统自身,包括他的用户模式组件

LS

Local Service

local services预定义的帐户(属于认证的的和世界的)。仅在Windows XP和更近版本有效。

 NS

Network Service

network services预定义的帐户(属于认证的的和世界的)。

 

下列SIDs表示机器上的组。

 

SID 

Description

BA

Administrators

机器内置的管理员组

BU

Built-in User Group

涵盖所有的本地用户帐户和域上的用户账户

BG

Built-in Guest Group

涵盖使用本地和域来宾帐户登录的所有用户

 

下列SIDs描述用户被认证的范围。

 

SID 

Description

AU

Authenticated Users

任何被本地机器或者域认证的用户。要注意的是,使用内置来宾帐户登录的用户是没有认证的。然而,在机器或者域上的来宾组的个人账号成员是认证的。

AN

Anonymous Logged-on User

任何没有使用标志符登录的用户,比如匿名网络会话。要注意的是,使用内置的来宾帐户登录的用户既不是匿名的也不是认证的。这个SID只在Windows XP和较近版本上有效。

 

下列SIDs描述用户是如何登录进机器的。

 

SID 

Description

IU

Interactive Users

谁最初登录到机器“interactively(人机交互的)”,比如本地登录和远程桌面登录。

NU

Network Logon User

远程访问这个机器的用户,除了人机对话的桌面访问(例如,文件共享或者RPC调用)。

WD

World

Windows XP之前,SID涵盖每个会话,不管是认证的用户、匿名用户还是内置的来宾帐户。

对于Windows XP和较近版本,这个SID不包括匿名登录会话——只有认证的用户和内置的来宾帐户。

要注意的是,World(世界)SID不包括不可信的或者“restricted(受限的)”代码。更多信息参看受限代码DIS描述。

 

下列SID值得特别一提。

 

SID 

Description

RC

Restricted Code

这个SID是用来控制不可信代码访问。对以RC令牌为标准的ACL验证有两个检查组成,一个以令牌的SIDs(包含WD实例)的标准列表为标准,另一个以一个次要列表为标准(通常包含RC和一个原始令牌SIDs的子集)。只有令牌通过了两个校验才能被允许访问。因此,RC实际上使用多个SIDs的组合。

任何ACL指定了RC就必须也指定WD。一旦在ACLRCWD配成对,那么将描述它们两者每个包含不可信代码的超集。

使用资源管理器中的Run As选项,不可信代码可以被编码运行。默认的,World不包括不可信代码。

 

用于设备对象的SDDL例子

这里将描述wdmsec.h创建的预定义SDDL字符串。我们可以用这些作为模板来定义新的用于设备对象的SDDL字符串。

 

SDDL_DEVOBJ_KERNEL_ONLY

“D:P”

 

SDDL_DEVOBJ_KERNEL_ONLY是个“空”ACL。用户模式的代码(包括作为system运行的进程)不能打开这个设备。

PnP总线驱动程序在创建一个PDO的时候可以使用这个描述符。INF可以在那时指定一个用于设备的宽松的安全设定。通过指定这个描述符,总线驱动程序可以确保在INF被处理完成之前不能试图打开设备。

同样的,一个非WDM驱动程序可以使用这个描述符来使得它的设备对象不能被访问到,直到合适的用户模式程序(例如一个安装程序)在注册表中设置了最终的安全描述符为止。

在所有这些情况下,默认是严格安全的,必要时可以宽松一些。

SDDL_DEVOBJ_SYS_ALL

"D:P(A;;GA;;;SY)"

 

SDDL_DEVOBJ_SYS_ALLSDDL_DEVOBJ_KERNEL_ONLY类似,只是除了内核模式代码,系统运行的用户模式代码也允许任意权限打开设备。

遗留的驱动程序可以使用这个ACL以严格安全设置启动,允许个别用户使用SetFileSecurity用户模式函数在它的服务运行时打开设备。这种情况下,这个服务将必须以system运行。

SDDL_DEVOBJ_SYS_ALL_ADM_ALL

"D:P(A;;GA;;;SY)(A;;GA;;;BA)"

 

SDDL_DEVOBJ_SYS_ALL_ADM_ALL允许内核、系统和管理员完全控制设备。没有其他用户可以访问设备。

SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R

"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)"

 

SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R允许内核和系统完全控制控制设备。默认情况下,管理员可以访问整个设备,但是不能改变ACL(管理员必须首先取得设备的控制)。

每个人(the World SID)被给予读访问权。不可信代码不能访问设备。

SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R_RES_R

"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)(A;;GR;;;RC)"

 

SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R_RES_R允许内核和系统完全控制设备。大体同SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_R

要注意的是,遍历访问没有授权给标准用户。因此,对于带有一个命名空间的设备来说,这个不是一个合适的描述符。

     

 

要注意的是,上面的SDDL字符串没有包含任何继承的修饰语。因此,它们仅适用于设备对象,不能用于文件或者注册表键。

 

9、            对于设备对象需要考虑的几点

在设计一个内核驱动程序的时候,要时刻记住下面几点:

l  除了某些文件系统驱动程序,所有I/O操作总是被发送给设备栈的栈顶设备对象。

l  对设备栈的识别是通过使用设备栈中的命名设备对象的名字,或者使用名字的别名,比如符号链接或者设备接口。对于WDM功能驱动程序,命名设备对象由总线驱动程序创建。非WDM驱动程序必须创建它们自己的命名设备对象。

l  底层驱动程序,比如PnP硬件总线驱动程序,为每个它控制的创建一个物理设备对象(PDO)。中间层驱动程序,比如PnP功能驱动程序,创建一个功能设备对象(FDO)。

WDM驱动程序在它的AddDevice例程中创建设备对象,在设备枚举后由PnP管理器调用。

l  对于大多数底层和中间层驱动程序,每个设备对象的设备扩展都是每个驱动程序主要的(或者经常用到的)或者全局数据存储区。许多驱动程序在每个驱动程序创建的设备对象的驱动程序定义的设备扩展中维护其需要的设备状态、设备特有数据和资源。

(另外,关联一个IRP的驱动程序指定的I/O栈存储单元可以被当作一个用于各种数据的操作指定的本地存储区。)

 

你可能感兴趣的:(驱动开发)