2014-01-09 36 views
1

我目前處於需要重新定位TCB(線程控制塊)的情況。 從我的理解,下面的方案是到位的處理的執行調用VDSO(根據this article重定位線程控制塊

  • 全部由指令呼叫觸發時*%GS:0x10的
  • %GS是段寄存器使用全局描述符表。 GDT是存儲在與進程關聯的內核堆棧中的關聯表,並且在進程的地址空間中的段寄存器值和地址之間保持對應關係。它是隨機初始化並由加載程序(glibc庫的一部分)選擇的
  • 一旦建立了對應關係,處理器將讀取*(GDT [%gs] + 0x10)處的地址,並進行VDSO中的呼叫。
  • 系統調用被執行並且從內核返回到用戶進程在內核的AS中使用返回地址存儲。

我的問題是我需要重寫一些我的進程內存與其他東西,大部分時間,它擦除地址部分(GDT [%gs] + 0x10)。

我想要做的是在我的進程AS中的一個空閒位置重定位TCB的內容(從GDT [%gs]到GDT [%gs] + 0x ..),但這意味着改變GDT的內容,我認爲我無法從用戶模式中完成。換句話說,我想在我的GDT中更改%GS的關聯。

預先感謝任何回答, /iansus

回答

0

好吧,我找到了解決辦法:

int relocateTCB() 
{ 

#ifndef TCB_LDT_INDEX 
#define TCB_LDT_INDEX 6 
#endif 


    struct user_desc* u_info = (struct user_desc*) malloc(sizeof(struct user_desc)); 
    int r,j; 
    int mstart, map; 
    int PS = sysconf(_SC_PAGESIZE); 

    if(u_info == NULL) 
    { 
     errno = EFAULT; 
     return -1; 
    } 

    u_info->entry_number = TCB_LDT_INDEX; 
    r = syscall(SYS_get_thread_area, u_info); 

    if(r==-1) return -1; 

    mstart = (u_info->base_addr) & ~(PS-1); 
    map = (int) mmap(NULL, PS, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, (off_t)0); 

    if(!map) 
    { 
     errno = EFAULT; 
     return -1; 
    } 

    for(j=mstart; j<mstart+PS; j+=sizeof(int)) 
    { 
     * ((int*) (map+j-mstart)) = * ((int*) j); 
    } 

    u_info->base_addr = map + u_info->base_addr - mstart; 
    r = syscall(SYS_set_thread_area, u_info); 

    if(r==-1) 
    { 
     errno = EINVAL; 
     return -1; 
    } 

    for(j=mstart; j<mstart+PS; j+=sizeof(int)) 
     *((int*) j) = 0; 

    // Keep *%gs = %gs 
    *((int*) u_info->base_addr) = u_info->base_addr; 

    return 0; 
}