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)。获取的进程对应的程序的文件名称不包含路径。

要想获取全路径,需要向上查找父路径,最后拼凑起来全路径。