linux 内核super_block 获取文件绝对路径,Linux内核中用d_path得到绝对路径名

Linux内核中用d_path得到绝对路径名

Linux 内核的d_path()函数转换目录数据结构(dentry结构)到ASCII路径名字,指定的目录数据结构(dentry结构)路径返回在一个缓冲区中,这个缓冲区得内核开发人员自己申请,自己释放。

在linux2.4.18以前的内核中,指定的目录数据结构(dentry结构)路径返回在一段大小为PAGE_SIZE字节的固定缓冲区中。 这样就存在一个著名的d_path()路径截断漏洞,也就是如果提交的的目录数据结构(dentry结构)路径过长,超过PAGE_SIZE - 1长度,就会返回不正确的值,返回的路径就会导致结构条目被截断,并没有错误报告。

那么先来看一下d_path的定义:

include/linux/dcache.h(linux kernel 2.6.24)

/* write full pathname into buffer and return start of pathname */

extern char * d_path(struct dentry *, struct vfsmount *, char *, int);

第一个参数struct dentry是目录项结构,我们知道linux内核的虚拟文件系统的通用文件模型是由四个结构组成的:超级块对象(struct super_block),索引节点对象(struct inode),目录项对象(struct dentry)和文件对象(struct file).

第二个参数就是此目录结构所属于的已安装文件系统

第三个参数就是要存储绝对路径名的缓冲区

第四个参数缓冲区大小

那么怎么得到这个struct dentry和struct vfsmount呢?

--------------------------------------------------------

我们再来看一个结构struct fs_struct:

这个结构都是和进程相关的,我们知道每一个进程都有它自己的当前工作目录和它自己的根目录(这仅仅是内核用来表示进程与文件系统相互作用所必须维护的数据中的两个例子).结构fs_struct的目的就在于记录进程和文件系统的关系.每个进程描述符的fs字段就是指向进程的fs_struct结构.

struct fs_struct {

atomic_t count;

rwlock_t lock;

int umask;

struct dentry * root,* pwd, * altroot;

struct vfsmount * rootmnt,* pwdmnt, * altrootmnt;

};

我们可以用这个结构中的pwd和pwdmnt来充当d_path的前两个参数,得到进程当前工作目录pwd的名字,然后再合并上在当前工作目录中打开的文件的名字,就得到了在当前工作目录下已打开文件的绝对路径名.大概流程如下:

pwd = dget(fs->pwd);

vfsmnt = mntget(fs->pwdmnt);

start = d_path(pwd,vfsmnt,path,PATH_MAX);

strcat(fullpath,start);

strcat(fullpath,"/");

strcat(fullpath,filename);

这个方法其实是首先得到进程的当前工作路径,然后再拼接上文件名.如果已打开的文件是在进程的当前工作目录下的,那么这个方法没问题.但是如果已打开的文件不是在进程当前的工作目录下呢?

-------------------------------------------------------------

我们知道每一个已打开的文件,内核中都有一个struct file与之对应.

struct file {

/*

* fu_list becomes invalid after file_free is called and queued via

* fu_rcuhead for RCU freeing

*/

union {

struct list_head        fu_list;

struct rcu_head         fu_rcuhead;

} f_u;

struct path             f_path;

#define f_dentry        f_path.dentry #define f_vfsmnt        f_path.mnt         const struct file_operations    *f_op;         atomic_t                f_count;         unsigned int            f_flags;         mode_t                  f_mode;         loff_t                  f_pos;         struct fown_struct      f_owner;         unsigned int            f_uid, f_gid;         struct file_ra_state    f_ra;         u64                     f_version; #ifdef CONFIG_SECURITY         void                    *f_security; #endif         /* needed for tty driver, and maybe others */         void                    *private_data; #ifdef CONFIG_EPOLL         /* Used by fs/eventpoll.c to link all the hooks to this file */         struct list_head        f_ep_links;         spinlock_t              f_ep_lock; #endif /* #ifdef CONFIG_EPOLL */         struct address_space    *f_mapping; }; 所以,我们可以这样做,首先得到文件对应的struct file结构,然后再用结构中的f_dentry和f_vfsmnt字段充当d_path的前两个参数,这样就得到了这个文件的绝对路径了,具体步骤如下: struct file *file = NULL; file = filp_open(MY_FILE, O_RDWR | O_CREAT,0644); d_path(file->f_dentry,file->f_vfsmnt,buffer,pathmax); ------------------------------------------------------------ 下面给出这两种方法的具体实现(针对linux2.6.24内核) ---------- util.h ---------- #ifndef __UTIL_H__ #define __UTIL_H__ char* getfullpath(const char* filename); char* getfullpath2(struct file* file); void putfullpath(char *mem); #endif // __UTIL_H_ ------------- util.c ------------- #include #include #include "util.h" char* getfullpath(const char* filename) {         char *path=NULL, *start=NULL;     char *fullpath=NULL;     struct dentry * pwd = NULL;     struct vfsmount *vfsmnt = NULL;     struct fs_struct *fs = current->fs;         fullpath = kmalloc(PATH_MAX,GFP_KERNEL);     if(!fullpath) goto OUT;     memset(fullpath,0,PATH_MAX);     path = kmalloc(PATH_MAX,GFP_KERNEL);     if(!path) {         kfree(fullpath);         goto OUT;     }     //get the dentry and vfsmnt     read_lock(&fs->lock);     pwd = dget(fs->pwd);     vfsmnt = mntget(fs->pwdmnt);     read_unlock(&fs->lock);     //get the path     start = d_path(pwd,vfsmnt,path,PATH_MAX);     strcat(fullpath,start);     strcat(fullpath,"/");     strcat(fullpath,filename);     kfree(path); OUT:     return fullpath; } char* getfullpath2(struct file* file) {         char *path=NULL, *start=NULL;     char *fullpath=NULL;     fullpath = kmalloc(PATH_MAX,GFP_KERNEL);     if(!fullpath) goto OUT;     memset(fullpath,0,PATH_MAX);     path = kmalloc(PATH_MAX,GFP_KERNEL);     if(!path) {         kfree(fullpath);         goto OUT;     }     memset(path,0,PATH_MAX);     //get the path     start = d_path(file->f_dentry,file->f_vfsmnt,path,PATH_MAX);     strcpy(fullpath,start);     kfree(path); OUT:     return fullpath; } void putfullpath(char* fullpath) {   if(fullpath)     kfree(fullpath); } ------------ main.c ------------ #include #include //for O_RDONLY #include //for filp_open #include //for get_fs #include //for PATH_MAX #include "util.h" #define MY_FILE "./abc" #define FILE_NAME "abc" #define TMP_FILE "/tmp/123" void test1(void) {   struct file *file = NULL;   char* fullpath = NULL;   //open ./abc   file = filp_open(MY_FILE, O_RDWR | O_CREAT,0644);   if (IS_ERR(file)) {     printk( "error occured while opening file %s, exiting.../n ", MY_FILE);     return;   }   //get the fullpath   fullpath = getfullpath(FILE_NAME);   if(!fullpath){     printk("Get fullpath error!/n");     return;   }   printk("FULLPATH:%s/n",fullpath);   //free mem   putfullpath(fullpath);   //close ./abc   if(file != NULL)     filp_close(file, NULL);   } void test2(void) {   struct file *file = NULL;   char* fullpath = NULL;   //open /tmp/123   file = filp_open(TMP_FILE, O_RDWR | O_CREAT,0644);   if (IS_ERR(file)) {     printk( "error occured while opening file %s, exiting.../n ", TMP_FILE);     return;   }   //get the fullpath   fullpath = getfullpath2(file);   if(!fullpath){     printk("Get fullpath error!/n");     return;   }   printk("FULLPATH:%s/n",fullpath);   //free mem   putfullpath(fullpath);   //close /tmp/123   if(file != NULL)     filp_close(file, NULL);   } int init_module(void) {   //full pathname = path + name   test1();   //full pathname = d_path()   test2();   return 0; } void cleanup_module(void) { } MODULE_LICENSE("GPL"); ----------- Makefile ----------- obj-m := my_test.o my_test-objs :=  main.o util.o all:     make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules     rm -f *.o *.mod.c .*.cmd sysenter.h Module.symvers clean:     rm -f *.o *.ko *.mod.c .*.cmd sysenter.h Module.symvers     make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean ----------------------------------------------------------------------------- 执行结果: $ make $ sudo insmod ./my_test.ko $ dmesg | tail [ 5530.069194] FULLPATH:/home/xulei/Project/kernel_project/absolute_path/abc [ 5530.069208] FULLPATH:/tmp/123

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值