将安全描述符应用到设备对象上

大多数驱动程序使用 I/O 管理器对其设备对象应用的访问控制来保护自己免受不当访问。 对于大多数驱动程序,最简单的方法是在安装驱动程序时应用显式安全描述符。 在 INF 文件中,此类安全描述符由 AddReg 部分中的“安全性”条目描述。 有关用于描述安全描述符的完整语言的详细信息,请参阅Microsoft Windows SDK文档中的安全描述符定义语言。

使用安全描述符定义语言 (SDDL) 的安全描述符的基本格式包括标准安全描述符的以下不同部分:

  • 所有者 SID。

  • 组 SID。

  • 自由访问控制列表 (DACL)。

  • 系统访问控制列表 (SACL)。

因此,安全描述符的 INF 脚本中的说明为:

O:owner-sidG:group-sidD:dacl-flags(ace)(ace)S:sacl-flags(ace)(ace)

单个访问控制条目描述要向安全标识符或 SID 指定的特定组或用户授予或拒绝访问权限。 例如,INF 文件可能包含如下行:

"D:P(A;CI;GR;;;BU)(A;CI;GR;;;PU)(A;CI;GA;;;BA)(A;CI;GA;;;SY)(A;CI;GA;;;NS)(A;CI;GA;;;LS)(A;CI;CCDCLCSWRPSDRC;;;S-1-5-32-556)"

上面的示例来自 NETTCPIP。Microsoft Windows XP Service Pack 1 (SP1) 系统中的 INF 文件。

在此实例中,没有指定所有者或组,因此它们默认为预定义值或默认值。 D 指示这是 DACL。 P 指示这是受保护的 ACL,不从包含对象的安全描述符继承任何权限。 受保护的 ACL 可防止继承父级的更宽松的安全性。 括号表达式指示 ACE) (一个访问控制项。 使用 SDDL 的访问控制项由多个不同的分号分隔组件组成。 按顺序排列:

  • ACE 的类型指示器。 DACL 有四种唯一类型,SACL 有四种不同的类型。

  • 标志 字段, 用于描述子对象的此 ACE 继承或 SACL 的审核和警报策略。

  • 权限字段指示 ACE 授予或拒绝了哪些权限。 此字段可以指定指示适用于此 ACE 的通用、标准和特定权限的特定数值,或使用常见访问权限的字符串说明。

  • 如果 DACL 是特定于对象的 ACE 结构,则为对象 GUID。

  • 如果 DACL 是特定于对象的 ACE 结构,则为继承的对象 GUID

  • 一个 SID,指示此 ACE 应用到的安全实体。

因此,解释示例安全描述符时,ACE 的“A”表示这是一个“允许访问”条目。 替代项是“拒绝访问”条目,该条目很少使用,由前导“D”字符表示。 标志字段指定容器继承 (CI) ,这指示此 ACE 由子对象继承。

权限字段值对包括通用权限和标准权限的特定权限进行编码。 例如,“GR”表示“泛型读取”访问权限,“GA”表示“泛型全部”访问,这两者都是泛型权限。 一些特殊权利遵循这些一般权利。 在上面的示例中,“CC”指示创建特定于文件和目录权限的子访问权限。 上面的示例还包括“CC”字符串后的其他标准权限,包括用于删除子访问的“DC”、用于列表子访问的“LC”、用于自权限访问的“SW”、用于读取属性访问的“RP”、用于标准删除访问的“SD”和用于读取控制访问的“RC”。

上述示例中的 SID 条目字符串包括:高级用户的“PU”、内置用户的“BU”、“内置管理员”的“BA”、“本地服务帐户的 LS”、“本地系统的”SY“和网络服务帐户的”NS”。 因此,在上面的示例中,将向用户授予对 对象的一般读取访问权限。 相比之下,为内置管理员、本地服务帐户、本地系统和网络服务提供常规的所有访问权限, (读取、写入和执行) 。 Windows SDK 中记录了所有可能的权限和标准 SID 字符串的完整集。

这些 ACL 将应用于由给定驱动程序创建的所有设备对象。 在创建命名设备对象时,驱动程序还可以通过使用新函数 IoCreateDeviceSecure 来控制特定对象的安全设置。 IoCreateDeviceSecure 函数在 Windows XP Service Pack 1 和 Windows Server 2003 及更高版本上可用。 使用 IoCreateDeviceSecure,将使用适用于设备对象的完整安全描述符定义语言的子集描述要应用于设备对象的安全描述符。

将特定安全描述符应用于设备对象的目的是确保在应用程序尝试访问设备本身时对设备执行适当的安全检查。 对于包含名称结构 (文件系统命名空间的设备对象(例如) ),管理对此设备命名空间的访问权限的详细信息属于驱动程序,而不是 I/O 管理器。

在这些情况下,一个有趣的问题是,如何在负责检查对驱动程序设备对象的访问的 I/O 管理器和设备驱动程序(实现适用于驱动程序的任何安全策略)之间的边界处处理安全性。 传统上,如果打开的对象是设备本身的名称,则 I/O 管理器将直接使用其安全描述符对设备对象执行完全访问检查。 但是,如果打开的对象指示驱动程序本身内的路径,则 I/O 管理器将仅检查以确保向设备对象授予遍历访问权限。 通常,授予此遍历权限是因为大多数线程都被授予 了 SeChangeNotifyPrivilege,这对应于授予对目录的遍历权限。 不支持名称结构的设备通常会请求 I/O 管理器执行完整的安全检查。 这是通过在设备特征字段中设置 FILE_DEVICE_SECURE_OPEN 位来完成的。 包含混合此类设备对象的驱动程序应为不支持名称结构的设备设置此特征。 例如,文件系统会在其命名设备对象上设置此选项, (不支持) 命名结构,但不会在卷 (未命名的设备对象(例如) )上设置此选项,后者支持命名结构。 未能正确设置此位是驱动程序中的常见 bug,可能允许对设备进行不当访问。 对于使用 IoAttachDeviceToDeviceStackSafe (附件接口的驱动程序(例如) ),如果在驱动程序连接到的设备中设置此字段,则会设置 FILE_DEVICE_SECURE_OPEN 位。 因此,筛选器驱动程序无需担心安全检查的这一特定方面。