I/O 用户模式进程的指令
I/O instructions by user-mode process
有两种访问硬件的方法:
- 通过内存映射I/O (MMIO)
- 通过 I/O 个端口
如果用户模式进程直接想访问 I/O 而不使用系统调用,并且它知道特定的硬件,则无法通过内存映射 I/O 访问它,因为它是不在其地址 space 中,因此会发生分段错误。但是如何使用 I/O 端口来做到这一点呢?由于 I/O 端口不在内存地址 space 中,而是被处理器直接执行的指令访问,那么会发生什么情况,进程是否可以访问它们?
短版
没有。例如,在x86架构中,in
和out
是特权指令,只能在Ring 0运行。由于user-mode在Ring 3应用运行, CPU 将在尝试执行该指令时出错。
长版
一般来说,在 OS 中强制执行内存保护和进程分离(例如 Windows、Linux、Mac OS,但不是DOS), user-mode 应用程序不能直接访问硬件,而是使用系统调用要求内核代表它们执行所需的操作。然后内核可以决定应用程序是否有权执行所述操作,该操作是否安全等。
如果 user-mode 应用程序能够执行通常只能由内核执行的任何操作,那么它就是一个 bug/backdoor 并且是内核中的一个巨大安全漏洞(或者有时 CPU本身)。
在 x86 架构上,I/O 端口指令在除实模式外的所有操作模式下都具有特权。尝试执行任何特权指令都会产生错误(具体来说,#GP
、General-Protection 错误,对应于 INT 0xD
)。
为了允许像 user-mode 驱动程序这样的进程工作,OS 可以通过两种方式覆盖 I/O 指令的特权状态:
- 使用
FLAGS
寄存器(位 12 和 13)中的 IOPL
(I/O 特权级别)字段。这是一个从 0 到 3 的数字,指定可以 运行 I/O 指令的最低特权环。将 IOPL
设置为 3 将允许所有进程访问任何 I/O 端口,这是不安全的并且违背了保护其他一切(如内存)的目的。为此,操作系统通常将此字段设置为0。
- 使用任务状态段 (TSS) 结构中的
IOPB
(I/O 权限位图)位域。这只是 65536 位的集合,每个位指定 I/O 端口是否可以访问(0
)或不可以(1
)。如果 user-mode 驱动程序需要访问端口 0xAB
,那么 OS 可以清除 TSS 中的相应位并允许 user-mode 代码仅访问该端口,尽管 IOPL=0
。如果操作系统不包含所有 65536 位,则 CPU 假定缺少的那些位具有特权,因此无法访问。
有两种访问硬件的方法:
- 通过内存映射I/O (MMIO)
- 通过 I/O 个端口
如果用户模式进程直接想访问 I/O 而不使用系统调用,并且它知道特定的硬件,则无法通过内存映射 I/O 访问它,因为它是不在其地址 space 中,因此会发生分段错误。但是如何使用 I/O 端口来做到这一点呢?由于 I/O 端口不在内存地址 space 中,而是被处理器直接执行的指令访问,那么会发生什么情况,进程是否可以访问它们?
短版
没有。例如,在x86架构中,in
和out
是特权指令,只能在Ring 0运行。由于user-mode在Ring 3应用运行, CPU 将在尝试执行该指令时出错。
长版
一般来说,在 OS 中强制执行内存保护和进程分离(例如 Windows、Linux、Mac OS,但不是DOS), user-mode 应用程序不能直接访问硬件,而是使用系统调用要求内核代表它们执行所需的操作。然后内核可以决定应用程序是否有权执行所述操作,该操作是否安全等。
如果 user-mode 应用程序能够执行通常只能由内核执行的任何操作,那么它就是一个 bug/backdoor 并且是内核中的一个巨大安全漏洞(或者有时 CPU本身)。
在 x86 架构上,I/O 端口指令在除实模式外的所有操作模式下都具有特权。尝试执行任何特权指令都会产生错误(具体来说,#GP
、General-Protection 错误,对应于 INT 0xD
)。
为了允许像 user-mode 驱动程序这样的进程工作,OS 可以通过两种方式覆盖 I/O 指令的特权状态:
- 使用
FLAGS
寄存器(位 12 和 13)中的IOPL
(I/O 特权级别)字段。这是一个从 0 到 3 的数字,指定可以 运行 I/O 指令的最低特权环。将IOPL
设置为 3 将允许所有进程访问任何 I/O 端口,这是不安全的并且违背了保护其他一切(如内存)的目的。为此,操作系统通常将此字段设置为0。 - 使用任务状态段 (TSS) 结构中的
IOPB
(I/O 权限位图)位域。这只是 65536 位的集合,每个位指定 I/O 端口是否可以访问(0
)或不可以(1
)。如果 user-mode 驱动程序需要访问端口0xAB
,那么 OS 可以清除 TSS 中的相应位并允许 user-mode 代码仅访问该端口,尽管IOPL=0
。如果操作系统不包含所有 65536 位,则 CPU 假定缺少的那些位具有特权,因此无法访问。