在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。点击访问原文
/* 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); }