• 通过对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);
    
    }
  • 相关阅读:
    sqoop导入数据到mysql原理_sqoop的详细使用及原理
    Attempt to do update or delete using transaction manager that does not support these operations
    impala安装
    stm32单片机时钟中断的配置
    jtag引脚
    关于芯片封装类型
    Altium Designer绘制mark点
    Altium Designer如何移动选中的所有对象
    Altium Designer敷铜的规则设定
    关于Altium Designer重新修改某一原件pcb封装的问题
  • 原文地址:https://www.cnblogs.com/wuyuegb2312/p/2530249.html
Copyright © 2020-2023  润新知