3 回答

TA貢獻1877條經(jīng)驗 獲得超1個贊
我遇到了一些問題,因為我在2.6.32內(nèi)核上進行了嘗試,WARNING: at arch/x86/mm/pageattr.c:877 change_page_attr_set_clr+0x343/0x530() (Not tainted)隨后出現(xiàn)了內(nèi)核OOPS,因為它們無法寫入內(nèi)存地址。
上述行上方的注釋指出:
// 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()內(nèi)部調用的函數(shù)會在以下情況下set_memory_rw()刪除_PAGE_RW標志:
在BIOS區(qū)域
地址在.rodata內(nèi)部
設置CONFIG_DEBUG_RODATA且將內(nèi)核設置為只讀
我在調試后發(fā)現(xiàn)了這個問題,為什么在嘗試修改內(nèi)核函數(shù)的地址時仍然出現(xiàn)“無法處理內(nèi)核分頁請求”。最終,我可以自己找到地址的頁表條目并將其手動設置為可寫,從而解決了該問題。值得慶幸的是,該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條經(jīng)驗 獲得超2個贊
請注意,以下內(nèi)容也可以代替使用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));
}
}
添加回答
舉報