C and in-memory resource protection

When we compile a C program, it simply generates some machine code. This code can directly run on hardware, reporting this issue .

So my questions are:

  • If program C can run directly on hardware, how can the kernel handle resource allocation for this program?

  • If the executable file generated by the compiler is in a clean machine-friendly form, then how do privileged and unprivileged modes work?

  • How does the kernel control the resolution of hardware resources if a program can run directly on hardware not through the kernel?

+5
source share
4 answers

If program C can work directly on how the kernel can handle the allocation of resources for this program.

The kernel is responsible for managing the resources of the computer as a whole, including resources such as hardware. This means that for user-level applications to access things such as hardware devices, writing to a terminal, or reading a file, they must ask the kernel for permission. This is done using system calls opened by the operating system, as pointed out by @Marcus.

However, I would not say that the program runs directly on the hardware level in the sense that it does not interact directly with the hardware, since there will be a kernel module / driver. The client program will configure the arguments for the system call, and then interrupt the kernel and wait for the kernel to service the interrupt request made by the program.

That's why the OS today works in protected mode, unlike the old days, when they started in real mode, and the program could, for example, get confused with hardware resources directly - and potentially damage things.

This difference becomes very clear if you try to write the trivial program "hello world" in the x86 assembly. A few years ago, I wrote and documented this , 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 (eg 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 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 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 sys_write write system call and then tells the file descriptor where to write, being stdout , the line to write, etc.

In other words, the program itself does not perform a write operation; he installs things and asks the kernel to do this on his behalf, using a special interrupt, int 80h .

A possible analogy here may be when you go to a restaurant. The server will accept your order, but the chef will be the one to cook. In this analogy, you are a user application, the server accepting your food order is a system call, and the chef in the kitchen is the core of the OS.

If the executable file created from gcc is in a clean machine in an understandable form, then how to use privileged and unprivileged mode to work?

Disconnecting from the previous section, user level programs always start in user mode. When a program needs access to something (for example, a terminal, reading a file, etc.), it sets things up, as in the example with sys_write above, and asks the kernel to do this on its behalf with interruption. Interruption causes the program to enter kernel mode and remain there until the kernel completes servicing the client request, which may include refusing it at all (for example, trying to read a file that the user does not have the right to read).

Internally, this is the system call responsible for issuing the int 80h . User-level applications simply see a system call, which is the common interface between the client and the OS.

How does the kernel control the resolution of hardware resources when a program can directly work on hardware not through the kernel?

If you followed the previous explanations, now you can see that the kernel acts as a gatekeeper and that programs “tapped” these gates with the int 80h .

+5
source

While the program is in machine code to do anything not within its own memory area, it will need to call the kernel through system calls.

The processor actually has an idea of ​​code privileges. Unprivileged code cannot directly access physical memory, etc .; he has to go through the OS and ask for access.

Therefore, each program runs directly on the CPU, but this does not mean that it can do something with the hardware - it is hardware measurements against it. The privilege you need to perform certain tasks is one of them.

+5
source

how the kernel can handle the allocation of resources to this program

The kernel provides functions and mechanisms for allocating memory, input / output (recording on the screen, interacting with a network / sound card), etc., called system calls for user programs. These system calls are the interface between the kernel and user programs, alas, between hardware and user programs.

How does privileged and unprivileged mode work?

User programs are in unprivileged mode (user space), while the kernel is in privilege mode (kernelspace). The user cannot be trusted, so if he gets confused (for example, accessing high-priority memory or dereferencing with a null pointer), he prevented it (for example, with a segmentation error and subsequent program termination).

The kernel, on the other hand, runs in Privileged mode. He can do whatever he wants: write to user space programs, steal data (for example, passwords) from user programs, write everything to the processor firmware. In addition, there are different types of cores: monolithic cores and micronuclei are the heaviest (does this word even exist?) That were used.

Linux (initiated by Linus Torvalds) is an example of a monolithic kernel. Here, the kernel is one large system where every part of the kernel code has full access to the system.

Minix (initiated by Andrew S. Tanenbaum) is an example for a microkernel. The part that has access to everything is quite small. It contains only the functionality that should be privileged (MMU management, hardware access), etc. Other functions, such as file systems, run in unprivileged mode, where they are protected from possible errors using the usual protection mechanisms used in user space (Unprivileged Mode), for example, "Segmentation Defects".

An interesting read about the advantages / disadvantages of monolithic cores and microkernels is the discussion between Linus Torvalds (some guy who created the OS at that time) and Andrew S. Tanenbaum (who was a CS professor at the time, wrote some amazing books, BTW).

a program can run directly on hardware not through the kernel

It really works directly on the hardware run by the CPU. It cannot directly access certain resources , but, like memory, access to these resources requires interacting with the kernel. This is one of the major improvements (next to, possibly, virtual processors, that is, processes) over earlier operating systems such as DOS: user space programs cannot work directly on hardware. If they could, they could spoil the whole car with irreparable causes (intentionally - like viruses or unintentionally). Instead, as mentioned at the beginning of this answer, system calls are used.

In DOS, you had an option to use the routines provided by the OS (usually this is an IV trap (interrupt vector, offset (and physical memory address) in the real-mode IDT (interrupt descriptor table))) 0x21 (called via int 0x21 / int 21h ), and ax contains the function number identifying the system call 1 ). Approximately the same mechanisms as in our days, where available , but not available , are strictly observed. You can overwrite the entire OS, replace it with one of your own program and destroy the machine (for example, load random values ​​into CMOS registers). You can also simply use the routines provided by the BIOS to bypass the OS.


1 I use "call to system" here instead of "system call". Here, system calls only indicate user space queries in kernelspace to do something for this. Since DOS (i.e., Real Mode) did not provide a real distinction between user space and kernel space, it actually does not have system calls.

+3
source

So, my first question is: can program C run directly on hardware, how can the kernel handle the allocation of resources to this program.

CPUs carry the concept of privileges when executing code. For example, on x86 there is a real mode in which the code is allowed access to any resource and protected mode in which the code runs in different security rings . Most operating systems will switch to protected mode, where the numeric lower rings indicate higher privileges.

The kernel is usually executed in Ring 0, which gives direct access to equipment, while user programs run in Ring 3, which restricts access. When a user program needs to access a privileged resource, the processor will switch to the operating system, which is privileged, either implicitly, or directly through a system call command (for example, syscall in assembly x86-64).

If the executable generated from gcc is in a clean, understandable machine, then how does privileged and unprivileged mode work?

Again, things like memory access are checked by the processor. For example, if a program tries to access a virtual address at which it does not have permission, the operating system catches an invalid access to the page and generally signals the process (i.e. SIGSEGV ).

How does the kernel control the resolution of hardware resources when a program can run directly on hardware rather than through the kernel?

The processor must interact directly with the operating system through certain control registers and tables. For example, the table address of the virtual address table is stored in the CR3 for x86.

+2
source

Source: https://habr.com/ru/post/1234210/


All Articles