• linux内核中ecryptfs模块分析


    1、何为ecryptfs

            内核中实现的一套加密文件系统。

            在VFS层和实际底层文件系统(如ext4、vfat)之间,嵌入一层ecryptfs。在该层完成文件的加解密处理。

            从而在通用文件系统的基础上,叠加该层实现文件系统的加密,而不是单纯去做一套加密文件系统,这样更加灵活,但堆叠式的文件系统会对性能带来一定影响。

    1. root@xxzh:~/src/kernel/fs/ecryptfs# ls
    2. built-in.o debug.c dentry.o ecryptfs.mod.c file.c inode.o keystore.o main.c messaging.c miscdev.o modules.order super.c
    3. crypto.c debug.o ecryptfs_kernel.h ecryptfs.mod.o file.o Kconfig kthread.c main.o messaging.o mmap.c read_write.c super.o
    4. crypto.o dentry.c ecryptfs.ko ecryptfs.o inode.c keystore.c kthread.o Makefile miscdev.c mmap.o read_write.o
    5. root@xxzh:~/src/kernel/fs/ecryptfs#

    如何用ecryptfs

            本文不再分析如何在ubunut上如何使用ecryptfs,网上教程比较多,在ubunut上基本安装后配置一下就可以达到效果。

            在内核安装ecryptfs模块之后,通过mount的时候指定为ecryptfs类型。如mmcblk0p1卡以ext4

    类型挂载在sd下,在sd下创建ecryptfs目录。然后挂载

    mount -t ecryptfs /sd/ecryptfs /sd/ecryptfs  ...

            ...中可以是一些加密参数。之后在/sd/ecryptfs目录下创建文件,读取文件都将经过加解密处理。最终磁盘上的文件都是经过加密处理的。访问时候需要先挂载。

    本文的重点

            本文重点说明ecryptfs的实现机制,以及如何通过mount嵌入ecryptfs层,并最终分析文件的读写过程。其中,并不重点分析加密过程,ecryptfs也依赖内核的加密模块进行加密。

    2、ecryptfs驱动初始化分析

    核心数据结构

    ecryptfs_inode_info

            ecryptfs_alloc_inode的时候,通过kmem_cache_alloc创建,并返回inode_info->vfs_inode。

    1. struct ecryptfs_inode_info {
    2.     struct inode vfs_inode;
    3.     struct inode *wii_inode;
    4.     struct mutex lower_file_mutex;
    5.     atomic_t lower_file_count;
    6.     struct file *lower_file;
    7.     struct ecryptfs_crypt_stat crypt_stat;
    8. };

    ecryptfs_sb_info 

            kmem_cache_zalloc创建,是sb的私有数据。sb->s_fs_info = sb_info

    1. /* superblock private data. */
    2. struct ecryptfs_sb_info {
    3. struct super_block *wsi_sb;
    4. struct ecryptfs_mount_crypt_stat mount_crypt_stat;
    5. struct backing_dev_info bdi;
    6. };

    入口函数

            核心函数调用如下:

    1. static int __init ecryptfs_init(void)
    2. {
    3. int rc;
    4. rc = ecryptfs_init_kmem_caches();
    5. #if 0
    6. rc = do_sysfs_registration();
    7. #endif
    8. rc = ecryptfs_init_kthread();
    9. #if 0
    10. rc = ecryptfs_init_messaging();
    11. #endif
    12. rc = ecryptfs_init_crypto();
    13. rc = register_filesystem(&ecryptfs_fs_type);
    14. return rc;
    15. }

            ecryptfs_init_kmem_caches中,使用kmem_cache_create创建了各种slab缓存,如inode的缓存,用户在文件产生、读写过程中使用,毕竟文件访问要讲究效率,所以用了slab。

            do_sysfs_registration注册sys下的辅助节点,不做分析

            ecryptfs_init_kthread创建了一个内核线程,后期用于绕过文件读写权限

            ecryptfs_init_messaging创建了一个辅助字符设备,不做分析

            ecryptfs_init_crypto 加密key链表初始化,不做分析

            register_filesystem注册ecryptfs文件系统,因为挂载的时候-t 指定了ecryptfs,所有一定有register_filesystem来注册这个文件系统,只是这个文件系统和ext4等不是并列关系,而是上下关系,最终在内核是VFS-ECRYPTFS-EXT4。

            因此,驱动入口函数,主要任务是创建slab缓存,并注册文件系统。

    3、ecryptfs文件系统信息

            注册的ecryptfs文件系统如下,可见创建一个文件系统,最重要的指定其名字,以及该名字的文件系统mount时候的调用函数ecryptfs_mount。

    1. static struct file_system_type ecryptfs_fs_type = {
    2. .owner = THIS_MODULE,
    3. .name = "ecryptfs",
    4. .mount = ecryptfs_mount,
    5. .kill_sb = ecryptfs_kill_block_super,
    6. .fs_flags = 0
    7. };
    8. MODULE_ALIAS_FS("ecryptfs");

            mount函数调用如下

    1. static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags,
    2. const char *dev_name, void *raw_data)
    3. {
    4. struct super_block *s;
    5. struct ecryptfs_sb_info *sbi;
    6. struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
    7. struct ecryptfs_dentry_info *root_info;
    8. const char *err = "Getting sb failed";
    9. struct inode *inode;
    10. struct path path;
    11. uid_t check_ruid;
    12. int rc;
    13. //创建超级块缓存
    14. sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL);
    15. //解析参数
    16. rc = ecryptfs_parse_options(sbi, raw_data, &check_ruid);
    17. //分配一个super_block
    18. s = sget(fs_type, NULL, set_anon_super, flags, NULL);
    19. //回写相关
    20. rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs");
    21. ecryptfs_set_superblock_private(s, sbi);
    22. s->s_bdi = &sbi->bdi;
    23. /* ->kill_sb() will take care of sbi after that point */
    24. sbi = NULL;
    25. //挂载文件系统的操作函数
    26. s->s_op = &ecryptfs_sops;
    27. s->s_d_op = &ecryptfs_dops;
    28. rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
    29. //防止重复mount
    30. if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) {
    31. goto out_free;
    32. }
    33. //挂载权限检查
    34. if (check_ruid && !uid_eq(d_inode(path.dentry)->i_uid, current_uid())) {
    35. goto out_free;
    36. }
    37. //底下一层文件系统的sb
    38. ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
    39. s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
    40. s->s_blocksize = path.dentry->d_sb->s_blocksize;
    41. s->s_magic = ECRYPTFS_SUPER_MAGIC;
    42. s->s_stack_depth = path.dentry->d_sb->s_stack_depth + 1;
    43. inode = ecryptfs_get_inode(d_inode(path.dentry), s);
    44. //设置全局根目录/
    45. s->s_root = d_make_root(inode);
    46. if (!s->s_root) {
    47. rc = -ENOMEM;
    48. goto out_free;
    49. }
    50. root_info = kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL);
    51. /* ->kill_sb() will take care of root_info */
    52. //设置文件系统的私有数据
    53. ecryptfs_set_dentry_private(s->s_root, root_info);
    54. root_info->lower_path = path;
    55. s->s_flags |= MS_ACTIVE;
    56. return dget(s->s_root);
    57. }

            kmem_cache_zalloc创建超级块ecryptfs_sb_info,作为超级块的信息sb->s_fs_info = sb_info。

            ecryptfs_parse_options解析mount时候传入的加密信息,不做分析

            sget创建一个超级块,每个文件系统都需要有的,存在文件系统相关信息。

            bdi_setup_and_register,bdi回写相关设置初始化

            kern_path获取挂载路径信息,存储在path

            ecryptfs_set_superblock_lower将ecryptfs和底层文件系统关联。

            ecryptfs_get_inode获取挂载目录的ecryptfs层的inode。

    4、创建新文件

            执行touch text.txt的时候,会创建这个文件,从上层看会调用VFS层的vfs_create,之后进入ecryptfs层,之后再到具体的文件系统层。

            VFS层对下层的调用:

             如上,我们在根目录下创建新文件,因此是根据挂载目录的inode里面的方法进行create。那么挂载目录的inode在哪里设置呢。在mount的时候设置的,如下:

     

            通过上面,在vfs_create的时候,调用了ecryptfs_dir_iops中的ecryptfs_create函数创建。

     创建文件的主要工作:

            根据挂载时候给mount点inode的设置,调用其设置好的create函数,产生新文件的inode,并在新文件开始的前8K空间中存储加解密信息。并为新文件初始化并设置了inode,为后续读写准好了准备。

    5、写加密文件

            还是定位到VFS层到ecryptfs的入口。写之前肯定还有open操作。

    写加密文件总结:

            以page为单位进行加密处理,分配一个page进行加密,加密后写入底层文件。全程依赖VFS层inode,并通过该inode找到底层inode后进行最后写入。

    存储介质中ext4的文件排布_【星星之火】的博客-CSDN博客

     

    6、VFS与下层函数设置关系

    6.1 inode的设置

            在获取inode的时候,通过ecryptfs_inode_set设置了indo中的操作函数。

     

  • 相关阅读:
    夯实c语言基础
    华为云实验 -- 对云硬盘数据盘进行备份
    【Shell编程】| if 判断
    80%测试员被骗,关于jmeter 的一个弥天大谎!
    Dijkstra 邻接表表示算法 | 贪心算法实现--附C++/JAVA实现源码
    【Linux】 yum —— Linux 的软件包管理器
    二叉树链式存储结构
    SAP ABAP基础语法-日期函数(九)
    容器中的nginx暴露一个端口部署多个功能的网站
    ctf之流量分析学习
  • 原文地址:https://blog.csdn.net/fengyuwuzu0519/article/details/126526213