Linux Kernel中获取当前目录方法(undone)

目录

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),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。