mirror of
https://github.com/commaai/agnos-kernel-sdm845.git
synced 2026-06-08 11:24:51 +08:00
Enable hardware based FBE on f2fs and adapt ext4 fs
Hardware File Based Encryption (FBE) uses crypto engine to encrypt the user data with unique key for each file. File name and data both are encrypted with this feature. 1. security/pfk: changes to support per file encryption for f2fs using hardware crypto engine. 2. fs/ext4: adapted crypto APIs for generic crypto layer. 3. fs/f2fs: support hardware crypto engine based per file encryption. 4. fs/crypto: export APIs to support hardware crypto engine based per file encryption. Other changes made to provide support framework for per file encryption. Change-Id: I7981fa7f8f0c4bc058b80b7b8e342cfd81697c74 Signed-off-by: Neeraj Soni <neersoni@codeaurora.org>
This commit is contained in:
committed by
Veerabhadrarao Badiganti
parent
7bcb1bb423
commit
36c6512ecd
10
block/bio.c
10
block/bio.c
@@ -565,6 +565,15 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio)
|
||||
}
|
||||
EXPORT_SYMBOL(bio_phys_segments);
|
||||
|
||||
static inline void bio_clone_crypt_key(struct bio *dst, const struct bio *src)
|
||||
{
|
||||
#ifdef CONFIG_PFK
|
||||
dst->bi_crypt_key = src->bi_crypt_key;
|
||||
dst->bi_iter.bi_dun = src->bi_iter.bi_dun;
|
||||
#endif
|
||||
dst->bi_dio_inode = src->bi_dio_inode;
|
||||
}
|
||||
|
||||
/**
|
||||
* __bio_clone_fast - clone a bio that shares the original bio's biovec
|
||||
* @bio: destination bio
|
||||
@@ -590,6 +599,7 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
|
||||
bio->bi_iter = bio_src->bi_iter;
|
||||
bio->bi_io_vec = bio_src->bi_io_vec;
|
||||
bio->bi_dio_inode = bio_src->bi_dio_inode;
|
||||
bio_clone_crypt_key(bio, bio_src);
|
||||
bio_clone_blkcg_association(bio, bio_src);
|
||||
}
|
||||
EXPORT_SYMBOL(__bio_clone_fast);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/pfk.h>
|
||||
#include <trace/events/block.h>
|
||||
|
||||
#include <linux/pfk.h>
|
||||
#include "blk.h"
|
||||
|
||||
static struct bio *blk_bio_discard_split(struct request_queue *q,
|
||||
|
||||
@@ -425,7 +425,10 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
|
||||
/*
|
||||
* First try one-hit cache.
|
||||
*/
|
||||
if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) {
|
||||
if (q->last_merge) {
|
||||
if (!elv_bio_merge_ok(q->last_merge, bio))
|
||||
return ELEVATOR_NO_MERGE;
|
||||
|
||||
ret = blk_try_merge(q->last_merge, bio);
|
||||
if (ret != ELEVATOR_NO_MERGE) {
|
||||
*req = q->last_merge;
|
||||
|
||||
@@ -2044,6 +2044,8 @@ static void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q)
|
||||
if (!shost->use_clustering)
|
||||
q->limits.cluster = 0;
|
||||
|
||||
if (shost->inlinecrypt_support)
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_INLINECRYPT, q);
|
||||
/*
|
||||
* Set a reasonable default alignment: The larger of 32-byte (dword),
|
||||
* which is a common minimum for HBAs, and the minimum DMA alignment,
|
||||
|
||||
@@ -897,11 +897,18 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba,
|
||||
req = lrbp->cmd->request;
|
||||
else
|
||||
return 0;
|
||||
|
||||
/* Use request LBA as the DUN value */
|
||||
if (req->bio)
|
||||
*dun = (req->bio->bi_iter.bi_sector) >>
|
||||
UFS_QCOM_ICE_TR_DATA_UNIT_4_KB;
|
||||
/*
|
||||
* Right now ICE do not support variable dun but can be
|
||||
* taken as future enhancement
|
||||
* if (bio_dun(req->bio)) {
|
||||
* dun @bio can be split, so we have to adjust offset
|
||||
* *dun = bio_dun(req->bio);
|
||||
* } else
|
||||
*/
|
||||
if (req->bio) {
|
||||
*dun = req->bio->bi_iter.bi_sector;
|
||||
*dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB;
|
||||
}
|
||||
|
||||
ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable);
|
||||
|
||||
@@ -2133,6 +2140,8 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||
dev_err(dev, "%s: ufs_qcom_ice_get_dev failed %d\n",
|
||||
__func__, err);
|
||||
goto out_host_free;
|
||||
} else {
|
||||
hba->host->inlinecrypt_support = 1;
|
||||
}
|
||||
|
||||
host->generic_phy = devm_phy_get(dev, "ufsphy");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o
|
||||
|
||||
ccflags-y += -Ifs/ext4
|
||||
fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o
|
||||
ccflags-y += -Ifs/f2fs
|
||||
|
||||
fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o fscrypt_ice.o
|
||||
fscrypto-$(CONFIG_BLOCK) += bio.o
|
||||
|
||||
@@ -33,7 +33,7 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
|
||||
bio_for_each_segment_all(bv, bio, i) {
|
||||
struct page *page = bv->bv_page;
|
||||
|
||||
if (fs_is_ice_enabled()) {
|
||||
if (fscrypt_using_hardware_encryption(page->mapping->host)) {
|
||||
SetPageUptodate(page);
|
||||
} else {
|
||||
int ret = fscrypt_decrypt_page(page->mapping->host,
|
||||
|
||||
146
fs/crypto/fscrypt_ice.c
Normal file
146
fs/crypto/fscrypt_ice.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "fscrypt_ice.h"
|
||||
|
||||
int fscrypt_using_hardware_encryption(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
|
||||
return S_ISREG(inode->i_mode) && ci &&
|
||||
ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_using_hardware_encryption);
|
||||
|
||||
/*
|
||||
* Retrieves encryption key from the inode
|
||||
*/
|
||||
char *fscrypt_get_ice_encryption_key(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = NULL;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
return &(ci->ci_raw_key[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves encryption salt from the inode
|
||||
*/
|
||||
char *fscrypt_get_ice_encryption_salt(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = NULL;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
return &(ci->ci_raw_key[fscrypt_get_ice_encryption_key_size(inode)]);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns true if the cipher mode in inode is AES XTS
|
||||
*/
|
||||
int fscrypt_is_aes_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
|
||||
if (!ci)
|
||||
return 0;
|
||||
|
||||
return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns true if encryption info in both inodes is equal
|
||||
*/
|
||||
bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1,
|
||||
const struct inode *inode2)
|
||||
{
|
||||
char *key1 = NULL;
|
||||
char *key2 = NULL;
|
||||
char *salt1 = NULL;
|
||||
char *salt2 = NULL;
|
||||
|
||||
if (!inode1 || !inode2)
|
||||
return false;
|
||||
|
||||
if (inode1 == inode2)
|
||||
return true;
|
||||
|
||||
/* both do not belong to ice, so we don't care, they are equal
|
||||
*for us
|
||||
*/
|
||||
if (!fscrypt_should_be_processed_by_ice(inode1) &&
|
||||
!fscrypt_should_be_processed_by_ice(inode2))
|
||||
return true;
|
||||
|
||||
/* one belongs to ice, the other does not -> not equal */
|
||||
if (fscrypt_should_be_processed_by_ice(inode1) ^
|
||||
fscrypt_should_be_processed_by_ice(inode2))
|
||||
return false;
|
||||
|
||||
key1 = fscrypt_get_ice_encryption_key(inode1);
|
||||
key2 = fscrypt_get_ice_encryption_key(inode2);
|
||||
salt1 = fscrypt_get_ice_encryption_salt(inode1);
|
||||
salt2 = fscrypt_get_ice_encryption_salt(inode2);
|
||||
|
||||
/* key and salt should not be null by this point */
|
||||
if (!key1 || !key2 || !salt1 || !salt2 ||
|
||||
(fscrypt_get_ice_encryption_key_size(inode1) !=
|
||||
fscrypt_get_ice_encryption_key_size(inode2)) ||
|
||||
(fscrypt_get_ice_encryption_salt_size(inode1) !=
|
||||
fscrypt_get_ice_encryption_salt_size(inode2)))
|
||||
return false;
|
||||
|
||||
if ((memcmp(key1, key2,
|
||||
fscrypt_get_ice_encryption_key_size(inode1)) == 0) &&
|
||||
(memcmp(salt1, salt2,
|
||||
fscrypt_get_ice_encryption_salt_size(inode1)) == 0))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void fscrypt_set_ice_dun(const struct inode *inode, struct bio *bio, u64 dun)
|
||||
{
|
||||
if (fscrypt_should_be_processed_by_ice(inode))
|
||||
bio->bi_iter.bi_dun = dun;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_set_ice_dun);
|
||||
|
||||
/*
|
||||
* This function will be used for filesystem when deciding to merge bios.
|
||||
* Basic assumption is, if inline_encryption is set, single bio has to
|
||||
* guarantee consecutive LBAs as well as ino|pg->index.
|
||||
*/
|
||||
bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted)
|
||||
{
|
||||
if (!bio)
|
||||
return true;
|
||||
|
||||
/* if both of them are not encrypted, no further check is needed */
|
||||
if (!bio_dun(bio) && !bio_encrypted)
|
||||
return true;
|
||||
|
||||
/* ICE allows only consecutive iv_key stream. */
|
||||
return bio_end_dun(bio) == dun;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_mergeable_bio);
|
||||
106
fs/crypto/fscrypt_ice.h
Normal file
106
fs/crypto/fscrypt_ice.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FSCRYPT_ICE_H
|
||||
#define _FSCRYPT_ICE_H
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode)
|
||||
{
|
||||
if (!inode->i_sb->s_cop)
|
||||
return 0;
|
||||
if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode))
|
||||
return 0;
|
||||
|
||||
return fscrypt_using_hardware_encryption(inode);
|
||||
}
|
||||
|
||||
static inline int fscrypt_is_ice_capable(const struct super_block *sb)
|
||||
{
|
||||
return blk_queue_inlinecrypt(bdev_get_queue(sb->s_bdev));
|
||||
}
|
||||
|
||||
int fscrypt_is_aes_xts_cipher(const struct inode *inode);
|
||||
|
||||
char *fscrypt_get_ice_encryption_key(const struct inode *inode);
|
||||
char *fscrypt_get_ice_encryption_salt(const struct inode *inode);
|
||||
|
||||
bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1,
|
||||
const struct inode *inode2);
|
||||
|
||||
static inline size_t fscrypt_get_ice_encryption_key_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return FS_AES_256_XTS_KEY_SIZE / 2;
|
||||
}
|
||||
|
||||
static inline size_t fscrypt_get_ice_encryption_salt_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return FS_AES_256_XTS_KEY_SIZE / 2;
|
||||
}
|
||||
#else
|
||||
static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_is_ice_capable(const struct super_block *sb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *fscrypt_get_ice_encryption_key(const struct inode *inode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline char *fscrypt_get_ice_encryption_salt(const struct inode *inode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline size_t fscrypt_get_ice_encryption_key_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t fscrypt_get_ice_encryption_salt_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_is_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_ice_encryption_info_equal(
|
||||
const struct inode *inode1,
|
||||
const struct inode *inode2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_is_aes_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _FSCRYPT_ICE_H */
|
||||
@@ -11,9 +11,12 @@
|
||||
#ifndef _FSCRYPT_PRIVATE_H
|
||||
#define _FSCRYPT_PRIVATE_H
|
||||
|
||||
#ifndef __FS_HAS_ENCRYPTION
|
||||
#define __FS_HAS_ENCRYPTION 1
|
||||
#endif
|
||||
#include <linux/fscrypt.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/pfk.h>
|
||||
|
||||
/* Encryption parameters */
|
||||
#define FS_IV_SIZE 16
|
||||
@@ -58,11 +61,18 @@ struct fscrypt_symlink_data {
|
||||
char encrypted_path[1];
|
||||
} __packed;
|
||||
|
||||
enum ci_mode_info {
|
||||
CI_NONE_MODE = 0,
|
||||
CI_DATA_MODE,
|
||||
CI_FNAME_MODE,
|
||||
};
|
||||
|
||||
/*
|
||||
* A pointer to this structure is stored in the file system's in-core
|
||||
* representation of an inode.
|
||||
*/
|
||||
struct fscrypt_info {
|
||||
u8 ci_mode;
|
||||
u8 ci_data_mode;
|
||||
u8 ci_filename_mode;
|
||||
u8 ci_flags;
|
||||
@@ -97,6 +107,12 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_private_data_mode(struct fscrypt_info *ci)
|
||||
{
|
||||
return ci->ci_mode == CI_DATA_MODE &&
|
||||
ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE;
|
||||
}
|
||||
|
||||
/* crypto.c */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern int fscrypt_initialize(unsigned int cop_flags);
|
||||
@@ -116,10 +132,6 @@ extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
|
||||
u32 orig_len, u32 max_len,
|
||||
u32 *encrypted_len_ret);
|
||||
|
||||
static inline int fs_is_ice_enabled(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
/* keyinfo.c */
|
||||
extern void __exit fscrypt_essiv_cleanup(void);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <crypto/sha.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include "fscrypt_private.h"
|
||||
#include "fscrypt_ice.h"
|
||||
|
||||
static struct crypto_shash *essiv_hash_tfm;
|
||||
|
||||
@@ -67,7 +68,7 @@ out:
|
||||
}
|
||||
|
||||
static int validate_user_key(struct fscrypt_info *crypt_info,
|
||||
struct fscrypt_context *ctx, u8 *raw_key,
|
||||
struct fscrypt_context *ctx,
|
||||
const char *prefix, int min_keysize)
|
||||
{
|
||||
char *description;
|
||||
@@ -115,7 +116,24 @@ static int validate_user_key(struct fscrypt_info *crypt_info,
|
||||
res = -ENOKEY;
|
||||
goto out;
|
||||
}
|
||||
res = derive_key_aes(ctx->nonce, master_key, raw_key);
|
||||
res = derive_key_aes(ctx->nonce, master_key, crypt_info->ci_raw_key);
|
||||
/* If we don't need to derive, we still want to do everything
|
||||
* up until now to validate the key. It's cleaner to fail now
|
||||
* than to fail in block I/O.
|
||||
if (!is_private_data_mode(crypt_info)) {
|
||||
res = derive_key_aes(ctx->nonce, master_key,
|
||||
crypt_info->ci_raw_key);
|
||||
} else {
|
||||
* Inline encryption: no key derivation required because IVs are
|
||||
* assigned based on iv_sector.
|
||||
|
||||
BUILD_BUG_ON(sizeof(crypt_info->ci_raw_key) !=
|
||||
sizeof(master_key->raw));
|
||||
memcpy(crypt_info->ci_raw_key,
|
||||
master_key->raw, sizeof(crypt_info->ci_raw_key));
|
||||
res = 0;
|
||||
}
|
||||
*/
|
||||
out:
|
||||
up_read(&keyring_key->sem);
|
||||
key_put(keyring_key);
|
||||
@@ -151,8 +169,10 @@ static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
|
||||
}
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
ci->ci_mode = CI_DATA_MODE;
|
||||
mode = ci->ci_data_mode;
|
||||
} else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
|
||||
ci->ci_mode = CI_FNAME_MODE;
|
||||
mode = ci->ci_filename_mode;
|
||||
*fname = 1;
|
||||
} else {
|
||||
@@ -173,7 +193,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
|
||||
|
||||
crypto_free_skcipher(ci->ci_ctfm);
|
||||
crypto_free_cipher(ci->ci_essiv_tfm);
|
||||
memzero_explicit(ci->ci_raw_key, sizeof(ci->ci_raw_key));
|
||||
memset(ci, 0, sizeof(*ci)); /* sanitizes ->ci_raw_key */
|
||||
kmem_cache_free(fscrypt_info_cachep, ci);
|
||||
}
|
||||
|
||||
@@ -243,21 +263,12 @@ void __exit fscrypt_essiv_cleanup(void)
|
||||
crypto_free_shash(essiv_hash_tfm);
|
||||
}
|
||||
|
||||
static int fs_data_encryption_mode(void)
|
||||
static int fscrypt_data_encryption_mode(struct inode *inode)
|
||||
{
|
||||
return fs_is_ice_enabled() ? FS_ENCRYPTION_MODE_PRIVATE :
|
||||
FS_ENCRYPTION_MODE_AES_256_XTS;
|
||||
return fscrypt_should_be_processed_by_ice(inode) ?
|
||||
FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS;
|
||||
}
|
||||
|
||||
int fs_using_hardware_encryption(struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
|
||||
return S_ISREG(inode->i_mode) && ci &&
|
||||
ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE;
|
||||
}
|
||||
EXPORT_SYMBOL(fs_using_hardware_encryption);
|
||||
|
||||
int fscrypt_get_encryption_info(struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *crypt_info;
|
||||
@@ -283,7 +294,8 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
||||
/* Fake up a context for an unencrypted directory */
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
|
||||
ctx.contents_encryption_mode = fs_data_encryption_mode();
|
||||
ctx.contents_encryption_mode =
|
||||
fscrypt_data_encryption_mode(inode);
|
||||
ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
|
||||
memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
|
||||
} else if (res != sizeof(ctx)) {
|
||||
@@ -319,55 +331,65 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
||||
*/
|
||||
res = -ENOMEM;
|
||||
|
||||
res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key,
|
||||
FS_KEY_DESC_PREFIX, keysize);
|
||||
res = validate_user_key(crypt_info, &ctx, FS_KEY_DESC_PREFIX,
|
||||
keysize);
|
||||
if (res && inode->i_sb->s_cop->key_prefix) {
|
||||
int res2 = validate_user_key(crypt_info, &ctx,
|
||||
crypt_info->ci_raw_key,
|
||||
inode->i_sb->s_cop->key_prefix, keysize);
|
||||
inode->i_sb->s_cop->key_prefix,
|
||||
keysize);
|
||||
if (res2) {
|
||||
if (res2 == -ENOKEY)
|
||||
res = -ENOKEY;
|
||||
goto out;
|
||||
}
|
||||
res = 0;
|
||||
} else if (res) {
|
||||
goto out;
|
||||
}
|
||||
if (crypt_info->ci_data_mode != FS_ENCRYPTION_MODE_PRIVATE || fname) {
|
||||
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
|
||||
if (!ctfm || IS_ERR(ctfm)) {
|
||||
res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
|
||||
pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n",
|
||||
|
||||
if (is_private_data_mode(crypt_info)) {
|
||||
if (!fscrypt_is_ice_capable(inode->i_sb)) {
|
||||
pr_warn("%s: ICE support not available\n",
|
||||
__func__);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* Let's encrypt/decrypt by ICE */
|
||||
goto do_ice;
|
||||
}
|
||||
|
||||
|
||||
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
|
||||
if (!ctfm || IS_ERR(ctfm)) {
|
||||
res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
|
||||
pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n",
|
||||
__func__, res, inode->i_ino);
|
||||
goto out;
|
||||
}
|
||||
crypt_info->ci_ctfm = ctfm;
|
||||
crypto_skcipher_clear_flags(ctfm, ~0);
|
||||
crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
|
||||
/*
|
||||
* if the provided key is longer than keysize, we use the first
|
||||
* keysize bytes of the derived key only
|
||||
*/
|
||||
res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, keysize);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
if (S_ISREG(inode->i_mode) &&
|
||||
crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) {
|
||||
res = init_essiv_generator(crypt_info, crypt_info->ci_raw_key,
|
||||
keysize);
|
||||
if (res) {
|
||||
pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n",
|
||||
__func__, res, inode->i_ino);
|
||||
goto out;
|
||||
}
|
||||
crypt_info->ci_ctfm = ctfm;
|
||||
crypto_skcipher_clear_flags(ctfm, ~0);
|
||||
crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
|
||||
/*
|
||||
* if the provided key is longer than keysize, we use the first
|
||||
* keysize bytes of the derived key only
|
||||
*/
|
||||
res = crypto_skcipher_setkey(ctfm,
|
||||
crypt_info->ci_raw_key, keysize);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
if (S_ISREG(inode->i_mode) && crypt_info->ci_data_mode ==
|
||||
FS_ENCRYPTION_MODE_AES_128_CBC) {
|
||||
res = init_essiv_generator(crypt_info,
|
||||
crypt_info->ci_raw_key, keysize);
|
||||
if (res) {
|
||||
pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n",
|
||||
__func__, res, inode->i_ino);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else if (!fs_is_ice_enabled()) {
|
||||
pr_warn("%s: ICE support not available\n", __func__);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
memzero_explicit(crypt_info->ci_raw_key,
|
||||
sizeof(crypt_info->ci_raw_key));
|
||||
do_ice:
|
||||
if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
|
||||
crypt_info = NULL;
|
||||
out:
|
||||
@@ -384,51 +406,3 @@ void fscrypt_put_encryption_info(struct inode *inode)
|
||||
inode->i_crypt_info = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_put_encryption_info);
|
||||
|
||||
char *fscrypt_get_ice_encryption_key(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
return &(ci->ci_raw_key[0]);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_get_ice_encryption_key);
|
||||
|
||||
/*
|
||||
* Retrieves encryption salt from the inode
|
||||
*/
|
||||
char *fscrypt_get_ice_encryption_salt(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
return &(ci->ci_raw_key[FS_AES_256_XTS_KEY_SIZE / 2]);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_get_ice_encryption_salt);
|
||||
|
||||
/*
|
||||
* returns true if the cipher mode in inode is AES XTS
|
||||
*/
|
||||
int fscrypt_is_aes_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci;
|
||||
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return 0;
|
||||
|
||||
return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_is_aes_xts_cipher);
|
||||
|
||||
@@ -13,4 +13,3 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
|
||||
|
||||
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
|
||||
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
|
||||
ext4-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.o
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ext4_ice.h"
|
||||
#include <linux/fscrypt.h>
|
||||
|
||||
/*
|
||||
* Retrieves encryption key from the inode
|
||||
*/
|
||||
char *ext4_get_ice_encryption_key(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* struct fscrypt_info *ci;
|
||||
* if (!inode)
|
||||
* return NULL;
|
||||
* ci = inode->i_crypt_info;
|
||||
* if (!ci)
|
||||
* return NULL;
|
||||
* return &(ci->ci_raw_key[0]);
|
||||
*/
|
||||
return fscrypt_get_ice_encryption_key(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves encryption salt from the inode
|
||||
*/
|
||||
char *ext4_get_ice_encryption_salt(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* struct fscrypt_info *ci;
|
||||
* if (!inode)
|
||||
* return NULL;
|
||||
* ci = inode->i_crypt_info;
|
||||
* if (!ci)
|
||||
* return NULL;
|
||||
* return &(ci->ci_raw_key[ext4_get_ice_encryption_key_size(inode)]);
|
||||
*/
|
||||
return fscrypt_get_ice_encryption_salt(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns true if the cipher mode in inode is AES XTS
|
||||
*/
|
||||
int ext4_is_aes_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
/*
|
||||
* struct fscrypt_info *ci;
|
||||
* ci = inode->i_crypt_info;
|
||||
* if (!ci)
|
||||
* return 0;
|
||||
* return (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE);
|
||||
*/
|
||||
return fscrypt_is_aes_xts_cipher(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns true if encryption info in both inodes is equal
|
||||
*/
|
||||
int ext4_is_ice_encryption_info_equal(const struct inode *inode1,
|
||||
const struct inode *inode2)
|
||||
{
|
||||
char *key1 = NULL;
|
||||
char *key2 = NULL;
|
||||
char *salt1 = NULL;
|
||||
char *salt2 = NULL;
|
||||
|
||||
if (!inode1 || !inode2)
|
||||
return 0;
|
||||
|
||||
if (inode1 == inode2)
|
||||
return 1;
|
||||
|
||||
/* both do not belong to ice, so we don't care, they are equal for us */
|
||||
if (!ext4_should_be_processed_by_ice(inode1) &&
|
||||
!ext4_should_be_processed_by_ice(inode2))
|
||||
return 1;
|
||||
|
||||
/* one belongs to ice, the other does not -> not equal */
|
||||
if (ext4_should_be_processed_by_ice(inode1) ^
|
||||
ext4_should_be_processed_by_ice(inode2))
|
||||
return 0;
|
||||
|
||||
key1 = ext4_get_ice_encryption_key(inode1);
|
||||
key2 = ext4_get_ice_encryption_key(inode2);
|
||||
salt1 = ext4_get_ice_encryption_salt(inode1);
|
||||
salt2 = ext4_get_ice_encryption_salt(inode2);
|
||||
|
||||
/* key and salt should not be null by this point */
|
||||
if (!key1 || !key2 || !salt1 || !salt2 ||
|
||||
(ext4_get_ice_encryption_key_size(inode1) !=
|
||||
ext4_get_ice_encryption_key_size(inode2)) ||
|
||||
(ext4_get_ice_encryption_salt_size(inode1) !=
|
||||
ext4_get_ice_encryption_salt_size(inode2)))
|
||||
return 0;
|
||||
|
||||
return ((memcmp(key1, key2,
|
||||
ext4_get_ice_encryption_key_size(inode1)) == 0) &&
|
||||
(memcmp(salt1, salt2,
|
||||
ext4_get_ice_encryption_salt_size(inode1)) == 0));
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _EXT4_ICE_H
|
||||
#define _EXT4_ICE_H
|
||||
|
||||
#include "ext4.h"
|
||||
#define EXT4_256_XTS_KEY_SIZE 64
|
||||
|
||||
#ifdef CONFIG_EXT4_FS_ICE_ENCRYPTION
|
||||
static inline int ext4_should_be_processed_by_ice(const struct inode *inode)
|
||||
{
|
||||
if (!ext4_encrypted_inode((struct inode *)inode))
|
||||
return 0;
|
||||
|
||||
return fs_using_hardware_encryption((struct inode *)inode);
|
||||
}
|
||||
|
||||
static inline int ext4_is_ice_enabled(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ext4_is_aes_xts_cipher(const struct inode *inode);
|
||||
|
||||
char *ext4_get_ice_encryption_key(const struct inode *inode);
|
||||
char *ext4_get_ice_encryption_salt(const struct inode *inode);
|
||||
|
||||
int ext4_is_ice_encryption_info_equal(const struct inode *inode1,
|
||||
const struct inode *inode2);
|
||||
|
||||
static inline size_t ext4_get_ice_encryption_key_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return EXT4_256_XTS_KEY_SIZE / 2;
|
||||
}
|
||||
|
||||
static inline size_t ext4_get_ice_encryption_salt_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return EXT4_256_XTS_KEY_SIZE / 2;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int ext4_should_be_processed_by_ice(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int ext4_is_ice_enabled(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *ext4_get_ice_encryption_key(const struct inode *inode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline char *ext4_get_ice_encryption_salt(const struct inode *inode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline size_t ext4_get_ice_encryption_key_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t ext4_get_ice_encryption_salt_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_is_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_is_ice_encryption_info_equal(
|
||||
const struct inode *inode1,
|
||||
const struct inode *inode2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ext4_is_aes_xts_cipher(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fs_using_hardware_encryption(struct inode *inode)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _EXT4_ICE_H */
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "truncate.h"
|
||||
#include "ext4_ice.h"
|
||||
//#include "ext4_ice.h"
|
||||
|
||||
#include <trace/events/ext4.h>
|
||||
#include <trace/events/android_fs.h>
|
||||
@@ -1154,7 +1154,7 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len,
|
||||
*wait_bh++ = bh;
|
||||
decrypt = ext4_encrypted_inode(inode) &&
|
||||
S_ISREG(inode->i_mode) &&
|
||||
!ext4_is_ice_enabled();
|
||||
!fscrypt_using_hardware_encryption(inode);
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -3511,9 +3511,9 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter)
|
||||
get_block_func = ext4_dio_get_block_unwritten_async;
|
||||
dio_flags = DIO_LOCKING;
|
||||
}
|
||||
#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \
|
||||
!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION)
|
||||
BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
|
||||
#if defined(CONFIG_EXT4_FS_ENCRYPTION)
|
||||
WARN_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)
|
||||
&& !fscrypt_using_hardware_encryption(inode));
|
||||
#endif
|
||||
if (IS_DAX(inode)) {
|
||||
ret = dax_do_io(iocb, inode, iter, get_block_func,
|
||||
@@ -3634,9 +3634,9 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
ssize_t ret;
|
||||
int rw = iov_iter_rw(iter);
|
||||
|
||||
#if defined(CONFIG_EXT4_FS_ENCRYPTION) && \
|
||||
!defined(CONFIG_EXT4_FS_ICE_ENCRYPTION)
|
||||
if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
|
||||
#if defined(CONFIG_EXT4_FS_ENCRYPTION)
|
||||
if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)
|
||||
&& !fscrypt_using_hardware_encryption(inode))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -3833,7 +3833,7 @@ static int __ext4_block_zero_page_range(handle_t *handle,
|
||||
goto unlock;
|
||||
if (S_ISREG(inode->i_mode) &&
|
||||
ext4_encrypted_inode(inode) &&
|
||||
!fs_using_hardware_encryption(inode)) {
|
||||
!fscrypt_using_hardware_encryption(inode)) {
|
||||
/* We expect the key to be set. */
|
||||
BUG_ON(!fscrypt_has_encryption_key(inode));
|
||||
BUG_ON(blocksize != PAGE_SIZE);
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "ext4_jbd2.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "ext4_ice.h"
|
||||
//#include "ext4_ice.h"
|
||||
|
||||
static struct kmem_cache *io_end_cachep;
|
||||
|
||||
@@ -470,7 +470,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
|
||||
gfp_t gfp_flags = GFP_NOFS;
|
||||
|
||||
retry_encrypt:
|
||||
if (!fs_using_hardware_encryption(inode))
|
||||
if (!fscrypt_using_hardware_encryption(inode))
|
||||
data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0,
|
||||
page->index, gfp_flags);
|
||||
if (IS_ERR(data_page)) {
|
||||
|
||||
@@ -1180,6 +1180,11 @@ static unsigned ext4_max_namelen(struct inode *inode)
|
||||
EXT4_NAME_LEN;
|
||||
}
|
||||
|
||||
static inline bool ext4_is_encrypted(struct inode *inode)
|
||||
{
|
||||
return ext4_encrypted_inode(inode);
|
||||
}
|
||||
|
||||
static const struct fscrypt_operations ext4_cryptops = {
|
||||
.key_prefix = "ext4:",
|
||||
.get_context = ext4_get_context,
|
||||
@@ -1187,6 +1192,7 @@ static const struct fscrypt_operations ext4_cryptops = {
|
||||
.dummy_context = ext4_dummy_context,
|
||||
.empty_dir = ext4_empty_dir,
|
||||
.max_namelen = ext4_max_namelen,
|
||||
.is_encrypted = ext4_is_encrypted,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -437,6 +437,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
|
||||
struct bio *bio;
|
||||
struct page *page = fio->encrypted_page ?
|
||||
fio->encrypted_page : fio->page;
|
||||
struct inode *inode = fio->page->mapping->host;
|
||||
|
||||
verify_block_addr(fio, fio->new_blkaddr);
|
||||
trace_f2fs_submit_page_bio(page, fio);
|
||||
@@ -446,6 +447,9 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
|
||||
bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
|
||||
1, is_read_io(fio->op), fio->type, fio->temp);
|
||||
|
||||
if (f2fs_may_encrypt_bio(inode, fio))
|
||||
fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, fio->page));
|
||||
|
||||
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
|
||||
bio_put(bio);
|
||||
return -EFAULT;
|
||||
@@ -465,6 +469,9 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
|
||||
enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
|
||||
struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
|
||||
struct page *bio_page;
|
||||
struct inode *inode;
|
||||
bool bio_encrypted;
|
||||
u64 dun;
|
||||
int err = 0;
|
||||
|
||||
f2fs_bug_on(sbi, is_read_io(fio->op));
|
||||
@@ -488,6 +495,9 @@ next:
|
||||
verify_block_addr(fio, fio->new_blkaddr);
|
||||
|
||||
bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
|
||||
inode = fio->page->mapping->host;
|
||||
dun = PG_DUN(inode, fio->page);
|
||||
bio_encrypted = f2fs_may_encrypt_bio(inode, fio);
|
||||
|
||||
/* set submitted = true as a return value */
|
||||
fio->submitted = true;
|
||||
@@ -498,6 +508,11 @@ next:
|
||||
(io->fio.op != fio->op || io->fio.op_flags != fio->op_flags) ||
|
||||
!__same_bdev(sbi, fio->new_blkaddr, io->bio)))
|
||||
__submit_merged_bio(io);
|
||||
|
||||
/* ICE support */
|
||||
if (!fscrypt_mergeable_bio(io->bio, dun, bio_encrypted))
|
||||
__submit_merged_bio(io);
|
||||
|
||||
alloc_new:
|
||||
if (io->bio == NULL) {
|
||||
if ((fio->type == DATA || fio->type == NODE) &&
|
||||
@@ -509,6 +524,9 @@ alloc_new:
|
||||
io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
|
||||
BIO_MAX_PAGES, false,
|
||||
fio->type, fio->temp);
|
||||
if (bio_encrypted)
|
||||
fscrypt_set_ice_dun(inode, io->bio, dun);
|
||||
|
||||
io->fio = *fio;
|
||||
}
|
||||
|
||||
@@ -575,6 +593,9 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
|
||||
if (IS_ERR(bio))
|
||||
return PTR_ERR(bio);
|
||||
|
||||
if (f2fs_may_encrypt_bio(inode, NULL))
|
||||
fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page));
|
||||
|
||||
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
|
||||
bio_put(bio);
|
||||
return -EFAULT;
|
||||
@@ -1434,6 +1455,8 @@ static int f2fs_mpage_readpages(struct address_space *mapping,
|
||||
sector_t last_block_in_file;
|
||||
sector_t block_nr;
|
||||
struct f2fs_map_blocks map;
|
||||
bool bio_encrypted;
|
||||
u64 dun;
|
||||
|
||||
map.m_pblk = 0;
|
||||
map.m_lblk = 0;
|
||||
@@ -1511,6 +1534,14 @@ submit_and_realloc:
|
||||
__submit_bio(F2FS_I_SB(inode), bio, DATA);
|
||||
bio = NULL;
|
||||
}
|
||||
|
||||
dun = PG_DUN(inode, page);
|
||||
bio_encrypted = f2fs_may_encrypt_bio(inode, NULL);
|
||||
if (!fscrypt_mergeable_bio(bio, dun, bio_encrypted)) {
|
||||
__submit_bio(F2FS_I_SB(inode), bio, DATA);
|
||||
bio = NULL;
|
||||
}
|
||||
|
||||
if (bio == NULL) {
|
||||
bio = f2fs_grab_read_bio(inode, block_nr, nr_pages);
|
||||
if (IS_ERR(bio)) {
|
||||
@@ -1518,7 +1549,8 @@ submit_and_realloc:
|
||||
goto set_error_page;
|
||||
}
|
||||
}
|
||||
|
||||
if (bio_encrypted)
|
||||
fscrypt_set_ice_dun(inode, bio, dun);
|
||||
if (bio_add_page(bio, page, blocksize, 0) < blocksize)
|
||||
goto submit_and_realloc;
|
||||
|
||||
@@ -1588,6 +1620,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
|
||||
f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr);
|
||||
|
||||
retry_encrypt:
|
||||
if (fscrypt_using_hardware_encryption(inode))
|
||||
return 0;
|
||||
|
||||
fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
|
||||
PAGE_SIZE, 0, fio->page->index, gfp_flags);
|
||||
if (!IS_ERR(fio->encrypted_page))
|
||||
|
||||
@@ -3321,9 +3321,20 @@ static inline bool f2fs_may_encrypt(struct inode *inode)
|
||||
|
||||
static inline bool f2fs_force_buffered_io(struct inode *inode, int rw)
|
||||
{
|
||||
return (f2fs_post_read_required(inode) ||
|
||||
return ((f2fs_post_read_required(inode) &&
|
||||
!fscrypt_using_hardware_encryption(inode)) ||
|
||||
(rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
|
||||
F2FS_I_SB(inode)->s_ndevs);
|
||||
}
|
||||
|
||||
static inline bool f2fs_may_encrypt_bio(struct inode *inode,
|
||||
struct f2fs_io_info *fio)
|
||||
{
|
||||
if (fio && (fio->type != DATA || fio->encrypted_page))
|
||||
return false;
|
||||
|
||||
return (f2fs_encrypted_file(inode) &&
|
||||
fscrypt_using_hardware_encryption(inode));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1936,6 +1936,11 @@ static unsigned f2fs_max_namelen(struct inode *inode)
|
||||
inode->i_sb->s_blocksize : F2FS_NAME_LEN;
|
||||
}
|
||||
|
||||
static inline bool f2fs_is_encrypted(struct inode *inode)
|
||||
{
|
||||
return f2fs_encrypted_file(inode);
|
||||
}
|
||||
|
||||
static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.key_prefix = "f2fs:",
|
||||
.get_context = f2fs_get_context,
|
||||
@@ -1943,6 +1948,7 @@ static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.dummy_context = f2fs_dummy_context,
|
||||
.empty_dir = f2fs_empty_dir,
|
||||
.max_namelen = f2fs_max_namelen,
|
||||
.is_encrypted = f2fs_is_encrypted,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len)
|
||||
#define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9)
|
||||
#define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio)))
|
||||
#define bio_dun(bio) ((bio)->bi_iter.bi_dun)
|
||||
#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */
|
||||
#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio))
|
||||
|
||||
/*
|
||||
* Check whether this bio carries any data or not. A NULL bio is allowed.
|
||||
@@ -169,6 +172,11 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter,
|
||||
{
|
||||
iter->bi_sector += bytes >> 9;
|
||||
|
||||
#ifdef CONFIG_PFK
|
||||
if (iter->bi_dun)
|
||||
iter->bi_dun += bytes >> 12;
|
||||
#endif
|
||||
|
||||
if (bio_no_advance_iter(bio))
|
||||
iter->bi_size -= bytes;
|
||||
else
|
||||
|
||||
@@ -66,6 +66,10 @@ struct bio {
|
||||
struct bio_integrity_payload *bi_integrity; /* data integrity */
|
||||
#endif
|
||||
};
|
||||
#ifdef CONFIG_PFK
|
||||
/* Encryption key to use (NULL if none) */
|
||||
const struct blk_encryption_key *bi_crypt_key;
|
||||
#endif
|
||||
|
||||
unsigned short bi_vcnt; /* how many bio_vec's */
|
||||
|
||||
|
||||
@@ -509,6 +509,7 @@ struct request_queue {
|
||||
#define QUEUE_FLAG_FLUSH_NQ 25 /* flush not queueuable */
|
||||
#define QUEUE_FLAG_DAX 26 /* device supports DAX */
|
||||
#define QUEUE_FLAG_FAST 27 /* fast block device (e.g. ram based) */
|
||||
#define QUEUE_FLAG_INLINECRYPT 28 /* inline encryption support */
|
||||
|
||||
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
|
||||
(1 << QUEUE_FLAG_STACKABLE) | \
|
||||
@@ -600,6 +601,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
|
||||
(test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags))
|
||||
#define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
|
||||
#define blk_queue_fast(q) test_bit(QUEUE_FLAG_FAST, &(q)->queue_flags)
|
||||
#define blk_queue_inlinecrypt(q) \
|
||||
test_bit(QUEUE_FLAG_INLINECRYPT, &(q)->queue_flags)
|
||||
|
||||
#define blk_noretry_request(rq) \
|
||||
((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
|
||||
|
||||
@@ -41,6 +41,7 @@ struct bvec_iter {
|
||||
|
||||
unsigned int bi_bvec_done; /* number of bytes completed in
|
||||
current bvec */
|
||||
u64 bi_dun; /* DUN setting for bio */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||
|
||||
struct fscrypt_ctx;
|
||||
|
||||
/* iv sector for security/pfe/pfk_fscrypt.c and f2fs. sizeof is required
|
||||
* to accommodate 32 bit targets.
|
||||
*/
|
||||
#define PG_DUN(i, p) \
|
||||
((((i)->i_ino & 0xffffffff) << (sizeof((i)->i_ino)/2)) | \
|
||||
((p)->index & 0xffffffff))
|
||||
|
||||
struct fscrypt_info;
|
||||
|
||||
struct fscrypt_str {
|
||||
|
||||
@@ -183,6 +183,21 @@ static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* fscrypt_ice.c */
|
||||
static inline int fscrypt_using_hardware_encryption(const struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_ice_dun(const struct inode *inode,
|
||||
struct bio *bio, u64 dun){}
|
||||
|
||||
static inline bool fscrypt_mergeable_bio(struct bio *bio,
|
||||
sector_t iv_block, bool bio_encrypted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* hooks.c */
|
||||
|
||||
static inline int fscrypt_file_open(struct inode *inode, struct file *filp)
|
||||
|
||||
@@ -29,6 +29,7 @@ struct fscrypt_operations {
|
||||
bool (*dummy_context)(struct inode *);
|
||||
bool (*empty_dir)(struct inode *);
|
||||
unsigned (*max_namelen)(struct inode *);
|
||||
bool (*is_encrypted)(struct inode *);
|
||||
};
|
||||
|
||||
struct fscrypt_ctx {
|
||||
@@ -97,10 +98,6 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *,
|
||||
/* keyinfo.c */
|
||||
extern int fscrypt_get_encryption_info(struct inode *);
|
||||
extern void fscrypt_put_encryption_info(struct inode *);
|
||||
extern int fs_using_hardware_encryption(struct inode *inode);
|
||||
extern char *fscrypt_get_ice_encryption_key(const struct inode *inode);
|
||||
extern char *fscrypt_get_ice_encryption_salt(const struct inode *inode);
|
||||
extern int fscrypt_is_aes_xts_cipher(const struct inode *inode);
|
||||
|
||||
/* fname.c */
|
||||
extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
|
||||
@@ -199,6 +196,13 @@ extern void fscrypt_pullback_bio_page(struct page **, bool);
|
||||
extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
|
||||
unsigned int);
|
||||
|
||||
/* fscrypt_ice.c */
|
||||
extern int fscrypt_using_hardware_encryption(const struct inode *inode);
|
||||
extern void fscrypt_set_ice_dun(const struct inode *inode,
|
||||
struct bio *bio, u64 dun);
|
||||
extern bool fscrypt_mergeable_bio(struct bio *bio, u64 dun, bool bio_encrypted);
|
||||
|
||||
|
||||
/* hooks.c */
|
||||
extern int fscrypt_file_open(struct inode *inode, struct file *filp);
|
||||
extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir);
|
||||
|
||||
@@ -19,6 +19,19 @@ struct ice_crypto_setting;
|
||||
|
||||
#ifdef CONFIG_PFK
|
||||
|
||||
/*
|
||||
* Default key for inline encryption.
|
||||
*
|
||||
* For now only AES-256-XTS is supported, so this is a fixed length. But if
|
||||
* ever needed, this should be made variable-length with a 'mode' and 'size'.
|
||||
* (Remember to update pfk_allow_merge_bio() when doing so!)
|
||||
*/
|
||||
#define BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS 64
|
||||
|
||||
struct blk_encryption_key {
|
||||
u8 raw[BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS];
|
||||
};
|
||||
|
||||
int pfk_load_key_start(const struct bio *bio,
|
||||
struct ice_crypto_setting *ice_setting, bool *is_pfe, bool);
|
||||
int pfk_load_key_end(const struct bio *bio, bool *is_pfe);
|
||||
|
||||
@@ -662,6 +662,9 @@ struct Scsi_Host {
|
||||
/* The controller does not support WRITE SAME */
|
||||
unsigned no_write_same:1;
|
||||
|
||||
/* Inline encryption support? */
|
||||
unsigned inlinecrypt_support:1;
|
||||
|
||||
unsigned use_blk_mq:1;
|
||||
unsigned use_cmd_list:1;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#
|
||||
|
||||
ccflags-y += -Isecurity/selinux -Isecurity/selinux/include
|
||||
ccflags-y += -Ifs/ext4
|
||||
#ccflags-y += -Ifs/ext4
|
||||
ccflags-y += -Ifs/crypto
|
||||
|
||||
obj-$(CONFIG_PFT) += pft.o
|
||||
obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o
|
||||
obj-$(CONFIG_PFK) += pfk.o pfk_kc.o pfk_ice.o pfk_ext4.o pfk_f2fs.o
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include <linux/printk.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/security.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <crypto/ice.h>
|
||||
|
||||
#include <linux/pfk.h>
|
||||
@@ -56,8 +57,9 @@
|
||||
#include "objsec.h"
|
||||
#include "pfk_ice.h"
|
||||
#include "pfk_ext4.h"
|
||||
#include "pfk_f2fs.h"
|
||||
#include "pfk_internal.h"
|
||||
#include "ext4.h"
|
||||
//#include "ext4.h"
|
||||
|
||||
static bool pfk_ready;
|
||||
|
||||
@@ -67,7 +69,7 @@ static bool pfk_ready;
|
||||
#define PFK_SUPPORTED_SALT_SIZE 32
|
||||
|
||||
/* Various PFE types and function tables to support each one of them */
|
||||
enum pfe_type {EXT4_CRYPT_PFE, INVALID_PFE};
|
||||
enum pfe_type {EXT4_CRYPT_PFE, F2FS_CRYPT_PFE, INVALID_PFE};
|
||||
|
||||
typedef int (*pfk_parse_inode_type)(const struct bio *bio,
|
||||
const struct inode *inode,
|
||||
@@ -81,16 +83,19 @@ typedef bool (*pfk_allow_merge_bio_type)(const struct bio *bio1,
|
||||
|
||||
static const pfk_parse_inode_type pfk_parse_inode_ftable[] = {
|
||||
/* EXT4_CRYPT_PFE */ &pfk_ext4_parse_inode,
|
||||
/* F2FS_CRYPT_PFE */ &pfk_f2fs_parse_inode,
|
||||
};
|
||||
|
||||
static const pfk_allow_merge_bio_type pfk_allow_merge_bio_ftable[] = {
|
||||
/* EXT4_CRYPT_PFE */ &pfk_ext4_allow_merge_bio,
|
||||
/* F2FS_CRYPT_PFE */ &pfk_f2fs_allow_merge_bio,
|
||||
};
|
||||
|
||||
static void __exit pfk_exit(void)
|
||||
{
|
||||
pfk_ready = false;
|
||||
pfk_ext4_deinit();
|
||||
pfk_f2fs_deinit();
|
||||
pfk_kc_deinit();
|
||||
}
|
||||
|
||||
@@ -103,10 +108,15 @@ static int __init pfk_init(void)
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
|
||||
ret = pfk_f2fs_init();
|
||||
if (ret != 0)
|
||||
goto fail;
|
||||
|
||||
ret = pfk_kc_init();
|
||||
if (ret != 0) {
|
||||
pr_err("could init pfk key cache, error %d\n", ret);
|
||||
pfk_ext4_deinit();
|
||||
pfk_f2fs_deinit();
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -132,6 +142,9 @@ static enum pfe_type pfk_get_pfe_type(const struct inode *inode)
|
||||
if (pfk_is_ext4_type(inode))
|
||||
return EXT4_CRYPT_PFE;
|
||||
|
||||
if (pfk_is_f2fs_type(inode))
|
||||
return F2FS_CRYPT_PFE;
|
||||
|
||||
return INVALID_PFE;
|
||||
}
|
||||
|
||||
@@ -148,6 +161,9 @@ char *inode_to_filename(const struct inode *inode)
|
||||
struct dentry *dentry = NULL;
|
||||
char *filename = NULL;
|
||||
|
||||
if (!inode)
|
||||
return "NULL";
|
||||
|
||||
if (hlist_empty(&inode->i_dentry))
|
||||
return "unknown";
|
||||
|
||||
@@ -182,32 +198,30 @@ static inline bool pfk_is_ready(void)
|
||||
*/
|
||||
static struct inode *pfk_bio_get_inode(const struct bio *bio)
|
||||
{
|
||||
struct address_space *mapping;
|
||||
|
||||
if (!bio)
|
||||
return NULL;
|
||||
if (!bio_has_data((struct bio *)bio))
|
||||
return NULL;
|
||||
if (!bio->bi_io_vec)
|
||||
return NULL;
|
||||
if (!bio->bi_io_vec->bv_page)
|
||||
return NULL;
|
||||
if (!bio_has_data((struct bio *)bio))
|
||||
return NULL;
|
||||
|
||||
if (PageAnon(bio->bi_io_vec->bv_page)) {
|
||||
struct inode *inode;
|
||||
|
||||
//Using direct-io (O_DIRECT) without page cache
|
||||
/* Using direct-io (O_DIRECT) without page cache */
|
||||
inode = dio_bio_get_inode((struct bio *)bio);
|
||||
pr_debug("inode on direct-io, inode = 0x%pK.\n", inode);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
mapping = page_mapping(bio->bi_io_vec->bv_page);
|
||||
if (!mapping)
|
||||
if (!page_mapping(bio->bi_io_vec->bv_page))
|
||||
return NULL;
|
||||
|
||||
if (!mapping->host)
|
||||
if (!bio->bi_io_vec->bv_page->mapping->host)
|
||||
|
||||
return NULL;
|
||||
|
||||
return bio->bi_io_vec->bv_page->mapping->host;
|
||||
@@ -258,6 +272,58 @@ bool pfe_is_inode_filesystem_type(const struct inode *inode,
|
||||
return (strcmp(inode->i_sb->s_type->name, fs_type) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* pfk_get_key_for_bio() - get the encryption key to be used for a bio
|
||||
*
|
||||
* @bio: pointer to the BIO
|
||||
* @key_info: pointer to the key information which will be filled in
|
||||
* @algo_mode: optional pointer to the algorithm identifier which will be set
|
||||
* @is_pfe: will be set to false if the BIO should be left unencrypted
|
||||
*
|
||||
* Return: 0 if a key is being used, otherwise a -errno value
|
||||
*/
|
||||
static int pfk_get_key_for_bio(const struct bio *bio,
|
||||
struct pfk_key_info *key_info,
|
||||
enum ice_cryto_algo_mode *algo_mode,
|
||||
bool *is_pfe)
|
||||
{
|
||||
const struct inode *inode;
|
||||
enum pfe_type which_pfe;
|
||||
const struct blk_encryption_key *key;
|
||||
|
||||
inode = pfk_bio_get_inode(bio);
|
||||
which_pfe = pfk_get_pfe_type(inode);
|
||||
|
||||
if (which_pfe != INVALID_PFE) {
|
||||
/* Encrypted file; override ->bi_crypt_key */
|
||||
pr_debug("parsing inode %lu with PFE type %d\n",
|
||||
inode->i_ino, which_pfe);
|
||||
return (*(pfk_parse_inode_ftable[which_pfe]))
|
||||
(bio, inode, key_info, algo_mode, is_pfe);
|
||||
}
|
||||
|
||||
/*
|
||||
* bio is not for an encrypted file. Use ->bi_crypt_key if it was set.
|
||||
* Otherwise, don't encrypt/decrypt the bio.
|
||||
*/
|
||||
key = bio->bi_crypt_key;
|
||||
if (!key) {
|
||||
*is_pfe = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Note: the "salt" is really just the second half of the XTS key. */
|
||||
BUILD_BUG_ON(sizeof(key->raw) !=
|
||||
PFK_SUPPORTED_KEY_SIZE + PFK_SUPPORTED_SALT_SIZE);
|
||||
key_info->key = &key->raw[0];
|
||||
key_info->key_size = PFK_SUPPORTED_KEY_SIZE;
|
||||
key_info->salt = &key->raw[PFK_SUPPORTED_KEY_SIZE];
|
||||
key_info->salt_size = PFK_SUPPORTED_SALT_SIZE;
|
||||
if (algo_mode)
|
||||
*algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* pfk_load_key_start() - loads PFE encryption key to the ICE
|
||||
@@ -287,8 +353,6 @@ int pfk_load_key_start(const struct bio *bio,
|
||||
enum ice_cryto_algo_mode algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS;
|
||||
enum ice_crpto_key_size key_size_type = 0;
|
||||
u32 key_index = 0;
|
||||
struct inode *inode = NULL;
|
||||
enum pfe_type which_pfe = INVALID_PFE;
|
||||
|
||||
if (!is_pfe) {
|
||||
pr_err("is_pfe is NULL\n");
|
||||
@@ -310,23 +374,8 @@ int pfk_load_key_start(const struct bio *bio,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
inode = pfk_bio_get_inode(bio);
|
||||
if (!inode) {
|
||||
*is_pfe = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe);
|
||||
|
||||
which_pfe = pfk_get_pfe_type(inode);
|
||||
if (which_pfe == INVALID_PFE) {
|
||||
*is_pfe = false;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
pr_debug("parsing file %s with PFE %d\n",
|
||||
inode_to_filename(inode), which_pfe);
|
||||
|
||||
ret = (*(pfk_parse_inode_ftable[which_pfe]))
|
||||
(bio, inode, &key_info, &algo_mode, is_pfe);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@@ -351,7 +400,7 @@ int pfk_load_key_start(const struct bio *bio,
|
||||
ice_setting->key_index = key_index;
|
||||
|
||||
pr_debug("loaded key for file %s key_index %d\n",
|
||||
inode_to_filename(inode), key_index);
|
||||
inode_to_filename(pfk_bio_get_inode(bio)), key_index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -371,8 +420,6 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
{
|
||||
int ret = 0;
|
||||
struct pfk_key_info key_info = {NULL, NULL, 0, 0};
|
||||
enum pfe_type which_pfe = INVALID_PFE;
|
||||
struct inode *inode = NULL;
|
||||
|
||||
if (!is_pfe) {
|
||||
pr_err("is_pfe is NULL\n");
|
||||
@@ -388,20 +435,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
if (!pfk_is_ready())
|
||||
return -ENODEV;
|
||||
|
||||
inode = pfk_bio_get_inode(bio);
|
||||
if (!inode) {
|
||||
*is_pfe = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
which_pfe = pfk_get_pfe_type(inode);
|
||||
if (which_pfe == INVALID_PFE) {
|
||||
*is_pfe = false;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = (*(pfk_parse_inode_ftable[which_pfe]))
|
||||
(bio, inode, &key_info, NULL, is_pfe);
|
||||
ret = pfk_get_key_for_bio(bio, &key_info, NULL, is_pfe);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@@ -409,7 +443,7 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
key_info.salt, key_info.salt_size);
|
||||
|
||||
pr_debug("finished using key for file %s\n",
|
||||
inode_to_filename(inode));
|
||||
inode_to_filename(pfk_bio_get_inode(bio)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -431,10 +465,12 @@ int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
|
||||
*/
|
||||
bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2)
|
||||
{
|
||||
struct inode *inode1 = NULL;
|
||||
struct inode *inode2 = NULL;
|
||||
enum pfe_type which_pfe1 = INVALID_PFE;
|
||||
enum pfe_type which_pfe2 = INVALID_PFE;
|
||||
const struct blk_encryption_key *key1;
|
||||
const struct blk_encryption_key *key2;
|
||||
const struct inode *inode1;
|
||||
const struct inode *inode2;
|
||||
enum pfe_type which_pfe1;
|
||||
enum pfe_type which_pfe2;
|
||||
|
||||
if (!pfk_is_ready())
|
||||
return false;
|
||||
@@ -445,24 +481,38 @@ bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2)
|
||||
if (bio1 == bio2)
|
||||
return true;
|
||||
|
||||
key1 = bio1->bi_crypt_key;
|
||||
key2 = bio2->bi_crypt_key;
|
||||
|
||||
inode1 = pfk_bio_get_inode(bio1);
|
||||
inode2 = pfk_bio_get_inode(bio2);
|
||||
|
||||
|
||||
which_pfe1 = pfk_get_pfe_type(inode1);
|
||||
which_pfe2 = pfk_get_pfe_type(inode2);
|
||||
|
||||
/* nodes with different encryption, do not merge */
|
||||
/*
|
||||
* If one bio is for an encrypted file and the other is for a different
|
||||
* type of encrypted file or for blocks that are not part of an
|
||||
* encrypted file, do not merge.
|
||||
*/
|
||||
if (which_pfe1 != which_pfe2)
|
||||
return false;
|
||||
|
||||
/* both nodes do not have encryption, allow merge */
|
||||
if (which_pfe1 == INVALID_PFE)
|
||||
return true;
|
||||
|
||||
if (which_pfe1 != INVALID_PFE) {
|
||||
/* Both bios are for the same type of encrypted file. */
|
||||
return (*(pfk_allow_merge_bio_ftable[which_pfe1]))(bio1, bio2,
|
||||
inode1, inode2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Neither bio is for an encrypted file. Merge only if the default keys
|
||||
* are the same (or both are NULL).
|
||||
*/
|
||||
return key1 == key2 ||
|
||||
(key1 && key2 &&
|
||||
!crypto_memneq(key1->raw, key2->raw, sizeof(key1->raw)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush key table on storage core reset. During core reset key configuration
|
||||
* is lost in ICE. We need to flash the cache, so that the keys will be
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include "ext4_ice.h"
|
||||
#include "fscrypt_ice.h"
|
||||
#include "pfk_ext4.h"
|
||||
//#include "ext4_ice.h"
|
||||
|
||||
static bool pfk_ext4_ready;
|
||||
|
||||
@@ -102,7 +103,7 @@ bool pfk_is_ext4_type(const struct inode *inode)
|
||||
if (!pfe_is_inode_filesystem_type(inode, "ext4"))
|
||||
return false;
|
||||
|
||||
return ext4_should_be_processed_by_ice(inode);
|
||||
return fscrypt_should_be_processed_by_ice(inode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +125,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode,
|
||||
if (!inode)
|
||||
return -EINVAL;
|
||||
|
||||
if (!ext4_is_aes_xts_cipher(inode)) {
|
||||
if (!fscrypt_is_aes_xts_cipher(inode)) {
|
||||
pr_err("ext4 alghoritm is not supported by pfk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -163,25 +164,25 @@ int pfk_ext4_parse_inode(const struct bio *bio,
|
||||
if (!key_info)
|
||||
return -EINVAL;
|
||||
|
||||
key_info->key = ext4_get_ice_encryption_key(inode);
|
||||
key_info->key = fscrypt_get_ice_encryption_key(inode);
|
||||
if (!key_info->key) {
|
||||
pr_err("could not parse key from ext4\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_info->key_size = ext4_get_ice_encryption_key_size(inode);
|
||||
key_info->key_size = fscrypt_get_ice_encryption_key_size(inode);
|
||||
if (!key_info->key_size) {
|
||||
pr_err("could not parse key size from ext4\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_info->salt = ext4_get_ice_encryption_salt(inode);
|
||||
key_info->salt = fscrypt_get_ice_encryption_salt(inode);
|
||||
if (!key_info->salt) {
|
||||
pr_err("could not parse salt from ext4\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_info->salt_size = ext4_get_ice_encryption_salt_size(inode);
|
||||
key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode);
|
||||
if (!key_info->salt_size) {
|
||||
pr_err("could not parse salt size from ext4\n");
|
||||
return -EINVAL;
|
||||
@@ -207,5 +208,5 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1,
|
||||
if (!inode1 || !inode2)
|
||||
return false;
|
||||
|
||||
return ext4_is_ice_encryption_info_equal(inode1, inode2);
|
||||
return fscrypt_is_ice_encryption_info_equal(inode1, inode2);
|
||||
}
|
||||
|
||||
200
security/pfe/pfk_f2fs.c
Normal file
200
security/pfe/pfk_f2fs.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Per-File-Key (PFK) - f2fs
|
||||
*
|
||||
* This driver is used for working with EXT4/F2FS crypt extension
|
||||
*
|
||||
* The key information is stored in node by EXT4/F2FS when file is first opened
|
||||
* and will be later accessed by Block Device Driver to actually load the key
|
||||
* to encryption hw.
|
||||
*
|
||||
* PFK exposes API's for loading and removing keys from encryption hw
|
||||
* and also API to determine whether 2 adjacent blocks can be agregated by
|
||||
* Block Layer in one request to encryption hw.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Uncomment the line below to enable debug messages */
|
||||
#define DEBUG 1
|
||||
#define pr_fmt(fmt) "pfk_f2fs [%s]: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include "fscrypt_ice.h"
|
||||
#include "pfk_f2fs.h"
|
||||
|
||||
static bool pfk_f2fs_ready;
|
||||
|
||||
/*
|
||||
* pfk_f2fs_deinit() - Deinit function, should be invoked by upper PFK layer
|
||||
*/
|
||||
void pfk_f2fs_deinit(void)
|
||||
{
|
||||
pfk_f2fs_ready = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* pfk_f2fs_init() - Init function, should be invoked by upper PFK layer
|
||||
*/
|
||||
int __init pfk_f2fs_init(void)
|
||||
{
|
||||
pfk_f2fs_ready = true;
|
||||
pr_info("PFK F2FS inited successfully\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pfk_f2fs_is_ready() - driver is initialized and ready.
|
||||
*
|
||||
* Return: true if the driver is ready.
|
||||
*/
|
||||
static inline bool pfk_f2fs_is_ready(void)
|
||||
{
|
||||
return pfk_f2fs_ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* pfk_is_f2fs_type() - return true if inode belongs to ICE F2FS PFE
|
||||
* @inode: inode pointer
|
||||
*/
|
||||
bool pfk_is_f2fs_type(const struct inode *inode)
|
||||
{
|
||||
if (!pfe_is_inode_filesystem_type(inode, "f2fs"))
|
||||
return false;
|
||||
|
||||
return fscrypt_should_be_processed_by_ice(inode);
|
||||
}
|
||||
|
||||
/**
|
||||
* pfk_f2fs_parse_cipher() - parse cipher from inode to enum
|
||||
* @inode: inode
|
||||
* @algo: pointer to store the output enum (can be null)
|
||||
*
|
||||
* return 0 in case of success, error otherwise (i.e not supported cipher)
|
||||
*/
|
||||
static int pfk_f2fs_parse_cipher(const struct inode *inode,
|
||||
enum ice_cryto_algo_mode *algo)
|
||||
{
|
||||
/*
|
||||
* currently only AES XTS algo is supported
|
||||
* in the future, table with supported ciphers might
|
||||
* be introduced
|
||||
*/
|
||||
if (!inode)
|
||||
return -EINVAL;
|
||||
|
||||
if (!fscrypt_is_aes_xts_cipher(inode)) {
|
||||
pr_err("f2fs alghoritm is not supported by pfk\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (algo)
|
||||
*algo = ICE_CRYPTO_ALGO_MODE_AES_XTS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pfk_f2fs_parse_inode(const struct bio *bio,
|
||||
const struct inode *inode,
|
||||
struct pfk_key_info *key_info,
|
||||
enum ice_cryto_algo_mode *algo,
|
||||
bool *is_pfe)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!is_pfe)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* only a few errors below can indicate that
|
||||
* this function was not invoked within PFE context,
|
||||
* otherwise we will consider it PFE
|
||||
*/
|
||||
*is_pfe = true;
|
||||
|
||||
if (!pfk_f2fs_is_ready())
|
||||
return -ENODEV;
|
||||
|
||||
if (!inode)
|
||||
return -EINVAL;
|
||||
|
||||
if (!key_info)
|
||||
return -EINVAL;
|
||||
|
||||
key_info->key = fscrypt_get_ice_encryption_key(inode);
|
||||
if (!key_info->key) {
|
||||
pr_err("could not parse key from f2fs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_info->key_size = fscrypt_get_ice_encryption_key_size(inode);
|
||||
if (!key_info->key_size) {
|
||||
pr_err("could not parse key size from f2fs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_info->salt = fscrypt_get_ice_encryption_salt(inode);
|
||||
if (!key_info->salt) {
|
||||
pr_err("could not parse salt from f2fs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_info->salt_size = fscrypt_get_ice_encryption_salt_size(inode);
|
||||
if (!key_info->salt_size) {
|
||||
pr_err("could not parse salt size from f2fs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = pfk_f2fs_parse_cipher(inode, algo);
|
||||
if (ret != 0) {
|
||||
pr_err("not supported cipher\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool pfk_f2fs_allow_merge_bio(const struct bio *bio1,
|
||||
const struct bio *bio2, const struct inode *inode1,
|
||||
const struct inode *inode2)
|
||||
{
|
||||
bool mergeable;
|
||||
|
||||
/* if there is no f2fs pfk, don't disallow merging blocks */
|
||||
if (!pfk_f2fs_is_ready())
|
||||
return true;
|
||||
|
||||
if (!inode1 || !inode2)
|
||||
return false;
|
||||
|
||||
mergeable = fscrypt_is_ice_encryption_info_equal(inode1, inode2);
|
||||
if (!mergeable)
|
||||
return false;
|
||||
|
||||
|
||||
/* ICE allows only consecutive iv_key stream. */
|
||||
if (!bio_dun(bio1) && !bio_dun(bio2))
|
||||
return true;
|
||||
else if (!bio_dun(bio1) || !bio_dun(bio2))
|
||||
return false;
|
||||
|
||||
return bio_end_dun(bio1) == bio_dun(bio2);
|
||||
}
|
||||
37
security/pfe/pfk_f2fs.h
Normal file
37
security/pfe/pfk_f2fs.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _PFK_F2FS_H_
|
||||
#define _PFK_F2FS_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <crypto/ice.h>
|
||||
#include "pfk_internal.h"
|
||||
|
||||
bool pfk_is_f2fs_type(const struct inode *inode);
|
||||
|
||||
int pfk_f2fs_parse_inode(const struct bio *bio,
|
||||
const struct inode *inode,
|
||||
struct pfk_key_info *key_info,
|
||||
enum ice_cryto_algo_mode *algo,
|
||||
bool *is_pfe);
|
||||
|
||||
bool pfk_f2fs_allow_merge_bio(const struct bio *bio1,
|
||||
const struct bio *bio2, const struct inode *inode1,
|
||||
const struct inode *inode2);
|
||||
|
||||
int __init pfk_f2fs_init(void);
|
||||
|
||||
void pfk_f2fs_deinit(void);
|
||||
|
||||
#endif /* _PFK_F2FS_H_ */
|
||||
@@ -435,6 +435,7 @@ int pfk_kc_init(void)
|
||||
}
|
||||
kc_ready = true;
|
||||
kc_spin_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -446,8 +447,8 @@ int pfk_kc_init(void)
|
||||
int pfk_kc_deinit(void)
|
||||
{
|
||||
int res = pfk_kc_clear();
|
||||
|
||||
kc_ready = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user