繁体   English   中英

C和内存中的资源保护

[英]C and resource protection in memory

当我们编译一个C程序时,它只生成一些机器可理解的代码。 这个代码可以直接在硬件上运行,从这个问题来讲

所以我的问题是:

  1. 如果C程序可以直接在硬件上运行,那么内核如何处理该程序的资源分配?

  2. 如果从编译器生成的可执行文件是纯机器可理解的形式,那么特权和非特权模式如何工作?

  3. 如果程序可以直接在硬件上运行而不是通过内核,内核如何管理硬件资源的权限?

虽然程序是在机器代码中,为了做不在自己的内存区域内的任何事情,它需要通过系统调用调用内核。

CPU实际上有一个代码特权的概念。 非特权代码不能直接访问物理内存等; 必须通过操作系统并要求它提供访问权限。

因此,每个程序都直接在CPU上运行,但这并不意味着它可以对硬件做任何事情 - 对此进行硬件测量。 您需要做某些事情的特权就是其中之一。

如果C程序可以直接在硬件上运行,那么内核如何处理该程序的资源分配。

内核负责管理整个计算机的资源,包括硬件等资源。 这意味着,要使用户级应用程序能够访问硬件设备,写入终端或读取文件等内容,他们必须向内核请求许可。 这是通过使用OS公开的系统调用来完成的,如@Marcus所述。

但是,我不会说程序直接在硬件上运行,因为它不会直接与硬件交互,就像内核模块/驱动程序那样。 客户端程序将设置系统调用的参数,然后中断内核并等待内核服务程序发出的中断请求。

这就是为什么今天的操作系统被称为以受保护模式运行的原因,而不是过去他们以实模式运行的程序,例如,程序可能会直接乱用硬件资源 - 并且可能会搞砸。

如果你尝试在x86程序集中编写一个简单的“hello world”程序,这种区别就会变得非常明显。 我几年前写过并记录了这个 ,转载如下:

;
; This program runs in 32-bit protected mode.
;  build: nasm -f elf -F stabs name.asm
;  link:  ld -o name name.o
;
; In 64-bit long mode you can use 64-bit registers (e.g. rax instead of eax, rbx instead of ebx, etc.)
; Also change "-f elf " for "-f elf64" in build command.
;
section .data                           ; section for initialized data
str:     db 'Hello world!', 0Ah         ; message string with new-line char at the end (10 decimal)
str_len: equ $ - str                    ; calcs length of string (bytes) by subtracting the str's start address
                                            ; from this address ($ symbol)

section .text                           ; this is the code section
global _start                           ; _start is the entry point and needs global scope to be 'seen' by the
                                            ; linker --equivalent to main() in C/C++
_start:                                 ; definition of _start procedure begins here
    mov eax, 4                   ; specify the sys_write function code (from OS vector table)
    mov ebx, 1                   ; specify file descriptor stdout --in gnu/linux, everything's treated as a file,
                                             ; even hardware devices
    mov ecx, str                 ; move start _address_ of string message to ecx register
    mov edx, str_len             ; move length of message (in bytes)
    int 80h                      ; interrupt kernel to perform the system call we just set up -
                                             ; in gnu/linux services are requested through the kernel
    mov eax, 1                   ; specify sys_exit function code (from OS vector table)
    mov ebx, 0                   ; specify return code for OS (zero tells OS everything went fine)
    int 80h                      ; interrupt kernel to perform system call (to exit)

注意程序如何设置write系统调用sys_write ,然后指定写入位置的文件描述符, stdout ,要写入的字符串等等。

换句话说, 程序本身不执行写操作; 它设置了内容,并要求内核代表它使用特殊的中断, int 80h

这里可能有类比,当你去餐厅时。 服务器将接受您的订单,但厨师将进行烹饪。 在这个类比中,您是用户级应用程序,服务器命令的服务器是系统调用,厨房厨师是操作系统内核。

如果从gcc生成的可执行文件是纯机器可理解的形式,那么特权和非特权模式如何工作?

从上一节开始,用户级程序始终以用户模式运行。 当程序需要访问某些东西(例如终端,读取文件等)时,它会像上面的sys_write示例那样进行设置,并要求内核代表它执行中断操作。 中断导致程序进入内核模式并保持在那里,直到内核完成服务客户端的请求 - 这可能包括完全拒绝它(例如,尝试读取用户没有权限读取的文件)。

在内部,系统调用负责发出int 80h指令。 用户级应用程序只能看到系统调用,这是客户端和操作系统之间的通用接口。

当程序可以直接在硬件上运行而不是通过内核时,内核如何管理硬件资源的权限?

如果您按照前面的说明进行操作,您现在可以看到内核充当网守 ,并且程序通过使用int 80h指令来“敲击”此门。

内核如何处理该程序的资源分配

内核提供了分配内存,执行I / O(写入屏幕,与网络/声卡交互)等功能和机制,称为系统调用用户程序。 这些系统调用是内核和用户程序之间的接口,在硬件和用户程序之间。

特权模式和非特权模式如何工作?

用户程序处于非特权模式(用户空间),而内核以特权模式(内核空间)运行。 用户不可信任,因此如果他搞砸了(例如,访问更高权限的内存或取消引用空指针),他就会被阻止(例如,通过分段错误和以下程序终止)。

另一方面,内核以特权模式运行。 它可以做任何想做的事情:写入用户空间程序,从用户程序窃取数据(如密码),写入处理器的固件 - 一切。 此外,有不同种类的内核:单片内核和微内核是最重的(这个词是否存在?)使用的内核。

Linux(由Linus Torvalds发起)是单片内核的一个例子。 在这里,内核是一个大系统,每个内核代码都可以最终访问系统。

Minix(由Andrew S. Tanenbaum发起)是微内核的一个例子。 可以访问所有内容的部分相当小。 它只包含必须具有特权的功能(管理MMU,访问硬件)等。其他功能,如文件系统,在非特权模式下运行,通过用户空间中常用的保护机制保护它们免受可能的错误(Unprivileged)模式),像分段错误。

有关单片内核和微内核的优点/缺点的有趣读物是Linus Torvalds(当时创建操作系统的人)与Andrew S. Tanenbaum(当时是CS的老师)之间的争论 ;写了一些很棒的书,BTW)。

程序可以直接在硬件上运行而不是通过内核运行

它确实直接在硬件上运行,由CPU执行。 但是,它不能像内存那样直接访问某些资源 ,并且为了访问这些资源, 需要与内核进行交互。 与DOS之类的早期操作系统相比,这是主要改进之一(可能是虚拟处理器,也就是流程):用户空间程序不能直接在硬件上运行。 如果他们可以的话,他们可能会因为无法修复的原因(故意 - 像病毒,或无意中)而弄乱整台机器。 相反,如本答案开头所述,使用系统调用。

在DOS中,您可以选择使用OS提供的例程(通常是IV中的陷阱(中断向量,偏移(和物理内存地址)到实模式IDT(中断描述符表))0x21(通过int 0x21 / int 21h调用) int 21h ),而ax包含一个识别系统调用的功能号1 )。 大致相同的机制,如今可用严格执行。 可以覆盖整个操作系统,用自己的程序替换它并销毁机器(例如,将随机值加载到CMOS寄存器中)。 也可以绕过操作系统,使用BIOS提供的例程。


1我在这里故意使用“呼叫系统”而不是“系统呼叫”。 这里,系统调用仅表示从用户空间到内核空间的请求,以便为它做一些事情。 由于DOS(即实模式)没有提供用户空间和内核空间之间的真正区别,因此它实际上没有系统调用。

所以我的第一个问题是,如果C程序可以直接在硬件上运行,内核如何处理该程序的资源分配。

CPU在执行代码时带有特权概念。 例如,在x86上有一个允许代码访问任何资源的实模式 ,以及一个代码在不同安全环中执行的保护模式 大多数操作系统将切换到保护模式,其中数字较低的环意味着更高的权限。

内核通常在Ring 0中执行,它可以直接访问硬件,而用户程序在Ring 3中运行,这限制了访问。 当用户程序需要访问特权资源时,CPU通过系统调用指令(例如x86-64汇编中的syscall )隐式或直接调用具有特权的操作系统。

如果从gcc生成的可执行文件是纯机器可理解的形式,那么特权和非特权模式如何工作?

同样,CPU会检查内存访问等内容。 因此,例如,如果程序试图访问它没有权限的虚拟地址 ,则操作系统捕获无效页面访问并且通常表示该过程(即SIGSEGV )。

当程序可以直接在硬件上运行而不是通过内核时,内核如何管理硬件资源的权限?

CPU必须通过特定的控制寄存器和表直接与操作系统交互。 例如,虚拟地址页表的地址存储在x86的CR3寄存器中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM