简体   繁体   English

C和内存中的资源保护

[英]C and resource protection in memory

When we compile a C program, it just generates some machine-understandable code. 当我们编译一个C程序时,它只生成一些机器可理解的代码。 This code can directly run on the hardware, telling from this question . 这个代码可以直接在硬件上运行,从这个问题来讲

So my questions are: 所以我的问题是:

  1. If a C program can directly run on the hardware, how can the kernel handle the resource allocation for this program? 如果C程序可以直接在硬件上运行,那么内核如何处理该程序的资源分配?

  2. If the executable generated from the compiler is in pure machine-understandable form, then how do the privileged and non-privileged modes work? 如果从编译器生成的可执行文件是纯机器可理解的形式,那么特权和非特权模式如何工作?

  3. How does the kernel manage the permission of hardware resources if a program can directly run on the hardware not through the kernel? 如果程序可以直接在硬件上运行而不是通过内核,内核如何管理硬件资源的权限?

Whilst the program is in machine code, to do anything not within its own memory region, it will need to call the kernel via syscalls . 虽然程序是在机器代码中,为了做不在自己的内存区域内的任何事情,它需要通过系统调用调用内核。

The CPU actually has a notion of the privilege of code. CPU实际上有一个代码特权的概念。 Unprivileged code can't directly access physical memory etc; 非特权代码不能直接访问物理内存等; it has to go through the OS and ask it to give access. 必须通过操作系统并要求它提供访问权限。

Hence, every program does directly run on the CPU, but that doesn't mean it can do anything with the hardware – there's hardware measurements against that. 因此,每个程序都直接在CPU上运行,但这并不意味着它可以对硬件做任何事情 - 对此进行硬件测量。 The privilege that you'd need to do certain things is one of these. 您需要做某些事情的特权就是其中之一。

If a C program can directly run on the hardware how can kernel handle the resource allocation to this program. 如果C程序可以直接在硬件上运行,那么内核如何处理该程序的资源分配。

The kernel is responsible for managing the resources of the computer as a whole, including resources like the hardware. 内核负责管理整个计算机的资源,包括硬件等资源。 This means that, for user-level applications to be able to access things like hardware devices, write to a terminal, or read a file, they have to ask the kernel for permission. 这意味着,要使用户级应用程序能够访问硬件设备,写入终端或读取文件等内容,他们必须向内核请求许可。 This is done by using the system calls exposed by the OS, as mentioned by @Marcus. 这是通过使用OS公开的系统调用来完成的,如@Marcus所述。

However, I wouldn't say that the program runs directly on hardware in the sense that it does not interact with the hardware directly, as a kernel module/driver would. 但是,我不会说程序直接在硬件上运行,因为它不会直接与硬件交互,就像内核模块/驱动程序那样。 A client program will set up the arguments for a system call and then interrupt the kernel and wait until the kernel services the interrupt request the program made. 客户端程序将设置系统调用的参数,然后中断内核并等待内核服务程序发出的中断请求。

This is why OSes today are said to run in protected mode , as opposed to the old days when they ran in real mode and a program could, for example, mess around with hardware resources directly --and potentially screw things up. 这就是为什么今天的操作系统被称为以受保护模式运行的原因,而不是过去他们以实模式运行的程序,例如,程序可能会直接乱用硬件资源 - 并且可能会搞砸。

This distinction becomes very clear if you try writing a trivial "hello world" program in x86 assembly. 如果你尝试在x86程序集中编写一个简单的“hello world”程序,这种区别就会变得非常明显。 I wrote and documented this one several years ago, reproduced below: 我几年前写过并记录了这个 ,转载如下:

;
; 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)

Notice how the program sets up the write system call, sys_write , and then specifies the file descriptor of where to write, being stdout , the string to write, and so on. 注意程序如何设置write系统调用sys_write ,然后指定写入位置的文件描述符, stdout ,要写入的字符串等等。

In other words, the program itself does not perform the write operation; 换句话说, 程序本身不执行写操作; it sets things up and asks the kernel to do it on its behalf by using a special interrupt, int 80h . 它设置了内容,并要求内核代表它使用特殊的中断, int 80h

A possible analogy here might be when you go to a restaurant. 这里可能有类比,当你去餐厅时。 The server will take your order, but the chef is the one that will do the cooking. 服务器将接受您的订单,但厨师将进行烹饪。 In this analogy, you are the user-level application, the server taking your food order is the system call, and the chef in the kitchen is the OS kernel. 在这个类比中,您是用户级应用程序,服务器命令的服务器是系统调用,厨房厨师是操作系统内核。

If the executable generated from the gcc is in pure machine understandable form then how do the privileged and non-privileged mode work? 如果从gcc生成的可执行文件是纯机器可理解的形式,那么特权和非特权模式如何工作?

Keying off from the previous section, user level programs always run in user mode. 从上一节开始,用户级程序始终以用户模式运行。 When the program needs access to something (eg terminal, read a file, etc.), it sets things up, as with the sys_write example above, and asks the kernel to do it on its behalf with an interrupt. 当程序需要访问某些东西(例如终端,读取文件等)时,它会像上面的sys_write示例那样进行设置,并要求内核代表它执行中断操作。 The interrupt causes the program to go into kernel mode and remains there until the kernel has completed servicing the client's request --which may include denying it altogether (eg trying to read a file the user has no privilege to read). 中断导致程序进入内核模式并保持在那里,直到内核完成服务客户端的请求 - 这可能包括完全拒绝它(例如,尝试读取用户没有权限读取的文件)。

Internally, it's the system call that's responsible for issuing the int 80h instruction. 在内部,系统调用负责发出int 80h指令。 User-level applications just see the system call, which is the common interface between the client and the OS. 用户级应用程序只能看到系统调用,这是客户端和操作系统之间的通用接口。

How does the kernel manage the permission of hardware resources when a program can directly run on hardware not through the kernel? 当程序可以直接在硬件上运行而不是通过内核时,内核如何管理硬件资源的权限?

If you followed the previous explanations, you can now see that the kernel acts as a gatekeeper and that programs "knock" on this gate by using the int 80h instruction. 如果您按照前面的说明进行操作,您现在可以看到内核充当网守 ,并且程序通过使用int 80h指令来“敲击”此门。

how can kernel handle the resource allocation to this program 内核如何处理该程序的资源分配

The kernel provides functions and mechanisms to allocate memory, do I/O (write to the screen, interact with the network/sound card), etc., called system calls to user programs. 内核提供了分配内存,执行I / O(写入屏幕,与网络/声卡交互)等功能和机制,称为系统调用用户程序。 These system calls are the interface between kernel and user programs, alas between the hardware and user programs. 这些系统调用是内核和用户程序之间的接口,在硬件和用户程序之间。

how do the privileged and non-privileged mode work? 特权模式和非特权模式如何工作?

User programs are in Unprivileged Mode (userspace) while the kernel runs in Privileged Mode (kernelspace). 用户程序处于非特权模式(用户空间),而内核以特权模式(内核空间)运行。 The user can't be trusted, so if he messes up (accesses higher-privileged memory or dereferences a null pointer, for example) he's prevented from it (by a segmentation fault and the following termination of the program, for example). 用户不可信任,因此如果他搞砸了(例如,访问更高权限的内存或取消引用空指针),他就会被阻止(例如,通过分段错误和以下程序终止)。

The kernel on the other hand runs in Privileged Mode. 另一方面,内核以特权模式运行。 It can do whatever it wants: write to userspace programs, steal data (like passwords) from user programs, write to the processor's firmware - everything. 它可以做任何想做的事情:写入用户空间程序,从用户程序窃取数据(如密码),写入处理器的固件 - 一切。 Furthermore, there are different kinds of kernels: monolithic kernels and microkernels are the heaviliest (does that word exist at all?) used ones. 此外,有不同种类的内核:单片内核和微内核是最重的(这个词是否存在?)使用的内核。

Linux (initiated by Linus Torvalds) is an example for a monolithic kernel. Linux(由Linus Torvalds发起)是单片内核的一个例子。 Here, the kernel is one big system, where every piece of kernel code has ultimate access to the system. 在这里,内核是一个大系统,每个内核代码都可以最终访问系统。

Minix (initiated by Andrew S. Tanenbaum) is an example for a microkernel. Minix(由Andrew S. Tanenbaum发起)是微内核的一个例子。 The part, which can access everything is rather small. 可以访问所有内容的部分相当小。 It contains only the functionality that has to be privileged (managing the MMU, accessing hardware), etc. Other functionality, like filesystems, run in the Unprivileged Mode, where they are protected from possible bugs by the usual protection mechanisms employed in userspace (Unprivileged Mode), like Segmentation Faults. 它只包含必须具有特权的功能(管理MMU,访问硬件)等。其他功能,如文件系统,在非特权模式下运行,通过用户空间中常用的保护机制保护它们免受可能的错误(Unprivileged)模式),像分段错误。

An interesting read concerning the benefits/drawbacks of monolithic kernels and microkernels is the debate between Linus Torvalds (at that time some guy who created an OS) and Andrew S. Tanenbaum (at that time an established professor for CS; has written some amazing books, BTW). 有关单片内核和微内核的优点/缺点的有趣读物是Linus Torvalds(当时创建操作系统的人)与Andrew S. Tanenbaum(当时是CS的老师)之间的争论 ;写了一些很棒的书,BTW)。

a program can directly run on hardware not through the kernel 程序可以直接在硬件上运行而不是通过内核运行

It indeed runs directly on the hardware, executed by the CPU. 它确实直接在硬件上运行,由CPU执行。 It cannot access certain resources directly , though, like memory, and, in order to access these resources, is required to interact with the kernel. 但是,它不能像内存那样直接访问某些资源 ,并且为了访问这些资源, 需要与内核进行交互。 That's one of the major improvements (next to maybe virtual processors, that is, processes) over earlier OSes like DOS: userspace programs cannot run directly on the hardware. 与DOS之类的早期操作系统相比,这是主要改进之一(可能是虚拟处理器,也就是流程):用户空间程序不能直接在硬件上运行。 If they could, they possibly could mess up the whole machine with irreparable causes (intentionally - like viruses, or unintentionally). 如果他们可以的话,他们可能会因为无法修复的原因(故意 - 像病毒,或无意中)而弄乱整台机器。 Instead, as mentioned in the beginning of this answer, system calls are used. 相反,如本答案开头所述,使用系统调用。

In DOS you had the option to use routines provided by the OS (commonly a trap at IV (Interrupt Vector, the offset (and physical memory address) into the Real Mode IDT (Interrupt Descriptor Table)) 0x21 (invoked via int 0x21 / int 21h ), while ax contained a function number identifying the call to the system 1 ). 在DOS中,您可以选择使用OS提供的例程(通常是IV中的陷阱(中断向量,偏移(和物理内存地址)到实模式IDT(中断描述符表))0x21(通过int 0x21 / int 21h调用) int 21h ),而ax包含一个识别系统调用的功能号1 )。 Roughly the same mechanisms as nowadays where available but not strictly enforced. 大致相同的机制,如今可用严格执行。 One could overwrite the whole OS, replace it with one's own program and destroy the machine (load random values into CMOS registers, for example). 可以覆盖整个操作系统,用自己的程序替换它并销毁机器(例如,将随机值加载到CMOS寄存器中)。 One could also just use the BIOS-provided routines, bypassing the OS. 也可以绕过操作系统,使用BIOS提供的例程。


1 I use "call to the system" instead of "system call" intentionally here. 1我在这里故意使用“呼叫系统”而不是“系统呼叫”。 Here, system calls only denote the requests from userspace to kernelspace to do something for it. 这里,系统调用仅表示从用户空间到内核空间的请求,以便为它做一些事情。 As DOS (ie, Real Mode) didn't provide a real distinction between userspace and kernelspace, it doesn't really have system calls. 由于DOS(即实模式)没有提供用户空间和内核空间之间的真正区别,因此它实际上没有系统调用。

So my first question is if a C program can directly run on the hardware how can kernel handle the resource allocation to this program. 所以我的第一个问题是,如果C程序可以直接在硬件上运行,内核如何处理该程序的资源分配。

CPUs carry a notion of privileges when executing code. CPU在执行代码时带有特权概念。 For example, on x86 there is a Real Mode where code is allowed to access any resource, and a Protected Mode where code executes in distinct security rings . 例如,在x86上有一个允许代码访问任何资源的实模式 ,以及一个代码在不同安全环中执行的保护模式 Most Operating Systems will switch to Protected Mode, where numerically lower rings imply higher privileges. 大多数操作系统将切换到保护模式,其中数字较低的环意味着更高的权限。

The kernel typically executes in Ring 0, which gives direct access to the hardware, while user programs run in Ring 3 which restricts access. 内核通常在Ring 0中执行,它可以直接访问硬件,而用户程序在Ring 3中运行,这限制了访问。 When the user program needs to access a privileged resource, the CPU calls into the Operating System, which is privileged, either implicitly or directly through a system call instruction (eg syscall in x86-64 assembly). 当用户程序需要访问特权资源时,CPU通过系统调用指令(例如x86-64汇编中的syscall )隐式或直接调用具有特权的操作系统。

If the executable generated from the gcc is in pure machine understandable form then how do the privileged and non-privileged mode work? 如果从gcc生成的可执行文件是纯机器可理解的形式,那么特权和非特权模式如何工作?

Again, things like memory access are checked by the CPU. 同样,CPU会检查内存访问等内容。 So for example if a program tries to access a virtual address that it doesn't have permission for, the Operating System catches the invalid page access and generally signals the process (ie SIGSEGV ). 因此,例如,如果程序试图访问它没有权限的虚拟地址 ,则操作系统捕获无效页面访问并且通常表示该过程(即SIGSEGV )。

How does the kernel manage the permission of hardware resources when a program can directly run on hardware not through the kernel? 当程序可以直接在硬件上运行而不是通过内核时,内核如何管理硬件资源的权限?

The CPU has to interact directly with the Operating System through specific control registers and tables. CPU必须通过特定的控制寄存器和表直接与操作系统交互。 For example, the address of the virtual address page table is stored in the CR3 register for x86. 例如,虚拟地址页表的地址存储在x86的CR3寄存器中。

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

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