当我们在 C 中取消引用 NULL 指针时,操作系统会发生什么? [英] What happens in OS when we dereference a NULL pointer in C?

查看:17
本文介绍了当我们在 C 中取消引用 NULL 指针时,操作系统会发生什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有一个指针,我们用 NULL 初始化它.

Let's say there is a pointer and we initialize it with NULL.

int* ptr = NULL;
*ptr = 10;

现在,程序将崩溃,因为 ptr 没有指向任何地址,我们正在为那个分配一个值,这是一个无效的访问.那么,问题是,操作系统内部发生了什么?是否发生页面错误/分段错误?内核甚至会在页表中搜索吗?还是在此之前发生崩溃?

Now , the program will crash since ptr isn't pointing to any address and we're assigning a value to that , which is an invalid access. So , the question is , what happens internally in the OS ? Does a page-fault / segmentation-fault occur ? Will the kernel even search in the page table ? Or the crash occur before that?

我知道我不会在任何程序中做这样的事情,但这只是想知道在这种情况下操作系统或编译器内部会发生什么.这不是一个重复的问题.

I know I wouldn't do such a thing in any program but this is just to know what happens internally in the OS or Compiler in such a case. And it is NOT a duplicate question.

推荐答案

简答:这取决于很多因素,包括编译器、处理器架构、特定处理器型号和操作系统,等等.

Short answer: it depends on a lot of factors, including the compiler, processor architecture, specific processor model, and the OS, among others.

长答案(x86 和 x86-64):让我们深入到最底层:CPU.在 x86 和 x86-64 上,该代码通常会编译成这样的指令或指令序列:

Long answer (x86 and x86-64): Let's go down to the lowest level: the CPU. On x86 and x86-64, that code will typically compile into an instruction or instruction sequence like this:

movl $10, 0x00000000

它说将常量整数 10 存储在虚拟内存地址 0".英特尔® 64 和 IA-32架构软件开发人员手册详细描述了执行该指令时会发生什么,因此我将为您总结一下.

Which says to "store the constant integer 10 at virtual memory address 0". The Intel® 64 and IA-32 Architectures Software Developer Manuals describe in detail what happens when this instruction gets executed, so I'm going to summarize it for you.

CPU 可以在几种不同的模式下运行,其中一些是为了向后兼容更旧的 CPU.现代操作系统以一种称为保护模式的模式运行用户级代码,该模式使用分页将虚拟地址转换为物理地址.

The CPU can operate in several different modes, several of which are for backwards compatibility with much older CPUs. Modern operating systems run user-level code in a mode called protected mode, which uses paging to convert virtual addresses into physical addresses.

对于每个进程,操作系统都有一个页表,它规定了地址的映射方式.页表以 CPU 理解的特定格式存储在内存中(并受到保护,以便用户代码无法修改它们).对于发生的每一次内存访问,CPU 都会根据页表对其进行转换.如果翻译成功,则对物理内存位置执行相应的读/写操作.

For each process, the OS keeps a page table which dictates how the addresses are mapped. The page table is stored in memory in a specific format (and protected so that they can not be modified by the user code) that the CPU understands. For every memory access that happens, the CPU translates it according to the page table. If the translation succeeds, it performs the corresponding read/write to the physical memory location.

地址转换失败时会发生有趣的事情.并非所有地址都是有效的,如果任何内存访问产生无效地址,处理器将引发页面错误异常.这会触发从 用户模式(又名 x86/x86-64 上的当前权限级别 (CPL) 3)到 内核模式(又名 CPL)的转换0) 到内核代码中的特定位置,由中断描述符表 (IDT) 定义.

The interesting things happen when the address translation fails. Not all addresses are valid, and if any memory access generates an invalid address, the processor raises a page fault exception. This triggers a transition from user mode (aka current privilege level (CPL) 3 on x86/x86-64) into kernel mode (aka CPL 0) to a specific location in the kernel's code, as defined by the interrupt descriptor table (IDT).

内核重新获得控制权,并根据来自异常的信息和进程的页表,找出发生了什么.在这种情况下,它意识到用户级进程访问了一个无效的内存位置,然后它会做出相应的反应.在 Windows 上,它将调用 结构化异常处理以允许用户代码处理异常.在 POSIX 系统上,操作系统将向进程传递 SIGSEGV 信号.

The kernel regains control and, based on the information from the exception and the process's page table, figures out what happened. In this case, it realizes that the user-level process accessed an invalid memory location, and then it reacts accordingly. On Windows, it will invoke structured exception handling to allow the user code to handle the exception. On POSIX systems, the OS will deliver a SIGSEGV signal to the process.

在其他情况下,操作系统将在内部处理页面错误并从当前位置重新启动进程,就好像什么都没发生一样.例如,保护页面 被放置在堆栈的底部,以允许堆栈按需增长到一个限制,而不是为堆栈预先分配大量内存.类似的机制用于实现 copy-on-write 内存.

In other cases, the OS will handle the page fault internally and restart the process from its current location as if nothing happened. For example, guard pages are placed at the bottom of the stack to allow the stack to grow on demand up to a limit, instead of preallocating a large amount of memory for the stack. Similar mechanisms are used for achieving copy-on-write memory.

在现代操作系统中,通常设置页表以使地址 0 成为无效的虚拟地址.但有时可以改变这一点,例如在 Linux 上通过将 0 写入伪文件 /proc/sys/vm/mmap_min_addr,之后可以使用 mmap(2) 映射虚拟地址 0.在这种情况下,取消引用空指针不会导致页面错误.

In modern OSes, the page tables are usually set up to make the address 0 an invalid virtual address. But sometimes it's possible to change that, e.g. on Linux by writing 0 to the pseudofile /proc/sys/vm/mmap_min_addr, after which it's possible to use mmap(2) to map the virtual address 0. In that case, dereferencing a null pointer would not cause a page fault.

上面的讨论都是关于当原始代码在用户空间运行时会发生什么.但这也可能发生在内核内部.内核可以(并且肯定比用户代码更有可能)映射虚拟地址 0,因此这样的内存访问是正常的.但是如果它没有被映射,那么接下来发生的事情大致相似:CPU 引发一个页面错误错误,该错误会陷入内核的预定义点,内核检查发生了什么,并做出相应的反应.如果内核无法从异常中恢复,它通常会通过打印输出以某种方式出现恐慌(kernel panickernel oops 或 Windows 上的 BSOD)一些调试信息到控制台或串行端口,然后停止.

The above discussion is all about what happens when the original code is running in user space. But this could also happen inside the kernel. The kernel can (and is certainly much more likely than user code to) map the virtual address 0, so such a memory access would be normal. But if it's not mapped, then what happens then is largely similar: the CPU raises a page fault error which traps into a predefined point at the kernel, the kernel examines what happened, and reacts accordingly. If the kernel can't recover from the exception, it will typically panic in some fashion (kernel panic, kernel oops, or a BSOD on Windows, e.g.) by printing out some debug information to the console or serial port and then halting.

另请参阅 很多关于 NULL 的废话:利用内核 NULL 取消引用 举例说明攻击者如何利用内核内部的空指针取消引用错误来获得 Linux 机器上的 root 权限.

See also Much ado about NULL: Exploiting a kernel NULL dereference for an example of how an attacker could exploit a null pointer dereference bug from inside the kernel in order to gain root privileges on a Linux machine.

这篇关于当我们在 C 中取消引用 NULL 指针时,操作系统会发生什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆