3 回答

TA貢獻1877條經驗 獲得超1個贊
我遇到了一些問題,因為我在2.6.32內核上進行了嘗試,WARNING: at arch/x86/mm/pageattr.c:877 change_page_attr_set_clr+0x343/0x530() (Not tainted)隨后出現了內核OOPS,因為它們無法寫入內存地址。
上述行上方的注釋指出:
// People should not be passing in unaligned addresses
以下修改的代碼有效:
int set_page_rw(long unsigned int _addr)
{
? ? return set_memory_rw(PAGE_ALIGN(_addr) - PAGE_SIZE, 1);
}
int set_page_ro(long unsigned int _addr)
{
? ? return set_memory_ro(PAGE_ALIGN(_addr) - PAGE_SIZE, 1);
}
請注意,在某些情況下,這實際上仍未將頁面設置為讀/寫。在static_protections()內部調用的函數會在以下情況下set_memory_rw()刪除_PAGE_RW標志:
在BIOS區域
地址在.rodata內部
設置CONFIG_DEBUG_RODATA且將內核設置為只讀
我在調試后發現了這個問題,為什么在嘗試修改內核函數的地址時仍然出現“無法處理內核分頁請求”。最終,我可以自己找到地址的頁表條目并將其手動設置為可寫,從而解決了該問題。值得慶幸的是,該lookup_address()功能已在2.6.26+版本中導出。這是我為此編寫的代碼:
void set_addr_rw(unsigned long addr) {
? ? unsigned int level;
? ? pte_t *pte = lookup_address(addr, &level);
? ? if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
}
void set_addr_ro(unsigned long addr) {
? ? unsigned int level;
? ? pte_t *pte = lookup_address(addr, &level);
? ? pte->pte = pte->pte &~_PAGE_RW;
}
最后,雖然Mark的答案在技術上是正確的,但在Xen中運行時會遇到問題。如果要禁用寫保護,請使用讀/寫cr0功能。我像這樣宏化它們:
#define GPF_DISABLE write_cr0(read_cr0() & (~ 0x10000))
#define GPF_ENABLE write_cr0(read_cr0() | 0x10000)
希望這對遇到這個問題的其他人有所幫助。

TA貢獻1982條經驗 獲得超2個贊
請注意,以下內容也可以代替使用change_page_attr起作用,并且不能折舊:
static void disable_page_protection(void) {
unsigned long value;
asm volatile("mov %%cr0,%0" : "=r" (value));
if (value & 0x00010000) {
value &= ~0x00010000;
asm volatile("mov %0,%%cr0": : "r" (value));
}
}
static void enable_page_protection(void) {
unsigned long value;
asm volatile("mov %%cr0,%0" : "=r" (value));
if (!(value & 0x00010000)) {
value |= 0x00010000;
asm volatile("mov %0,%%cr0": : "r" (value));
}
}
- 3 回答
- 0 關注
- 889 瀏覽
添加回答
舉報