我正在为研究项目编写内核空间组件,这需要我在执行的不同点拦截和检查用户空间进程(具体说明)。由于各种原因,我无法修改用户空间程序或者ptrace那个过程。
为了实现这个目标,我试图在用户空间进程中插入一个断点(INT 3指令),我需要检查它,然后在内核空间中拦截SIGTRAP。不幸的是,我似乎无法弄清楚如何从该进程的内核空间正确修改用户空间代码的只读文本部分。我目前正在尝试使用get_user_pages
API强制页面可写并修改它们,但文本数据似乎没有变化。代码I尝试使用的相关部分如下。 user_addr
是在(unsigned long)
处插入断点的用户空间地址; page
是struct page *
。
char *addr;
unsigned long aligned_user_addr = user_addr & ~((unsigned long)PAGE_SIZE - 1);
down_read(¤t->mm->mmap_sem);
rc = get_user_pages(current, current->mm, aligned_user_addr,
1, 1, 1, &page, &vma);
up_read(¤t->mm->mmap_sem);
BUG_ON(rc != 1);
addr = kmap(page);
BUG_ON(!addr);
offs = user_addr % PAGE_SIZE;
/* NOTE: INT3_INSTR is defined to be 0xCC */
addr[offs] = INT3_INSTR;
BUG_ON(addr[offs] != INT3_INSTR); // Assertion fails
set_page_dirty(page);
kunmap(page);
page_cache_release(page);
我希望有更多内核知识和经验的人能够告诉我我做错了什么,或者正确的方法来完成我的任务。
感谢您的帮助。
答案 0 :(得分:1)
事实证明我的问题实际上是C符号扩展。 INT3_INSTR
定义为:
#define INT3_INSTR 0xCC
这使它成为一个整数,并且行:
BUG_ON(addr[offs] != INT3_INSTR);
评估addr[offs]
为signed char
。在c中,当signed char
与int
进行比较时,其类型被提升为int
的类型,并且由于其签名,如果其MSB为1,则将对其进行签名扩展。作为0xCC&#39 ; MSB始终为1,总是评估为:
BUG_ON(0xFFFFFFCC != 0xCC);
评价为假。将addr
更改为unsigned char *
可解决此问题。然后上面的代码工作。