inux內核獲取進程的全路徑3種方法
 

 

 

本文檔的CopyRight歸jonathan所有,可自由轉載,轉載時請保持文檔的完整性。
/*----------------------------------------------------------------------------------------------------------------------------*/

在linux內核獲取進程全路徑方式類似Windows內核獲取進程路徑,方法多樣。但是由於linux設計地特點,沒有一個很好的方法來直接獲取路徑:進程是動態執行體,其沒有物理位置的概念,嚴格於程序的概念區分開來。但是否就無法獲取linux內核進程全路徑了呢?答案當然是否定的。

task_struct結構中有一comm子段,里面存儲着程序的名稱,而且名稱最大是16(Windows 的 EPROCESS里面的ImageName也是16位,哪個先提出來的?!!)但是不包括路徑名稱。從task_struct獲取路徑基本就是靠mm_struct這個結構了,從中可以獲取進程全路徑。

在linux內核據我個人掌握的方法有3種,這里一一說明。

1 通過exe_file

     task_struct->mm->exe_file->f_path可獲取全路徑。

    但是此方法有限制,內核必須啟用PROC_FS。而一般發行版都是去掉這個選項的。因此不重新編譯內核基本無法使用,否則機器就要當了。

2 通過arg_xxx的進程參數內存   

task_struct->mm->arg_start ~ arg_end 之間內存存儲進程的參數,當然也包括了程序的全路徑。

     但是此方法也有限制,一般發行版中似乎都把這部分內容抹去了。我在自己編譯的內核中可以獲取,但是在發行版中就無法獲取到內容。此處很奇怪。

static void util_get_task_name(pid_t pid)
{
        struct task_struct *task = find_task_by_vpid(pid);
        
        if(task != NULL)
        {
                char *name = kzalloc(PATH_MAX, ATOM);
                char *buffer = NULL;
                struct mm_struct *mm = get_task_mm(task);
                int len = 0;
                unsigned long address = 0;
  
                if(!name || !mm)
                        goto out;

                down_read(&mm->mmap_sem);

                len = mm->arg_end - mm->arg_start;
                address = mm->arg_start;
                buffer = name;

                 while(len)
                {
                        void *maddr = NULL;
                        struct page *page = NULL;
                        struct vm_area_struct *vma = NULL;
                        int bytes = 0, offset = 0;
                        
                        int ret = get_user_pages(task, mm, address, 1, 0, 1, &page, &vma);

                        if(ret <= 0)
                        {
                                bytes = ret;
                                goto next;
                        }
                                
                        bytes = len;
                        offset = address & (PAGE_SIZE-1);       

                        if (bytes > PAGE_SIZE-offset)
                                bytes = PAGE_SIZE - offset;
                        
                        maddr = kmap(page);
                        copy_from_user_page(vma, page, address, buffer, maddr + offset, bytes);
                        kunmap(page);

                        page_cache_release(page);

next:
                        len -= bytes;
                        address += bytes;
                        buffer += bytes;
                }
                
                up_read(&mm->mmap_sem);
                mmput(mm);

                printk("xxxxxxxxxxxxx: name = %s, len = %d\n", name, len);
        }

out:

        if(name) kfree(name);
        return;
}

3 通過vm_area_struct

task_struct->mm->mmap,這里需要檢查檢查影射的內存是代碼段屬性(VM_EXECUTABLE)。獲取的進程對應的程序的文件名稱不包含路徑。

要想獲取全路徑,需要向上查找父路徑,最后拼湊起來全路徑。