ecryptfs透明加密

构建思想

透明加密一直是安全领域比较热门的领域,了解了下linux内核自带的ecryptfs。首先作者为了实现透明加密,构造了一个ecryptfs的文件系统。这个文件系统并没有对, 磁盘文件的直接组织,而是依附在已有的文件系统上,通过构建的文件系统对已有的文件系统做了重新组织实现。

文件系统架构

ecryptfs透明加密_第1张图片
正如常见的文件系统构成一样,ecrypt构建了自己的文件系统节点管理逻辑。
ecryptfs透明加密_第2张图片
之后是磁盘管理和虚拟文件系统管理。这些都是依附与一个叫lowe_path的核心逻辑,就是未加密文件夹。通过对未加密文件夹重新组织,实现对未加密文件页缓存加密。

剩余的就是挂载节点的管理如下图:
ecryptfs透明加密_第3张图片

文件系统构建起点

为了构造一个完整的加密文件系统,不可能自己实现inode dentry的管理,因为需要劫持底层ext4等文件的页缓存。那么就要依赖现有的文件inode管理。

研究struct file_system_type 的mount实现,可以观察到:
ecryptfs透明加密_第4张图片
整个文件系统围绕 dev_name构造的lower_path lower_sb进行。这个节点就是真实文件系统的节点管理的核心,也就是加密前的文件系统。这样借助现有文件系统,可以更方便的虚拟处一个文件系统,但实际数据全部还是在真是的文件系统上。

ecryptfs透明加密_第5张图片

文件节点创建

ecryptfs透明加密_第6张图片

static struct inode *
ecryptfs_do_create(struct inode *directory_inode,
		   struct dentry *ecryptfs_dentry, umode_t mode)
{
	int rc;
	struct dentry *lower_dentry;
	struct dentry *lower_dir_dentry;
	struct inode *inode;

	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
	lower_dir_dentry = lock_parent(lower_dentry);
	rc = vfs_create(d_inode(lower_dir_dentry), lower_dentry, mode, true);
	if (rc) {
		printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
		       "rc = [%d]\n", __func__, rc);
		inode = ERR_PTR(rc);
		goto out_lock;
	}
	inode = __ecryptfs_get_inode(d_inode(lower_dentry),
				     directory_inode->i_sb);
	if (IS_ERR(inode)) {
		vfs_unlink(d_inode(lower_dir_dentry), lower_dentry, NULL);
		goto out_lock;
	}
	fsstack_copy_attr_times(directory_inode, d_inode(lower_dir_dentry));
	fsstack_copy_inode_size(directory_inode, d_inode(lower_dir_dentry));
out_lock:
	unlock_dir(lower_dir_dentry);
	return inode;
}

这里跟我猜测的一样,利用vfs_create触发了底层文件系统节点构造方法。
可以看到直接利用 d_instantiate_new(ecryptfs_dentry, ecryptfs_inode); 把底层文件系统的几点元数据关联到了ecryptfs文件系统。表现就是,挂载点可以看到被挂在点的全部数据。

static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
				      struct dentry *ecryptfs_dentry,
				      unsigned int flags)
{
	char *encrypted_and_encoded_name = NULL;
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
	struct dentry *lower_dir_dentry, *lower_dentry;
	const char *name = ecryptfs_dentry->d_name.name;
	size_t len = ecryptfs_dentry->d_name.len;
	struct dentry *res;
	int rc = 0;

	lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);

	mount_crypt_stat = &ecryptfs_superblock_to_private(
				ecryptfs_dentry->d_sb)->mount_crypt_stat;
	if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
		rc = ecryptfs_encrypt_and_encode_filename(
			&encrypted_and_encoded_name, &len,
			mount_crypt_stat, name, len);
		if (rc) {
			printk(KERN_ERR "%s: Error attempting to encrypt and encode "
			       "filename; rc = [%d]\n", __func__, rc);
			return ERR_PTR(rc);
		}
		name = encrypted_and_encoded_name;
	}

	lower_dentry = lookup_one_len_unlocked(name, lower_dir_dentry, len);
	if (IS_ERR(lower_dentry)) {
		ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
				"[%ld] on lower_dentry = [%s]\n", __func__,
				PTR_ERR(lower_dentry),
				name);
		res = ERR_CAST(lower_dentry);
	} else {
		res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry);
	}
	kfree(encrypted_and_encoded_name);
	return res;
}

页缓存操作

这里是加解密的核心,如何借助现有文件系统,实现加解密的逻辑都在这里,其实就是把原有文件系统的页加密。

static int ecryptfs_readpage(struct file *file, struct page *page)
{
	struct ecryptfs_crypt_stat *crypt_stat =
		&ecryptfs_inode_to_private(page->mapping->host)->crypt_stat;
	int rc = 0;

	if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
		rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
						      PAGE_SIZE,
						      page->mapping->host);
	} else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
				     pgoff_t page_index,
				     size_t offset_in_page, size_t size,
				     struct inode *ecryptfs_inode)
{
	char *virt;
	loff_t offset;
	int rc;

	offset = ((((loff_t)page_index) << PAGE_SHIFT) + offset_in_page);
	virt = kmap(page_for_ecryptfs);
	rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
	if (rc > 0)
		rc = 0;
	kunmap(page_for_ecryptfs);
	flush_dcache_page(page_for_ecryptfs);
	return rc;
}
int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
			struct inode *ecryptfs_inode)
{
	struct file *lower_file;
	lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
	if (!lower_file)
		return -EIO;
	return kernel_read(lower_file, data, size, &offset);
}

最终借助前期关联的源文件struct file,读取文件。

你可能感兴趣的:(linux)