假设我有一个只读的内存页面(例如,通过mmap / mprotect设置)。如何以尽可能低的开销修改此页面上的一个字(8个字节)?
某些上下文:我假设x86-64,Linux作为我的运行时环境。修改很少发生,但经常发生,所以我不得不担心开销。该页面是只读的,以保护程序必须经常读取的一些重要数据,以防止恶意/非法修改。只有很少的地方可以修改页面上的数据,我知道这些地方的所有位置和页面的静态地址。我试图解决的问题是保护一些数据免受程序中的内存安全漏洞的影响,我需要在一些授权的地方对数据进行修改。这些修改并不频繁但频繁,因此几次内核往返(通过系统调用)成本太高。
到目前为止,我想到了以下解决方案:
的mprotect
mprotect(addr, 4096, PROT_WRITE | PROT_READ);
addr[12] = 0xc0fec0fe;
mprotect(addr, 4096, PROT_READ);
mprotect解决方案干净,简单,直接。不幸的是,它涉及到内核的两次往返,并将导致一些开销。此外,整个页面在该时间范围内是可写的,允许其他一些线程同时修改该内存区域。
ptrace的
不幸的是,ptraceing自己不再可能了(因为ptraced-process需要停止。所以解决方法是fork,ptrace子进程,然后使用PTRACE_POKETEXT写入子进程内存。
此选项具有产生父进程的缺点,并且如果tracee使用多个进程将导致问题。每次写入的开销至少是PTRACE的一个系统调用加上进程之间所需的同步。
共享内存
共享内存与ptrace解决方案类似,只是它减少了系统调用。这两个进程都设置了具有不同权限的共享内存(子级中的RW,父级中的R)。这两个进程仍需要在每次写入时进行同步,然后由父进程执行。共享内存在复杂性方面与ptrace解决方案类似,并且与多个通信进程不兼容。
新系统调用
向内核添加新的系统调用将解决问题,并且只需要单个系统调用即可修改流程中的一个单词,而无需更改页表或设置多个通信流程的要求。
有没有比4讨论/勾画的解决方案更快的东西?我可以依赖任何调试功能吗?还有其他整洁的低级系统技巧吗?