到目前为止,我认为内核具有以只读段写入的权限。但是这段代码带来了很多问题
int main() {
char *x = "Hello World";
int status = pipe((int*)x);
perror("Error");
}
代码的输出是
Error : Bad Address
我的论点是什么,“由于pipe
函数在内核模式下执行,ro
段必须可由内核写入”。这似乎不是这种情况。现在我的问题是
- 内核如何保护只读的内存段?
- 或者我对内核的功能有误?
醇>
答案 0 :(得分:1)
与用户空间非常相似,内核的地址空间取决于特定的虚拟地址(也称为逻辑地址)是否被映射为可读,可写和可执行。与用户空间不同,内核可以自由地将一组虚拟地址映射到页面并更改页面权限属性。然而,仅仅因为内核能够将页面映射为可写,并不意味着存储在char * x中的地址在内核的地址空间中被分页为可写,甚至是在页面空间中被分页。管道呼叫。
内核保护内存区域的方式是使用称为内存管理单元(MMU)的硬件。 MMU执行虚拟地址到物理地址的映射,并在这些区域中强制执行权限。内核或多或少可以自由配置MMU。与内核空间不同,用户空间代码应该无法访问MMU。由于用户空间无法访问MMU,因此无法更改页面表的映射或页面的权限属性。这实际上意味着用户空间必须使用地址空间映射和内核设置的权限。
答案 1 :(得分:1)
我不明白内核可以写到ro页面的位置"断言来自。如果内核想要它可以重新映射内存,但它当然看起来合适,但为什么会这样做呢?
我认为你在x86上运行。在这个拱门上,内核将地址空间分成两部分(用户/内核)。切换到内核时,仍会映射用户空间因此,特别是当内核想要尝试写入提供的地址时,它会触及用户空间进程所使用的相同映射。由于映射不允许写访问,因此操作失败。
为了论证,让我们说这不适用。也就是说,无论只读的映射是在用户空间中,内核都会写入它,这将是有效的。好吧,那将是一个即时的安全问题 - 考虑一个你只能读/ exec的文件,比如glibc。它映射为只读/执行。现在你将内核写入区域,有效地为每个人更改文件。那么为什么不特别读(evilfd,address_of_libc,sizeo_of_libc);和bam,你只是设法用你选择的数据覆盖整个lib。