在linux x86 中分页。
每个进程都有自己的页面目录。
页表遍历从 CR3 指向的页目录开始。
每个进程共享内核页目录内容
假设三个句子是正确的,假设某个进程进入内核模式并更新其内核页目录内容(地址映射、访问权限等......)
问题。由于内核地址空间在进程之间全局共享,因此此更新必须与其他进程的页目录同步,对吧?
如何管理?
我试图mmap在查看man mmap时了解其工作原理。
据我了解,它向页表添加了一个映射,该映射在文件和虚拟地址(这是给定的地址void *addr)之间进行映射
那么,当两个程序映射同一个文件时会发生什么?页表中是否有 2 个条目,每个程序一个?
ARM 的 aarch64 有一条 AT(地址转换)指令,该指令通过地址转换阶段运行虚拟地址,返回 PAR_EL1 中的物理地址,以及指示转换是否存在的状态。请参阅 ARMv8 ARM,C5.5 节。
问题是:x86_64 有等效的吗?Intel的系统编程指南(第3卷第5章)谈到了指针验证,但这些方法似乎适用于段级保护,并且似乎没有任何页级保护指针验证指令。
有人知道 x86_64 的类似 ARMv8-AT 的指令吗?
据我所知,CPU的一次内存访问涉及到CPU缓存和MMU。CPU 将尝试在缓存中找到它的目标,如果发生缓存未命中,CPU 将转向 MMU。在 MMU 访问期间,对应页表项的访问/脏位将由硬件设置。
然而,据我所知,除非出现缓存未命中,否则大多数 CPU 设计都不会触发 MMU,这里我的问题是,是否仍会在缓存命中时设置页表条目的访问/脏位?还是跟架构有关?
我搜索了很多资源,但没有发现任何具体的问题:
我知道在某些 linux 系统中,fork()系统调用与 copy-on-write 一起使用;也就是说,父子进程共享相同的地址空间,但是 PTE 现在被标记为read-only,以便稍后在 COW 中使用。当任何一个尝试访问一个页面时,PAGE_FAULT都会发生一个页面,并将该页面复制到另一个可以修改的地方。
但是,我无法理解操作系统如何到达共享 PTE 以将它们标记为“已读”。我假设当fork()系统调用发生时,操作系统在父页表上执行“页面遍历”并将它们标记为只读- 但我没有找到对此的确认,或有关该过程的任何信息。
有谁知道这些页面是如何被标记为只读的?将不胜感激任何帮助。谢谢!
如果在页面表中找不到虚拟地址,内核如何转换?该页面位于磁盘上,但内核究竟知道在哪里?(磁盘中的特定地址)
谢谢
我的印象是,Linux 内核试图保护自己的核心是不让恶意代码在内核空间中运行。特别是,如果要加载恶意内核模块,从安全角度来看,这将是“游戏结束”。然而,我最近看到一篇与这种观点相矛盾的帖子,并说内核可以通过某种方式保护自身的一部分免受自身其他部分的影响:
有很多机制可以保护您免受恶意模块的侵害。我写内核代码是为了好玩,所以我在这个领域有一些经验;它基本上是页表中的一个标志。
有什么可以阻止任何内核模块更改分页表中的那个标志?防止恶意模块的唯一保护是完全阻止它们加载。一旦加载,游戏就结束了。
使分页表只读。完毕。
内核模块可以再次将其设为可读写,就像您的代码将其设为只读一样,然后继续进行更改。
您实际上可以将其锁定,以便内核模式在发生中断之前无法修改页表。如果您的 IDT 也是只读的,则模块无法对其进行任何处理。
这对我来说没有任何意义。我是否遗漏了一些关于内核内存如何工作的重要信息?内核空间代码可以限制自己修改页表吗?这真的能阻止内核 rootkit 吗?如果是这样,那么为什么今天的 Linux 内核不这样做以结束所有内核 rootkit?
有人可以解释一下内核页表中的宏吗?
#define pgd_bad(pgd) (!(pgd_val(pgd) & 2))
#define pmd_bad(pmd) (!(pmd_val(pmd) & 2))
#define pud_bad(pud) (!(pud_val(pud) & 2))
Run Code Online (Sandbox Code Playgroud) 我正在执行页表遍历。当我准备更新内核时出现错误:
\n\nkernel/sys.c: In function \xe2\x80\x98__do_sys_get_page_info\xe2\x80\x99:\nkernel/sys.c:2745:23: error: passing argument 1 of \xe2\x80\x98pud_offset\xe2\x80\x99 from incompatible pointer type [-Werror=incompatible-pointer-types]\n pud = pud_offset(pgd, vmpage);\n ^\nIn file included from ./include/linux/mm.h:99:0,\n from kernel/sys.c:19:\n./arch/x86/include/asm/pgtable.h:905:22: note: expected \xe2\x80\x98p4d_t * {aka struct <anonymous> *}\xe2\x80\x99 but argument is of type \xe2\x80\x98pgd_t * {aka struct <anonymous> *}\xe2\x80\x99\n static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)\n ^\nRun Code Online (Sandbox Code Playgroud)\n\n这是使用代码的地方:
\n\n....\nint loc, ref, dirty;\nstruct vm_area_struct *vma;\nunsigned long vmpage;\nstruct mm_struct *task_mm = task->mm;\nif ((task_mm && task_mm->mmap))\n{\n int i;\n pgd_t *pgd;\n pud_t *pud;\n …Run Code Online (Sandbox Code Playgroud) 假设两个地址空间共享一块较大的非连续内存。系统可能希望在它们之间共享物理页表。这些表不会使用全局位(即使支持),并且如果支持的话会将它们绑定到asid。
这样做有直接的好处,因为数据缓存的污染比副本、更少的固定内存等污染要少。
页面遍历是否在任何已知架构中明确利用了这一点?如果是这样,这是否意味着mmu正在根据物理标签显式缓存和共享内部页面树节点?
很抱歉提出了多个问题;这确实是一件坏事。我正在尝试确定是否值得为此设计一个测量测试。