设备对象(DEVICE_OBJECT)-----------------设备名称

通常设备对象都把自己的名字放到\Device目录中。在Windows 2000中,设备的名称有两个用途。第一个用途,设备命名后,其它内核模式部件可以通过调用IoGetDeviceObjectPointer函数找到该设备,找到设备对象后,就可以向该设备的驱动程序发送IRP。

另一个用途,允许应用程序打开命名设备的句柄,这样它们就可以向驱动程序发送IRP。应用程序可以使用标准的CreateFile API打开命名设备句柄,然后用ReadFileWriteFile,和DeviceIoControl向驱动程序发出请求。应用程序打开设备句柄时使用\\.\路径前缀而不是标准的UNC(统一命名约定)名称,如C:\MYFILE.CPP或\\FRED\C-Drive\HISFILE.CPP。在内部,I/O管理器在执行名称搜索前自动把\\.\转换成\??\。为了把\??目录中的名字与名字在其它目录(例如,在\Device目录)中的对象相连接,对象管理器实现了一种称为符号连接(symbolic link)的对象。

符号连接

符号连接有点象桌面上的快捷方式,符号连接在Windows NT中的主要用途是把处于列表前面的DOS形式的名称连接到设备上。图2-17显示了\??目录的部分内容,这里就有一些符号名,例如,“C:”和其它一 些用DOS命名方案命名的驱动器名称,它们被连接到\Device目录中,而这些设备对象的真正名称就放在\Device目录中。符号连接可以使对象管理 器在分析一个名称时能跳到命名空间的某个地方。例如,如果我用CreateFile打开名称为“C:\MYFILE.CPP”的对象,对象管理器将以下面 过程打开该文件:

  1. 内核模式代码最开始看到的名称是\??\C:\MYFILE.CPP。对象管理器在根目录中查找“??”。
  2. 找到\??目录后,对象管理器在其中查找“C:”。它发现找到的对象是一个符号连接,所以它就用这个符号连接组成一个新的内核模式路径名:\Device\HarddiskVolume1\MYFILE.CPP,然后析取它。
  3. 使用新路径名后,对象管理器重新在根目录中查找“Device”。
  4. 找到\Device目录后,对象管理器在其中查找“HarddiskVolume1”,最后它找到一个以该名字命名的设备。

图2-17. \??目录和部分符号连接

现在,对象管理器要创建一个IRP,然后把它发到HarddiskVolume1设备的驱动程序。该IRP最终将使某个文件系统驱动程序或其它驱动 程序定位并打开一个磁盘文件。描述文件系统驱动程序的工作过程已经超出了本书的范围。如果我们使用设备名COM1,那么最终收到该IRP的将 是\Device\Serial0的驱动程序。

用户模式程序可以调用DefineDosDevice创建一个符号连接,如下例:

BOOL okay = DefineDosDevice(DDD_RAW_TARGET_PATH, "barf", "\\Device\\SECTEST_0");

图2-17中显示了上面调用的结果。

如果你需要在WDM驱动程序中创建一个符号连接,可以调用IoCreateSymbolicLink函数:

IoCreateSymbolicLink(linkname, targname);

linkname是要创建的符号连接名,targname是要连接的名字。顺便说一下,对象管理器并不关心targname是否是已存在对象的名字,如果连接到一个未定义的符号名,那么访问该符号连接将简单地收到一个错误。如果你想允许用户模式程序能超越这个连接而转到其它地方,应使用IoCreateUnprotectedSymbolicLink函数替代上面函数。

应该命名设备对象吗?

决定为设备对象命名之前,你应该多想一想。如果命名了设备对象,那么任何内核模式程序都可以打开该设备的句柄。另外,任何内核模式或用户模式程序都能创建连接到该设备的符号连接,并可以使用这个符号连接打开设备的句柄。你可能允许也可能不允许这种事情发生。

是否命名设备对象的主要考虑是安全问题。当有人打开一个命名对象的句柄时,对象管理器将检查他是否有权这样做。当IoCreateDevice为你 创建设备对象时,它也为设备对象设置了一个默认安全描述符(基于第四个参数中的设备类型)。下面是三个基本分类,I/O管理器基于这些分类来选择安全描述 符。(参考表2-4中的第二列)

  • 大部分文件系统设备对象(磁盘、CD-ROM、文件、磁带)将得到“public default unrestricted”ACL(访问控制表)。该表对系统(SYSTEM)和管理员(administrator)之外的所有账户给予了 SYNCHRONIZE、READ_CONTROL、FILE_READ_ATTRIBUTES、FILE_TRAVERSE访问权限。顺便说一下,文件 系统设备对象就是作为CreateFile函数的目标而存在,CreateFile函数将打开一个由文件系统管理的文件。
  • 磁盘设备和网络文件系统对象将得到与文件系统对象相同的ACL,但做了一些修改。例如,任何人对命名软磁盘设备对象都有全部访问权,管理员有足够 的权限运行ScanDisk。(用户模式的网络支持DLL需要更大的权限来访问其对应文件系统驱动程序的设备对象,这就是网络文件系统需要与其它文件系统 区别对待的原因)
  • 所有其它的设备对象将得到“public open unrestricted”ACL,它允许任何有设备句柄的人不受限制地使用该设备。

可以看出,如果非磁盘设备的驱动程序在调用IoCreateDevice时给出设备对象名,那么任何人都可以读写这个设备,因为默认安全设置几乎允 许用户有全部的访问权限,而且在创建符号连接时根本不进行安全检查。安全检查仅发生在对设备的打开操作上,基于命名对象的安全描述符。这对于在同一堆栈中 的有更严格安全限制的其它设备对象也是这样。

DevView可以显示设备对象的安全属性。你可以通过测试一个文件系统、一个磁盘设备、或者任何其它随机存取设备了解到我刚描述过的默认操作规则。

PDO也得到一个默认安全描述符,但这个安全描述符可能被存储在硬件键或类键的Properties子键中的安全描述符超越(当两者都存在时,硬件 键中的超越值有更高的优先权)。即使没有指定安全描述符超越,如果硬件键或类键的Properties子键中有设备类型或特征的超越值,那么I/O管理器 也会基于新类型为对象构造一个新的默认安全描述符。但I/O管理器不会超越PDO上面的任何其它设备对象的安全设置。因此,由于超越的影响,你不应该命名 你的设备对象。但不要失望,应用程序仍可以使用注册的接口(interface)访问你的设备。

关于安全问题的最后一点:当对象管理器析取对象名时,对于名字的中间部分仅需要具有FILE_TRAVERSE访问权,它仅在最终对象名上执行全部 的安全检查。所以,假设某个设备对象可以通过\Device\SECTEST_0名或符号连接\??\SecurityTest_0名到达,那么,如果设 备对象的安全描述符设置为拒绝写,则试图以写方式打开\\.\SecurityTest_0的用户模式应用程序将被阻塞。但如果应用程序试图打开名为 \\.\SecurityTest_0\ExtraStuff的对象,那么打开请求(IRP_MJ_CREATE形式)将被允许,而此时用户对\\. \SecurityTest_0\仅有FILE_TRAVERSE权限。I/O管理器希望设备驱动程序自己去处理额外名称部件的安全检查。

为了避免涉及到我刚描述过的安全问题,你可以在调用IoCreateDevice时指定设备特征参数为FILE_DEVICE_SECURE_OPEN。该标志将使Windows 2000在额外名称部件存在的情况下仍检查调用者是否有权限打开设备句柄。

设备名称

如果你决定命名设备对象,通常应该把对象名放在名称空间的\Device分支中。为了命名设备对象,首先应该创建一个UNICODE_STRING结构来存放对象名,然后把该串作为调用IoCreateDevice的参数:

UNICODE_STRING devname;
RtlInitUnicodeString(&devname, L"\\Device\\Simple0");
IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), &devname, ...);

我将在下一章中讨论RtlInitUnicodeString的用法。

通常,驱动程序用设备类型串后加上一个以0开始的实例号作为设备对象名(如上面的Simple0)。一般,你不希望象我上面做的那样使用带有硬编码性质的名称。你希望用串操作函数动态地合成一个名字:

UNICODE_STRING devname;
static LONG lastindex = -1;
LONG devindex = InterlockedIncrement(&lastindex);
WCHAR name[32];
_snwprintf(name, arraysize(name), L"\\Device\\SIMPLE%2.2d", devindex);
RtlInitUnicodeString(&devname, name);
IoCreateDevice(...);

我将在后两章中解释上面代码中出现的服务函数。如上面代码所示,从私有设备类型得出的实例号应该是一个静态变量。

posted on 2012-06-14 14:27  紫 陌  阅读(2902)  评论(0编辑  收藏  举报

导航