本文档的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)。获取的进程对应的程序的文件名称不包含路径。
要想获取全路径,需要向上查找父路径,最后拼凑起来全路径。