目录
0. 引言 1. 基于进程内存镜像信息struct mm_struct获取struct path调用d_path()获取当前进程的"绝对路径" 2. 基于文件描述符(fd)、task_struct调用d_path()获取当前进程的"当前目录" 3. 基于dentry、vfsmount调用d_path()获取当前进程的"当前目录" 4. 基于get_fs_pwd获取当前目录
0. 引言
本文涉及的是ring0下的获取当前进程工作目录的方法,LKM位于linux的内核内存区域,任何进程都可以通过LKM的导出函数指定当前LKM的代码,所以,我们需要在LKM中获取当前调用进程的当前工作目录
1. 基于进程内存镜像信息struct mm_struct获取struct path调用d_path()获取当前进程的"绝对路径"
d_path是内核提供的根据dentry和vfsmount获取绝对路径函数
此函数有2个版本,以内核版本2.6.25为分界 1. extern char *d_path(const struct path *, char *, int); 2. extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
get_absolute_path.c
#include <linux/module.h> #include <linux/fcntl.h>//for O_RDONLY #include <linux/fs.h>//for filp_open #include <linux/uaccess.h>//for get_fs #include <linux/limits.h>//for PATH_MAX #include <linux/sched.h> #include <linux/mm.h> char* get_absolute_path(struct task_struct * task) { char * ret_ptr = NULL; char * tpath = NULL ; struct vm_area_struct * vma = NULL; struct path base_path; tpath = (char*)kmalloc(512, 0); if(NULL == tpath || NULL == task) { return NULL; } memset(tpath,‘\0‘,512); task_lock(task); /* 获取当前进程的内存空间信息(通过内存空间) */ if(task->mm && task->mm->mmap) { vma = task->mm->mmap; } else { task_unlock(task); kfree(tpath); return NULL; } /* 取得path(a struct含dentry和vfsmount) */ while(vma) { if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { base_path = vma->vm_file->f_path; break; } vma = vma->vm_next; } task_unlock(task); /* * 调用 d_path, 得到绝对路径 */ ret_ptr = d_path(&base_path, tpath, 512); return ret_ptr; } int init_module(void) { struct task_struct * task = current; char *path = get_absolute_path(task); printk("FULLPATH: %s\n", path); return 0; } void cleanup_module(void) { } MODULE_LICENSE("GPL");
Makefile
# # Variables needed to build the kernel module # name = get_absolute_path obj-m += $(name).o all: build .PHONY: build install clean build: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y install: build -mkdir -p /lib/modules/`uname -r`/kernel/arch/x86/kernel/ cp $(name).ko /lib/modules/`uname -r`/kernel/arch/x86/kernel/ depmod /lib/modules/`uname -r`/kernel/arch/x86/kernel/$(name).ko clean: [ -d /lib/modules/$(shell uname -r)/build ] && make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Relevant Link:
http://blog.csdn.net/cenziboy/article/details/8761621
2. 基于文件描述符(fd)、task_struct调用d_path()获取当前进程的"当前目录"
/* 根据task_struct、fd(文件描述符)获取当前工作路径 */ int get_path(struct task_struct *mytask, int fd) { struct file *myfile = NULL; struct files_struct *files = NULL; char path[100] = {‘\0‘}; char *ppath = path; files = mytask->files; if (!files) { printk("files is null..\n"); return -1; } myfile = files->fdt->fd[fd]; if (!myfile) { printk("myfile is null..\n"); return -1; } ppath = d_path(&(myfile->f_path), ppath, 100); printk("FULLPATH: %s\n", ppath); return 1; }
Relevant Link:
http://edsionte.com/techblog/archives/4406 http://xd03071149.blog.163.com/blog/static/12350636320129822841854/
3. 基于dentry、vfsmount调用d_path()获取当前进程的"当前目录"
1. 首先得到文件对应的struct file结构 2. 后再用结构中的f_dentry和f_vfsmnt字段充当d_path的前两个参数 3. 得到了这个文件的绝对路径了具体步骤如下
关于linux内核中和文件系统、VFS相关的数据结构,请参阅另一篇文章
http://www.cnblogs.com/LittleHann/p/3865490.html
code
#include <linux/module.h> #include <linux/fcntl.h>//for O_RDONLY #include <linux/fs.h>//for filp_open #include <linux/uaccess.h>//for get_fs #include <linux/limits.h>//for PATH_MAX #include <linux/sched.h> #include <linux/mm.h> #include <linux/fdtable.h> #include <linux/types.h> #include <linux/stat.h> #include <linux/unistd.h> #include <linux/dcache.h> #include <linux/fs_struct.h> #include <linux/mount.h> #define MAX_TMPPATH 1024 void get_absolute_path(char *mod_name) { /* 假设 1024 已经足够了 */ char tmp_path[MAX_TMPPATH] = {0}; char * ptr = NULL; struct dentry *dentry = NULL; struct vfsmount * mnt = NULL; memset(tmp_path, 0, MAX_TMPPATH); ptr = tmp_path + MAX_TMPPATH - 256; task_lock(current); /* Get the Process working dentry */ dentry = current->fs->pwd.dentry; /* Get the Process working vfsmount */ mnt = current->fs->pwd.mnt; do { /* Process the dentry */ while(dentry && dentry->d_name.name && strcmp(dentry->d_name.name,"/")) { ptr = ptr - strlen(dentry->d_name.name); if(ptr <= tmp_path + strlen(dentry->d_name.name) + 1) { break; } memcpy(ptr, dentry->d_name.name, strlen(dentry->d_name.name)); *(--ptr) = ‘/‘; dentry= dentry->d_parent; } /* Process the filesystem mountpoint, 突破挂载点 */ if(mnt && mnt->mnt_mountpoint && mnt->mnt_mountpoint->d_name.name && strcmp(mnt->mnt_mountpoint->d_name.name,"/")) { dentry = mnt->mnt_mountpoint; ptr = ptr - strlen(dentry->d_name.name); if(ptr <= tmp_path + strlen(dentry->d_name.name) + 1) { break; } memcpy(ptr,dentry->d_name.name,strlen(dentry->d_name.name)); *(--ptr) = ‘/‘; mnt = mnt->mnt_parent; dentry= dentry->d_parent; } } while( 0 != strcmp(mnt->mnt_mountpoint->d_name.name,"/")); /* end do */ /* 直到文件系统的挂载点为 / */ task_unlock(current); //concat the full path strcat(ptr, "/"); strcat(ptr, mod_name); strcat(ptr, ".ko"); printk("full path: %s\n",ptr); } int init_module(void) { get_absolute_path(THIS_MODULE->name); } void cleanup_module(void) { } MODULE_LICENSE("GPL");
Makefile
# # Variables needed to build the kernel module # name = fd_d_path obj-m += $(name).o all: build .PHONY: build install clean build: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y install: build -mkdir -p /lib/modules/`uname -r`/kernel/arch/x86/kernel/ cp $(name).ko /lib/modules/`uname -r`/kernel/arch/x86/kernel/ depmod /lib/modules/`uname -r`/kernel/arch/x86/kernel/$(name).ko clean: [ -d /lib/modules/$(shell uname -r)/build ] && make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Relevant Link:
http://blog.csdn.net/cenziboy/article/details/7999217
4. 基于get_fs_pwd获取当前目录
2.6.39以上才能用 //获取.ko文件路径 /* get_fs_pwd(current->fs, &ko_pwd); ko_buf = (char*)__get_free_page(GFP_USER); ko_path = dentry_path_raw(ko_pwd.dentry, ko_buf, PAGE_SIZE); free_page((unsigned long)ko_buf); */ /* getcwd(buf, sizeof(buf)); */
待研究
Copyright (c) 2014 LittleHann All rights reserved
Linux Kernel中获取当前目录方法(undone),布布扣,bubuko.com
原文:http://www.cnblogs.com/LittleHann/p/3927316.html