通过对inode的修改对文件操作进行扩充

  在open、read、write的参数中,mode的接口提供的比较方便,通过对fs/namei.c中vfs_create()中添加判断,解除对高位的事后修改就能传入到文件的i_mode。然而i_mode各个位基本已被使用完毕,使用新的组合的mode可能会将这一类文件变为“古怪的文件”,虽然能用open()、read()、write()进行操作,但是不能用vi等工具打开,原因可能是没有针对这种mode添加进一步的其他操作,用起来并不像S_IFREG这种普通文件这么方便。

  经指点和启发,使用这三个函数的flag位进行扩充是可行的,以下是实现方法。本文以2.6.13的内核为例。

  /include/asm-i386/fcntl.h中添加一个新的flag,为open()进行i_node的flag的填充提供判断依据,如#define O_SECRET 04。

  /include/linux/fs.h中Inode flags添加一个新的flag,这个是inode中保存的flag,为read和write提供判断的依据,如#define S_SECRET 1024。

  这里需要说明一下,创建inode时使用了i_op->create。之前读到这里时感觉线索已经断了,这个create的定义在哪里呢?一篇文章对其进行了解释,文件系统的挂载会自动用相应的操作替换这个i_op。点击访问原文

i_op的替换过程(以ext2为例)
/* cnode.c */
static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
{
        coda_vattr_to_iattr(inode, attr);

        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &coda_file_inode_operations;
                inode->i_fop = &coda_file_operations;
        } else if (S_ISDIR(inode->i_mode)) {
                inode->i_op = &coda_dir_inode_operations;
                inode->i_fop = &coda_dir_operations;
        } else if (S_ISLNK(inode->i_mode)) {
        inode->i_op = &coda_symlink_inode_operations;
        inode->i_data.a_ops = &coda_symlink_aops;
        inode->i_mapping = &inode->i_data;
    } else
                init_special_inode(inode, inode->i_mode, huge_decode_dev(attr->va_rdev));
}

  重新梳理一下flag的传递过程。open() --> sys_open() --> filp_open() --> open_namei() (此时填充到nd中) --> vfs_create() --> i_op->create (对应namei.c中ext3_create()),在这里对新定义的flag进行处理。判断逻辑:if ((nd->intent.open.flags & 1024) == 1024)  ...; 此时要将namei.c中添加#include <linux/namei.h>。

  之后对sys_write()进行扩充。

if (file) {
        loff_t pos = file_pos_read(file);
        if ((file->f_dentry->d_inode->i_flags) & 1024) //新增异或加密功能
        {
            //printk("I'm in write...\n");
            test4_secret(buf,count);
            //printk("%s\n",buf);
            ret = vfs_write(file, buf, count, &pos);
        } else
            ret = vfs_write(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);

 

  加密函数如下,有一些bug没有修正,可能造成缓冲区溢出:

int test4_secret(const char *buf, size_t count) {
    char key ='a';
    char *ptr;
    ptr = buf;
    while (count) {
        *ptr = *ptr ^ key;
        ptr ++;
        count --;
    }
    return 0;
}

  sys_read()可以做类似处理,但这会造成整个写——读“透明”,无法判断是否成功加密。如果仅作验证,只修改sys_write()就行了。

测试程序
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

main() {
    int fd;
    char buf[1024]="my string.";
    struct stat stat_buf;
    fd = open("my", O_CREAT|O_WRONLY|O_TRUNC|04, 0777);
    //fstat(fd, &stat_buf);
    //printf("%o\n",stat_buf.st_mode);
    printf("%s\n",buf);
    int temp = strlen(buf);
    write(fd, buf ,temp);
    printf("%s\n",buf); 
    close(fd);

}
posted @ 2012-06-04 11:44  五岳  阅读(3067)  评论(0编辑  收藏  举报
回到顶部