现在的位置: 首页 > 综合 > 正文

Windows 安全模型:每个驱动程序作者都需要了解的内容

2014年02月19日 ⁄ 综合 ⁄ 共 12176字 ⁄ 字号 评论关闭
文章目录
On This Page
简介
简介
Windows 安全模型
Windows 安全模型
安全场景:创建一个文件
安全场景:创建一个文件
驱动程序安全责任
驱动程序安全责任
行动指南和资源 行动指南和资源

本文提供关于为 Microsoft Windows 家族操作系统编写安全的内核模式驱动程序的信息。其中描述了如何将 Windows 安全模型应用于驱动程序,并解释驱动程序作者必须采取哪些措施来确保其设备的安全性。

简介

Windows 安全模型基于安全对象。操作系统的每个组件都必须确保其负责的对象的安全性。因此,驱动程序必须保证其设备和设备对象的安全性。


文总结了如何将 Windows
安全模型应用于内核模式驱动程序,以及驱动程序编写人员必须采取哪些措施来确保其设备的安全性。一些类型的设备适用于附加的设备特定要求。请参阅
Microsoft Windows Driver Development Kit (DDK) 中的设备特定的文档,以了解详细信息。

注意:
关于本文中讨论的例程和问题的当前文档,请参见 Windows DDK 最新版本。关于如何获取当前的 DDK 的信息,请参见http://www.microsoft.com/whdc/devtools/ddk/default.mspx
.

Windows 安全模型

Windows 安全模型主要基于每个对象的权限,以及少量的系统级特权。安全对象包括(但不限于)进程、线程、事件和其它同步对象,以及文件、目录和设备。


于每种类型的对象,一般的读、写和执行权限都映射到详细的对象特定权限中。例如,对于文件和目录,可能的权限包括读或写文件或目录的权限、读或写扩展的文
件属性的权限、遍历目录的权限,以及写对象的安全描述符的权限。更多信息(包括完整的权限列表)请参见 MSDN
库的“安全性”节中的“安全性(常规)”,该库位于http://msdn.microsoft.com
.

安全模型涉及以下概念:

安全标识符 (SID)

存取令牌

安全描述符

访问控制列表 (ACL)

特权

安全标识符 (SID)

安全标识符(SID,也称为安全主体
)标识一个用户、组或登录会话。每个用户都有一个唯一的 SID,在登录时由操作系统检索。

SID 由一个权威机构(如操作系统或域服务器)分发。一些 SID 是众所周知的,并且具有名称和标识符。例如,SID S-1-1-0 标识所有人(或全世界)。

存取令牌

每个进程都有一个存取令牌。存取令牌描述进程的完整的安全上下文。它包含用户的 SID、用户所属组的 SID、登录会话的 SID,以及授予用户的系统级特权列表。


认情况下,当进程的线程与安全对象交互时,系统使用进程的主存取令牌。但是,一个线程可以模拟一个客户端帐户。当一个线程模拟客户端帐户时,它除了拥有自
己的主令牌之外还有一个模拟令牌。模拟令牌描述线程正在模拟的用户帐户的安全上下文。模拟在远程过程调用 (Remote Procedure
Call, RPC) 处理中尤其常见。

描述线程或进程的受限制的安全上下文的存取令牌被称为受限令牌
。受限令牌中的 SID 只能设置为拒绝访问安全对象,而不能设置为允许访问安全对象。此外,令牌可以描述一组有限的系统级特权。用户的 SID 和标识保持不变,但是在进程使用受限令牌时,用户的访问权限是有限的。CreateRestrictedToken
函数创建一个受限令牌。

受限令牌对于运行不可信代码(例如电子邮件附件)很有用。当您右键单击可执行文件,选择“运行方式”并选择“保护我的计算机和数据不受未授权程序的活动影响”时,Microsoft Windows XP 就会使用受限令牌。

安全描述符

每个命名的 Windows 对象都有一个安全描述符,一些未命名的对象也有。安全描述符描述对象的所有者和组 SID,以及对象的 ACL。

对象的安全描述符通常由创建该对象的函数创建。当驱动程序调用 IoCreateDevice
IoCreateDeviceSecure
例程来创建设备对象时,系统将一个安全描述符应用于创建的设备对象并为对象设置 ACL。对于大多数设备,ACL 是在设备信息 (INF) 文件中指定的。

访问控制列表

访问控制列表 (ACL) 允许细粒度地控制对对象的访问。ACL 是每个对象的安全描述符的一部分。

每个 ACL 包含零个或多个访问控制条目 (ACE)。而每个 ACE 仅包含一个 SID,用来标识用户、组或计算机以及该 SID 拒绝或允许的权限列表。

设备对象的 ACL

可以使用三种方式设置设备对象的 ACL:

在其设备类型的默认安全描述符中设置。

RtlCreateSecurityDescriptor
函数通过编程方式创建,并由 RtlSetDaclSecurityDescriptor
函数进行设置。

在设备 INF 文件中使用安全描述符定义语言 (Security Descriptor Definition Language, SDDL) 指定,或者在对 IoCreateDeviceSecure
例程的调用中指定。

所有新的驱动程序都应该在 INF 文件中使用 SDDL 为其设备对象指定 ACL。

SDDL 是一种可扩展的描述语言,允许组件以字符串格式创建 ACL。用户模式和内核模式代码都使用 SDDL。图 1 显示了设备对象的 SDDL 字符串的格式。

图 1. 设备对象的 SDDL 字符串

Access 值指定允许的访问类型。SID 值指定一个安全标识符,确定将 Access 值应用于谁(例如一个用户或组)。

例如,下面的 SDDL 字符串允许系统 (SY) 获得任何访问权限,而仅允许其他所有人 (WD) 获得读访问权:

“D:P(A;;GA;;;SY)(A;;GR;;;WD)”

头文件 wdmsec.h 还包括一组适用于设备对象的预定义 SDDL 字符串。例如,头文件按如下方式定义 SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX:

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


个字符串的第一节允许内核和操作系统 (SY) 完全控制设备。第二节允许内置管理员组 (BA) 中的任何人访问整个设备,但是不能更改
ACL。第三节允许所有人 (WD) 读或写设备,第四节将相同的权限授予不可信代码
(RC)。驱动程序可以按原样使用预定义字符串或者将其用作设备对象特定的字符串模型。

堆栈中的所有设备对象都应该具有相同的 ACL。更改堆栈中一个设备对象的 ACL 会更改整个设备堆栈的 ACL。


而,将新设备对象添加到堆栈中不会更改任何 ACL,无论是新设备对象的 ACL(如果它有 ACL)还是堆栈中任何现有设备对象的
ACL。当驱动程序创建一个新的设备对象并将其附加到堆栈顶部时,驱动程序应该将堆栈的 ACL
复制到新设备对象,方法是从该设备对象的下一层驱动程序中复制 DeviceObject.Characteristics
字段。

IoCreateDeviceSecure
例程支持 SDDL 字符串的一个子集,它使用预定义的 SID(例如 WD 和 SY)。用户模式 API 和 INF 文件支持所有 SDDL 语法。

使用 ACL 进行安全检查

当进程请求访问一个对象时,安全检查将对象的 ACL 与调用方存取令牌中的 SID 进行比较。

系统按照严格的从上往下的顺序比较 ACE,并在第一个相关的匹配处停止。因此,在创建 ACL 时,应该始终将拒绝 ACE 放在相应且允许的 ACE 上方。下面的例子展示了比较的方法。

例子 1:将 ACL 与存取令牌比较

例子 1 显示系统如何将 ACL 与调用方进程的存取令牌进行比较。假设调用方想要打开具有表 1 所示 ACL 的文件。

表 1. 示例文件 ACL

权限 SID 访问权

允许

Accounting

写、删除

允许

Sales

追加

拒绝

Legal

追加、写、删除

允许

Everyone

此 ACL 有 4 个 ACE,分别应用于 Accounting、Sales、Legal 和 Everyone 组。

下一步,假设请求进程的存取令牌包含一个用户和三个组的 SID,顺序如下:

用户 Jim (S-1-5-21...)

组 Accounting (S-1-5-22...)

组 Legal (S-1-5-23...)

组 Everyone (S-1-1-0)


比较文件 ACL 与存取令牌时,系统首先在文件的 ACL 中查找用户 Jim 的 ACE。没有找到,所以接下去它查找 Accounting
组的 ACE。如表 1 所示,Accounting 组的 ACE 就是文件的 ACL 中的第一个条目,因此 Jim
的进程被授予写或删除文件的权限,然后比较过程停止。相反,如果 ACL 中 Legal 组的 ACE 在 Accounting 组的 ACE
前面,那么进程将无法获得对文件的写、追加和删除权限。

例子 2:将 ACL 与受限令牌比较

系统将 ACL 与受限令牌比较的方式与将其与不受限令牌比较的方式相同。但是,受限令牌中的拒绝 SID 只能匹配 ACL 中的拒绝 ACE。

例子 2 显示系统如何将文件的 ACL 与受限令牌进行比较。假设文件具有与表 1 中所示的相同的 ACL。但是,在这个例子中,进程具有包含下列 SID 的受限令牌:

用户 Jim (S-1-5-21...) 拒绝

组 Accounting (S-1-5-22...) 拒绝

组 Legal (S-1-5-23...) 拒绝

组 Everyone (S-1-1-0)


件的 ACL 没有列出 Jim 的 SID,所以系统继续比较 Accounting 组 SID。尽管文件的 ACL 中存在
Accounting 组的 ACE,并且这条 ACE 允许访问,但是它与进程的受限令牌中的 SID(它拒绝访问)不匹配。因此,系统继续比较
Legal 组 SID。文件的 ACL 包含 Legal 组的一条 ACE(拒绝访问),因此进程不能写、追加或删除文件。

特权

特权是用户在本地计算机上执行与系统相关的操作(例如加载驱动程序、更改时间或关闭系统)的权限。

特权与访问权不同,因为特权应用于与系统(而不是对象)相关的任务和资源,并且特权由系统管理员(而不是操作系统)授予用户或组。

每个进程的存取令牌都包含一个授予该进程的特权列表。特权必须在使用之前专门启用。管理员使用 Windows 控制面板
中的管理工具
来启用和审核特权的使用;也可以通过编程方式启用特权。

安全场景:创建一个文件

当进程创建文件或对象的句柄时,系统使用“Windows 安全模型”中阐述的安全构造。图 2 显示当用户模式进程试图创建一个文件时触发的与安全相关的操作。


secmod2.gif
Click to view full-size image.

图 2. 处理 CreateFile 请求

图 2 显示当用户模式应用程序调用 CreateFile
函数时系统如何响应。下面对圆圈中的数字进行说明:

1.

用户模式应用程序调用 CreateFile
函数,传递一个有效的 Microsoft Win32 文件名。

2.

用户模式 Kernel32.dll 将请求传递给 Ntdll.dll,该 DLL 将 Win32 名称转换为 Microsoft Windows NT 文件名。

3.

Ntdll.dll 使用 Windows NT 文件名调用 NtCreateFile
函数。在 Ntoskrnl.exe 内部,I/O 管理器处理 NtCreateFile

4.

I/O 管理器将请求重新打包成一个对象管理器调用。

5.

对象管理器解析符号链接,并确保用户对将在其中创建文件的路径具有遍历权限。详细信息请参见本文稍后的“对象管理器中的安全检查”。

6.

对象管理器调用拥有与请求关联的底层对象类型的系统组件。对于一个文件创建请求,该组件就是 I/O 管理器,它拥有设备对象。

7.

I/O 管理器检查设备对象的安全描述符与用户进程的存取令牌,以确保用户具有所需的设备访问权。详细信息请参见本文稍后的“I/O 管理器中的安全检查”。

8.

如果用户进程具有所需的访问权,那么 I/O 管理器创建一个句柄并将一个 IRP_MJ_CREATE 请求发送到设备或文件系统的驱动程序。

9.

该驱动程序根据需要执行额外的安全检查。例如,如果请求在设备的命名空间中指定了一个对象,那么驱动程序必须确保调用方具有所需的访问权。详细信息请参见本文稍后的“驱动程序中的安全检查”。

对象管理器中的安全检查


查访问权限的责任属于可以执行这类检查的最高层组件。如果对象管理器能够验证调用方的访问权,那么它就是这个最高层组件。否则,对象管理器将请求传递给负
责底层对象类型的组件。然后该组件验证访问权(如果它拥有验证权限);如果无法验证,它将请求传递给更底层的组件,例如驱动程序。

对象管理
器检查简单对象类型(例如事件和互斥锁)的 ACL。对于具有命名空间的对象,由该类型的所有者执行安全检查。例如,I/O
管理器被认为是设备对象和文件对象类型的所有者。如果对象管理器在解析名称时找到了设备对象或文件对象的名称,那么它将该名称传递给 I/O
管理器,正如“安全场景:创建一个文件”中所示的文件创建场景一样。然后 I/O
管理器检查访问权限(如果它具有该权限的话)。如果该名称指定一个设备命名空间内部的对象,那么 I/O
管理器接下来会将名称传递给设备(或文件系统)驱动程序,该驱动程序负责验证请求的访问。

I/O 管理器中的安全检查


I/O 管理器创建一个句柄时,它检查对象的权限和进程的存取令牌,然后将授予用户的权限存储为句柄的一部分。在以后 I/O 请求到达时,I/O
管理器检查句柄中记录的权限,以确保进程拥有执行请求的 I/O 操作的权限。例如,如果进程在以后请求一个写操作,那么 I/O
管理器检查句柄中的权限以确保调用方具有对对象的写访问权。

如果句柄重复,那么可以从副本中删除权限,但是不能将权限添加到副本中。

当 I/O 管理器创建对象时,它将一般的 Win32 访问模式转换为对象特定的权限。例如,以下权限适用于文件和目录。

Win32 访问模式 对象特定的权限

GENERIC_READ

ReadData | ReadAttributes | ReadEA

GENERIC_WRITE

WriteData | WriteAttributes | WriteEA

GENERIC_EXECUTE

ReadAttributes | Execute/Traverse

GENERIC_ALL

所有权限


创建一个文件,进程必须具有对目标路径中的父目录的遍历权限。例如,要创建
/Device/Floppy0/Directory/File.txt,进程必须具有遍历 /Device、/Device/Floppy0 和
/Device/Floppy0/Directory 的权限。I/O 管理器只检查这些目录的遍历权限。

I/O
管理器在分析文件名时检查遍历权限。如果文件名是一个符号链接,那么 I/O
管理器将其解析为完整的路径,然后从根目录开始检查遍历权限。例如,假设符号链接 /DosDevices/A 映射为 Windows NT 设备名
/Device/Floppy0。进程必须具有对 /Device 目录的遍历权限。

驱动程序中的安全检查

实际上,
操作系统内核将每个驱动程序都视为具有其自己的命名空间的文件系统。因此,当调用方试图在设备命名空间中创建对象时,I/O
管理器就会检查进程是否具备对该路径中的目录的遍历权限。但是,默认情况下,I/O
管理器不对命名空间执行安全检查。驱动程序负责保证其命名空间的安全性。

驱动程序安全责任

设备的驱动程序负责保证未授权用户没有对设备的访问权。保证设备安全性涉及:

创建安全的设备对象。

保护设备命名空间。

在 INF 文件中指定设备特征和安全设置。

安全地定义和处理 IOCTL。

创建安全的设备对象


个设备对象都有一个安全描述符,它包含一个用于控制对设备的访问的 ACL。一般来讲,安全描述符是在创建设备对象的同时创建的,ACL 是在设备的
INF 文件中指定的,但具体细节因驱动程序在设备堆栈中的位置和其控制的设备类型不同而异。下面的章节描述以下驱动程序的特定要求:

总线驱动程序

其它即插即用和 Windows Driver Model (WDM) 驱动程序

传统设备

总线驱动程序

可以在 RAW 模式下运行的设备的 WDM 总线驱动程序必须使用 IoCreateDeviceSecure
例程来创建其物理设备对象 (PDO) 并设置强壮的默认 ACL。例如,RAW 模式设备 PDO 的 ACL 可以设置 SDDL_DEVOBJ_SYS_ALL,这允许系统 (SY) 进行访问,但是拒绝其他所有人进行访问:“D:P(A;;GA;;;SY)”


个 ACL 甚至会阻止管理员访问设备。但是,设备的 INF 文件可以放宽 ACL 条件,以允许管理员或其他合法用户进行访问。因为 RAW
模式设备无需 INF 文件就能启动,所以在创建设备对象时指定一个强壮的默认 ACL 非常关键。否则,如果设备没有 INF
文件,那么用户无需进行任何安全检查就可以获得对设备的访问权。

如果设备不能在 RAW 模式下使用,那么驱动程序可以调用 IoCreateDevice
IoCreateDeviceSecure
例程来创建设备对象。如果驱动程序使用 IoCreateDevice
,那么 PnP 管理器应用默认的安全描述符(正如它对其它 WDM 设备对象所做的一样)。但是,如果 PDO 需要比默认设置更严格的安全检查,那么 INF 文件应该提供一个安全描述符。

即插即用和 WDM 驱动程序

即插即用 (PnP) 和 WDM 驱动程序(总线驱动程序除外,该驱动程序已在“总线驱动程序”中描述)调用 IoCreateDevice
例程来创建一个未命名的设备对象。PnP 管理器将一个默认的安全描述符应用于每一个这类未命名设备对象。

设备的 INF 文件应该指定设备特定的 ACL。PnP 管理器确保将 ACL 应用于设备堆栈中的所有设备对象,从而在允许其它进程访问设备之前保护整个堆栈。

在 INF 文件中,ACL 通过 SDDL 指定并包含在 AddReg 节中。AddReg 节还可以设置设备特征,例如 FILE_DEVICE_SECURE_OPEN。

即插即用和 WDM 驱动程序不应使用 IoCreateDeviceSecure
例程来创建附加到设备堆栈的设备对象。但是,一些即插即用驱动程序可以创建已命名控制设备对象,这类对象不会附加到设备堆栈。必须使用 IoCreateDeviceSecure
例程来创建这类控制设备对象。

传统设备

传统设备指不受 PnP 管理器控制的设备。传统驱动程序必须在 /Device 对象目录中创建至少一个已命名设备对象来接收 I/O 请求。

要保护传统设备的设备对象,其驱动程序必须调用 IoCreateDeviceSecure
例程来创建已命名设备对象,并为设备设置默认的安全描述符和类 GUID。安全描述符应该指定一个强壮的默认 ACL,例如
SDDL_DEVOBJ_SYS_ALL。这项设置允许内核模式代码和用户模式代码以系统身份运行来访问设备对象。在运行时,驱动程序的服务(以系统身份
运行)可以使用 SetFileSecurity
用户模式函数将设备向用户打开。

保护设备命名空间

驱动程序在调用方试图打开设备命名空间中的对象时检查安全性。调用方可以使用下列任一种格式来指定对象。

路径 描述

/Device/设备名称

设备名称的设备对象

/Device/设备名称/

设备名称上的顶级目录

/Device/设备名称/文件

设备名称上的文件

I/O 管理器被视为设备对象的类型所有者;因此,I/O 管理器负责在调用方以“/Device/设备名称”的形式指定名称时检查安全性。

驱动程序被视为其命名空间中的对象的类型所有者。命名空间包含设备的顶级目录(/Device/设备名称/)和属于该目录的任何对象(/Device/设备名称/文件)。

安全地打开设备

用户通过指定设备名称来打开设备。例如:

/Device/Serial0

当 I/O 管理器接收到打开请求时,它解析目标设备名称并检查进程存取令牌中的权限和目标设备对象的 ACL。通过拒绝对其设备对象的遍历权限,驱动程序可以拒绝对其设备的所有访问。

如果一个设备堆栈具有两个已命名设备对象,那么进程可以使用其中任何一个来打开设备堆栈。在这种情况下,针对其中任何一个设备对象的 IRP 都被发送到同一个堆栈,所以两个设备对象的 ACL 必须同意这些 IRP。

作为一般规则,PDO 应该是堆栈中唯一的已命名设备对象。如无必要,驱动程序不应该命名 FDO,但是有一些例外。例如,含有卷参数块 (Volume Parameter Block, VPB) 的存储设备的 FDO 必须具有一个名称。

独占设备

同一时间只能为其打开一个句柄的设备。WDM 驱动程序在 INF 文件的 AddReg 指令中将设备指定为独占。使用 AddReg
指令,系统将设置设备对象的 Flags 字段中的 DO_EXCLUSIVE 位。如果设置了 DO_EXCLUSIVE,那么 I/O
管理器通过检查设备命名空间的打开请求来以独占的方式执行。如果未设置 DO_EXCLUSIVE,则 I/O
管理器不会检查设备命名空间的打开请求;而驱动程序必须进行检查。

然而,即使为设备对象设置了 DO_EXCLUSIVE
位,拥有设备堆栈句柄的应用程序仍然可能通过打开相对于现有句柄的 "" 来获取另外的句柄。要防止这个问题,驱动程序应该拒绝对相关文件对象的任何
IRP_MJ_CREATE 请求。驱动程序应该按如下方式检查 IRP_MJ_CREATE 请求中的 RelatedFileObject
字段值:

if ( IrpSp->FileObject->RelatedFileObject != NULL)

RelatedFileObject
字段中的非空值表示另一个句柄已经打开。如果这个值非空,驱动程序必须拒绝此请求。

安全地打开文件

下列形式的打开请求将指定设备命名空间中的文件或其它对象:

/Device/Floppy0/Readme.txt /Device/Mup/Server/Share/File.txt /Device/Serial0/ 

注意:
/Device/Serial0/ 中结尾的反斜杠表示设备 Serial0 上的顶级目录。


认情况下,驱动程序负责检查其设备命名空间内对象的安全性。如果驱动程序不支持设备命名空间,那么它应该在设备对象中设置
FILE_DEVICE_SECURE_OPEN
特性。如果设置了这个标志,那么操作系统将设备对象的安全描述符应用于设备命名空间中所有打开的请求。如果设备对象的 ACL 不允许访问,那么
I/O 管理器将拒绝该请求。

任何不支持设备命名空间且未设置 FILE_DEVICE_SECURE_OPEN 标志的驱动程序都必须拒绝对对象命名空间内对象的任何 IRP_MJ_CREATE 请求。驱动程序应该按如下方式检查 IRP_MJ_CREATE 请求中的文件名长度:

if ( IrpSp->FileObject->Filename.Length != 0 )

如果长度非零,那么驱动程序必须通过一个指示设备不支持文件打开的状态来拒绝该请求。


般来讲,支持设备命名空间的驱动程序也应该设置 FILE_DEVICE_SECURE_OPEN
特性。当设备命名空间需要与设备对象不同的安全性时,是唯一的例外;比如文件系统的卷设备对象。支持命名空间但未设置该标志的驱动程序必须对比检查目标文
件的 ACL 和请求进程的存取令牌。

驱动程序可以在其对 IoCreateDevice
IoCreateDeviceSecure
例程的调用中或者设备 INF 文件中设置 FILE_DEVICE_SECURE_OPEN 标志。I/O 管理器在设备堆栈的顶部检查这个字段。因此,筛选器驱动程序必须在附加到堆栈时其下一层驱动程序复制 Characteristics
字段。

在 INF 文件中指定设备特性和安全设置


多数驱动程序都应该在设备 INF 文件中指定设备特性和安全设置。INF 文件中的值覆盖设备类安全描述符的默认值。对于 WDM 驱动程序,在
INF 文件中指定安全设置是首选的方法。启动 WDM 设备堆栈之前,PnP 管理器将在 INF
文件中指定的安全设置应用于堆栈中驱动程序的安全描述符。

下面的例子是 INF 文件的一部分,展示了如何设置设备特性和安全性:

[MyDevice.NTx86] CopyFiles = ...

[MyDevice.NTx86.Services] AddService = ...

[MyDevice.NTx86.HW] AddReg = MyDevice.Security

[MyDevice.Security] HKR,,DeviceCharacteristics,0x10001,0x100 HKR,,Security,,”D:P(A;;GA;;;SY)”

在上面的例子中,MyDevice.NTx86.HW
节中的 AddReg 指令指定命名为 MyDevice.Security
Security
节。在 MyDevice.Security
节中,DeviceCharacteristics
条目指定标志 0x10001 并设置 0x100,前者表示下一个值是一个 DWORD 值,而后者指定 FILE_DEVICE_SECURE_OPEN 特性。使用 SDDL 格式化的 Security
条目只允许系统访问。这样的安全字符串适用于创建原始 PDO 的总线驱动程序。

安全地定义和处理 IOCTL

驱动程序必须正确定义 IOCTL 控制码,并且必须正确处理和验证 IOCTL 中接收到的 I/O 请求。

IOCTL 控制码具有以下格式:

I/O 控制码的第 15 和 14 位包含一个掩码来描述请求的访问。访问掩码可以指定下列权限:

FILE_ANY_ACCESS:允许访问任何拥有请求中所指定文件对象的句柄的调用方。(在 Microsoft Windows Server 2003 上,调用方必须至少具备一项经过验证的权限。)

FILE_READ_DATA:允许调用方从文件对象请求数据。

FILE_WRITE_DATA:允许调用方向文件对象写数据。

FILE_READ_DATA OR’ed with FILE_WRITE_DATA:允许调用方向对象读和写数据。

当调用方发送一个 IOCTL 时,I/O 管理器对比检查在控制码中指定的必需访问和授予调用方的权限(存储在对象句柄中)。如果调用方具备足够的权限,那么 I/O 管理器将 IRP 转发给设备堆栈。如果调用方权限不足,那么 I/O 管理器拒绝 IRP。

定义安全的 IOCTL


用户模式调用方定义 IOCTL 时,驱动程序应该始终在 CTL_CODE 宏中指定一个必需的访问值。在过去,许多驱动程序将
FILE_ANY_ACCESS
指定为必需的访问值。但是,这个值事实上允许对设备进行不受限制的访问。除非您确信允许对设备进行无限制访问不会导致系统遭受恶意用户攻击,否则请不要在
RequiredAccess
字段中指定 FILE_ANY_ACCESS。而应该适当地指定 FILE_READ_DATA 或 FILE_WRITE_DATA 或这两个值的组合。

安全地处理 IOCTL

I/O 管理器检查所有包含 IOCTL 的 IRP 的访问权限。授予调用方的权限存储在对象句柄中(对驱动程序不透明)。如果调用方权限不足,I/O 管理器就不会将 IOCTL 发送到设备堆栈。

一些系统定义的 IOCTL 和许多驱动程序定义的 IOCTL 都将 FILE_ANY_ACCESS 定义为必需的访问值。要在用户模式调用方发送这种 IOCTL 时加强安全性,驱动程序可以使用 IoValidateDeviceIoControlAccess
函数。这个函数允许驱动程序检查访问权限。

注意:
IoValidateDeviceIoControlAccess
记录在 Windows Server 2003 DDK 中并且可以在 Windows Server 2003 和以后的操作系统上使用。必须同时适用于 Windows 2000 和 Windows XP 的驱动程序必须链接 wdmsec.lib
才能使用这个例程。

接收到 IOCTL 之后,驱动程序可以调用 IoValidateDeviceIoControlAccess
,指定 FILE_READ_ACCESS、FILE_WRITE_ACCESS 或同时指定两者。作为响应,I/O 管理器检查授予调用方的访问权限。如果调用方没有指定的权限,那么驱动程序可以通过合适的状态拒绝此 IRP。


动程序还可以检查系统级特权。例如,Swenum.sys 驱动程序在将 IRP
沿设备堆栈向下转发之前测试“加载/卸载驱动程序”特权。沿设备堆栈向下传递 IRP 时,驱动程序应该检查特权。当 IRP
沿设备堆栈向上返回时不必检查特权,因为 I/O 已经完成。

行动指南和资源

在调用 IoCreateDeviceSecure
例程中设置坚固的缺省 ACL。

在 INF 文件中为每个设备指定 ACL。如有必要,这些 ACL 可以放宽默认的 ACL 条件。

设置 FILE_DEVICE_SECURE_OPEN 特性将设备对象安全设置应用于设备命名空间。

不要定义允许 FILE_ANY_ACCESS 的 IOCTL,除非这种访问不会被恶意利用。

使用 IoValidateDeviceIoControlAccess
例程来加强那些允许 FILE_ANY_ACCESS 的现有 IOCTL 的安全性。

更多信息请参见:

Writing Secure Code(第二版)。
LeBlanc、David 和 Michael Howard。华盛顿州雷蒙德市:Microsoft Press,2001 年。

Inside Microsoft Windows 2000(第三版)。
Solomon, David A. 和 Mark Russinovich。华盛顿州雷蒙德市:Microsoft Press,2000 年。

Windows Driver Development Kit:
http://www.microsoft.com/whdc/devtools/ddk/default.mspx

在 Windows Server 2003 或 Windows XP SP1 的 Windows DDK 中,查看相关的主题:

“设备安装”中的“创建安全的设备安装”。

“内核模式驱动程序体系结构”中的“控制设备命名空间访问”和“指定设备对象的独占访问”。

IoValidateDeviceIoControlAccess
函数和 IoCreateDeviceSecure
例程的参考文档。

在 Windows Server 2003 的 Windows DDK 中,查看“I/O 控制码的安全问题”。

Windows 平台开发白皮书和资源:
http://www.microsoft.com/whdc/default.mspx

抱歉!评论已关闭.