Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44614711 authored by Michael Halcrow's avatar Michael Halcrow Committed by Theodore Ts'o
Browse files

ext4 crypto: enable filename encryption

parent 1f3862b5
Loading
Loading
Loading
Loading
+49 −15
Original line number Diff line number Diff line
@@ -108,7 +108,10 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
	int err;
	struct inode *inode = file_inode(file);
	struct super_block *sb = inode->i_sb;
	struct buffer_head *bh = NULL;
	int dir_has_error = 0;
	struct ext4_fname_crypto_ctx *enc_ctx = NULL;
	struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};

	if (is_dx_dir(inode)) {
		err = ext4_dx_readdir(file, ctx);
@@ -125,17 +128,28 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)

	if (ext4_has_inline_data(inode)) {
		int has_inline_data = 1;
		int ret = ext4_read_inline_dir(file, ctx,
		err = ext4_read_inline_dir(file, ctx,
					   &has_inline_data);
		if (has_inline_data)
			return ret;
			return err;
	}

	enc_ctx = ext4_get_fname_crypto_ctx(inode, EXT4_NAME_LEN);
	if (IS_ERR(enc_ctx))
		return PTR_ERR(enc_ctx);
	if (enc_ctx) {
		err = ext4_fname_crypto_alloc_buffer(enc_ctx, EXT4_NAME_LEN,
						     &fname_crypto_str);
		if (err < 0) {
			ext4_put_fname_crypto_ctx(&enc_ctx);
			return err;
		}
	}

	offset = ctx->pos & (sb->s_blocksize - 1);

	while (ctx->pos < inode->i_size) {
		struct ext4_map_blocks map;
		struct buffer_head *bh = NULL;

		map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
		map.m_len = 1;
@@ -178,6 +192,7 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
					(unsigned long long)ctx->pos);
			ctx->pos += sb->s_blocksize - offset;
			brelse(bh);
			bh = NULL;
			continue;
		}
		set_buffer_verified(bh);
@@ -224,25 +239,44 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
			offset += ext4_rec_len_from_disk(de->rec_len,
					sb->s_blocksize);
			if (le32_to_cpu(de->inode)) {
				if (enc_ctx == NULL) {
					/* Directory is not encrypted */
					if (!dir_emit(ctx, de->name,
					    de->name_len,
					    le32_to_cpu(de->inode),
						get_dtype(sb, de->file_type))) {
					brelse(bh);
					return 0;
					    get_dtype(sb, de->file_type)))
						goto done;
				} else {
					/* Directory is encrypted */
					err = ext4_fname_disk_to_usr(enc_ctx,
							de, &fname_crypto_str);
					if (err < 0)
						goto errout;
					if (!dir_emit(ctx,
					    fname_crypto_str.name, err,
					    le32_to_cpu(de->inode),
					    get_dtype(sb, de->file_type)))
						goto done;
				}
			}
			ctx->pos += ext4_rec_len_from_disk(de->rec_len,
						sb->s_blocksize);
		}
		offset = 0;
		if ((ctx->pos < inode->i_size) && !dir_relax(inode))
			goto done;
		brelse(bh);
		if (ctx->pos < inode->i_size) {
			if (!dir_relax(inode))
				return 0;
		}
		bh = NULL;
		offset = 0;
	}
	return 0;
done:
	err = 0;
errout:
#ifdef CONFIG_EXT4_FS_ENCRYPTION
	ext4_put_fname_crypto_ctx(&enc_ctx);
	ext4_fname_crypto_free_buffer(&fname_crypto_str);
#endif
	brelse(bh);
	return err;
}

static inline int is_32bit_api(void)
+19 −2
Original line number Diff line number Diff line
@@ -1033,11 +1033,28 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
	ext4_set_inode_state(inode, EXT4_STATE_NEW);

	ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;

#ifdef CONFIG_EXT4_FS_ENCRYPTION
	if ((sbi->s_file_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID) &&
	    (sbi->s_dir_encryption_mode == EXT4_ENCRYPTION_MODE_INVALID)) {
		ei->i_inline_off = 0;
		if (EXT4_HAS_INCOMPAT_FEATURE(sb,
			EXT4_FEATURE_INCOMPAT_INLINE_DATA))
			ext4_set_inode_state(inode,
			EXT4_STATE_MAY_INLINE_DATA);
	} else {
		/* Inline data and encryption are incompatible
		 * We turn off inline data since encryption is enabled */
		ei->i_inline_off = 1;
		if (EXT4_HAS_INCOMPAT_FEATURE(sb,
			EXT4_FEATURE_INCOMPAT_INLINE_DATA))
			ext4_clear_inode_state(inode,
			EXT4_STATE_MAY_INLINE_DATA);
	}
#else
	ei->i_inline_off = 0;
	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_INLINE_DATA))
		ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);

#endif
	ret = inode;
	err = dquot_alloc_inode(inode);
	if (err)