Merge "Enable hardware based FBE on f2fs and adapt ext4 fs"

This commit is contained in:
qctecmdr Service 2018-08-23 22:01:16 -07:00 committed by Gerrit - the friendly Code Review server
commit 7803301623
50 changed files with 1136 additions and 474 deletions

View File

@ -577,6 +577,14 @@ 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
}
/**
* __bio_clone_fast - clone a bio that shares the original bio's biovec
* @bio: destination bio
@ -606,6 +614,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);

View File

@ -7,9 +7,9 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
#include <linux/pfk.h>
#include <trace/events/block.h>
#include <trace/events/block.h>
#include <linux/pfk.h>
#include "blk.h"
static struct bio *blk_bio_discard_split(struct request_queue *q,
@ -705,6 +705,7 @@ static struct request *attempt_merge(struct request_queue *q,
if (crypto_not_mergeable(req->bio, next->bio))
return 0;
/*
* If we are allowed to merge, then append bio list
* from next to rq and release next. merge_requests_fn

View File

@ -436,7 +436,7 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req,
{
struct elevator_queue *e = q->elevator;
struct request *__rq;
enum elv_merge ret;
/*
* Levels of merges:
* nomerges: No merges at all attempted
@ -449,9 +449,11 @@ enum elv_merge elv_merge(struct request_queue *q, struct request **req,
/*
* First try one-hit cache.
*/
if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) {
enum elv_merge ret = blk_try_merge(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;
return ret;

View File

@ -773,4 +773,5 @@ config CRYPTO_DEV_ARTPEC6
if ARCH_QCOM
source drivers/crypto/msm/Kconfig
endif
endif # CRYPTO_HW

View File

@ -2159,6 +2159,8 @@ 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,

View File

@ -937,11 +937,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);
@ -2180,6 +2187,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_variant_clear;
} else {
hba->host->inlinecrypt_support = 1;
}
host->generic_phy = devm_phy_get(dev, "ufsphy");

View File

@ -1,6 +1,7 @@
obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o
fscrypto-y := crypto.o fname.o hooks.o keyinfo.o policy.o
fscrypto-$(CONFIG_BLOCK) += bio.o
ccflags-y += -Ifs/ext4
fscrypto-$(CONFIG_EXT4_FS_ICE_ENCRYPTION) += ext4_ice.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

View File

@ -25,7 +25,6 @@
#include <linux/bio.h>
#include <linux/namei.h>
#include "fscrypt_private.h"
#include "ext4_ice.h"
static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
{
@ -34,12 +33,11 @@ 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 (ext4_should_be_processed_by_ice(page->mapping->host)) {
if (fscrypt_using_hardware_encryption(page->mapping->host)) {
SetPageUptodate(page);
} else {
int ret = fscrypt_decrypt_page(page->mapping->host,
page, PAGE_SIZE, 0, page->index);
page, PAGE_SIZE, 0, page->index);
if (ret) {
WARN_ON_ONCE(1);
SetPageError(page);

View File

@ -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.
*/
#include "ext4_ice.h"
#include "fscrypt_private.h"
/*
* Retrieves encryption key from the inode
*/
char *ext4_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 *ext4_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[ext4_get_ice_encryption_key_size(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 = NULL;
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
*/
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));
}

146
fs/crypto/fscrypt_ice.c Normal file
View 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
View 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 */

View File

@ -17,6 +17,7 @@
#endif
#include <linux/fscrypt.h>
#include <crypto/hash.h>
#include <linux/pfk.h>
/* Encryption parameters */
#define FS_IV_SIZE 16
@ -61,11 +62,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;
@ -105,12 +113,12 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
return false;
}
static inline bool is_private_mode(struct fscrypt_info *ci)
static inline bool is_private_data_mode(struct fscrypt_info *ci)
{
return ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE;
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);

View File

@ -16,7 +16,7 @@
#include <crypto/sha.h>
#include <crypto/skcipher.h>
#include "fscrypt_private.h"
#include "ext4_ice.h"
#include "fscrypt_ice.h"
static struct crypto_shash *essiv_hash_tfm;
@ -69,7 +69,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;
@ -117,21 +117,20 @@ static int validate_user_key(struct fscrypt_info *crypt_info,
res = -ENOKEY;
goto out;
}
/*
* If we don't need to derive, we still want to do everything
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_mode(crypt_info)) {
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
/* Inline encryption: no key derivation required because IVs are
* assigned based on iv_sector.
*/
if (sizeof(crypt_info->ci_raw_key) != sizeof(master_key->raw))
goto out;
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;
@ -156,42 +155,37 @@ static const struct {
FS_AES_128_CTS_KEY_SIZE },
[FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { "xts(speck128)", 64 },
[FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { "cts(cbc(speck128))", 32 },
[FS_ENCRYPTION_MODE_PRIVATE] = { "bugon", FS_AES_256_XTS_KEY_SIZE },
[FS_ENCRYPTION_MODE_PRIVATE] = { "bugon",
FS_AES_256_XTS_KEY_SIZE },
};
static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
const char **cipher_str_ret, int *keysize_ret, int *fname)
const char **cipher_str_ret, int *keysize_ret)
{
u32 mode;
if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) {
pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n",
inode->i_ino,
ci->ci_data_mode, ci->ci_filename_mode);
return -EINVAL;
}
if (S_ISREG(inode->i_mode)) {
if (ci->ci_data_mode == FS_ENCRYPTION_MODE_AES_256_XTS) {
*cipher_str_ret = "xts(aes)";
*keysize_ret = FS_AES_256_XTS_KEY_SIZE;
return 0;
} else if (ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE) {
*cipher_str_ret = "bugon";
*keysize_ret = FS_AES_256_XTS_KEY_SIZE;
return 0;
}
pr_warn_once("fscrypto: unsupported contents encryption mode %d for inode %lu\n",
ci->ci_data_mode, inode->i_ino);
return -ENOKEY;
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;
} else {
WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n",
inode->i_ino, (inode->i_mode & S_IFMT));
return -EINVAL;
}
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
if (ci->ci_filename_mode == FS_ENCRYPTION_MODE_AES_256_CTS) {
*cipher_str_ret = "cts(cbc(aes))";
*keysize_ret = FS_AES_256_CTS_KEY_SIZE;
*fname = 1;
return 0;
}
pr_warn_once("fscrypto: unsupported filenames encryption mode %d for inode %lu\n",
ci->ci_filename_mode, inode->i_ino);
return -ENOKEY;
}
pr_warn_once("fscrypto: unsupported file type %d for inode %lu\n",
(inode->i_mode & S_IFMT), inode->i_ino);
return -ENOKEY;
*cipher_str_ret = available_modes[mode].cipher_str;
*keysize_ret = available_modes[mode].keysize;
return 0;
}
static void put_crypt_info(struct fscrypt_info *ci)
@ -201,6 +195,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
crypto_free_skcipher(ci->ci_ctfm);
crypto_free_cipher(ci->ci_essiv_tfm);
memset(ci, 0, sizeof(*ci)); /* sanitizes ->ci_raw_key */
kmem_cache_free(fscrypt_info_cachep, ci);
}
@ -271,21 +266,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 ext4_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;
@ -293,8 +279,8 @@ int fscrypt_get_encryption_info(struct inode *inode)
struct crypto_skcipher *ctfm;
const char *cipher_str;
int keysize;
u8 *raw_key = NULL;
int res;
int fname = 0;
if (inode->i_crypt_info)
return 0;
@ -311,7 +297,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)) {
@ -336,8 +323,7 @@ int fscrypt_get_encryption_info(struct inode *inode)
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
sizeof(crypt_info->ci_master_key));
res = determine_cipher_type(crypt_info, inode, &cipher_str,
&keysize, &fname);
res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
if (res)
goto out;
@ -346,17 +332,16 @@ int fscrypt_get_encryption_info(struct inode *inode)
* crypto API as part of key derivation.
*/
res = -ENOMEM;
raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
if (!raw_key)
goto out;
if (fscrypt_dummy_context_enabled(inode)) {
memset(crypt_info->ci_raw_key, 0x42, FS_AES_256_XTS_KEY_SIZE);
goto got_key;
}
res = validate_user_key(crypt_info, &ctx, crypt_info->ci_raw_key,
FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
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;
@ -366,42 +351,57 @@ int fscrypt_get_encryption_info(struct inode *inode)
} else if (res) {
goto out;
}
got_key:
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_err("%s: error %d inode %u allocating crypto tfm\n",
__func__, res, (unsigned int) inode->i_ino);
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;
}
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;
} else if (S_ISREG(inode->i_mode) &&
/* 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);
keysize);
if (res) {
pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n",
__func__, res, inode->i_ino);
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:
if (res == -ENOKEY)
res = 0;
put_crypt_info(crypt_info);
kzfree(raw_key);
return res;
}
EXPORT_SYMBOL(fscrypt_get_encryption_info);

View File

@ -473,10 +473,9 @@ struct inode *dio_bio_get_inode(struct bio *bio)
return NULL;
inode = bio->bi_dio_inode;
return inode;
}
EXPORT_SYMBOL(dio_bio_get_inode);
/*
* Release any resources in case of a failure
*/

View File

@ -2,7 +2,6 @@
#
# Makefile for the linux ext4-filesystem routines.
#
ccflags-y += -Ifs/crypto
obj-$(CONFIG_EXT4_FS) += ext4.o

View File

@ -40,9 +40,7 @@
#include <linux/compat.h>
#endif
#ifndef __FS_HAS_ENCRYPTION
#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION)
#endif
#include <linux/fscrypt.h>
/*
@ -2352,7 +2350,6 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
}
static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
#define fscrypt_set_d_op(i)
#endif
/* dir.c */

View File

@ -1,104 +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"
#include <linux/fscrypt.h>
#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 FS_AES_256_XTS_KEY_SIZE / 2;
}
static inline size_t ext4_get_ice_encryption_salt_size(
const struct inode *inode)
{
return FS_AES_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;
}
#endif
#endif /* _EXT4_ICE_H */

View File

@ -44,7 +44,6 @@
#include "xattr.h"
#include "acl.h"
#include "truncate.h"
#include "ext4_ice.h"
#include <trace/events/ext4.h>
#include <trace/events/android_fs.h>
@ -1220,7 +1219,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_should_be_processed_by_ice(inode);
!fscrypt_using_hardware_encryption(inode);
}
}
/*
@ -3716,15 +3715,14 @@ 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)
if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
return 0;
#if defined(CONFIG_EXT4_FS_ENCRYPTION)
WARN_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)
&& !fscrypt_using_hardware_encryption(inode));
#endif
ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter,
get_block_func, ext4_end_io_dio, NULL,
dio_flags);
ret = __blockdev_direct_IO(iocb, inode,
inode->i_sb->s_bdev, iter,
get_block_func,
ext4_end_io_dio, NULL, dio_flags);
if (ret > 0 && !overwrite && ext4_test_inode_state(inode,
EXT4_STATE_DIO_UNWRITTEN)) {
@ -3830,9 +3828,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
@ -4042,7 +4040,7 @@ static int __ext4_block_zero_page_range(handle_t *handle,
goto unlock;
if (S_ISREG(inode->i_mode) &&
ext4_encrypted_inode(inode) &&
!ext4_should_be_processed_by_ice(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);

View File

@ -939,13 +939,11 @@ resizefs_out:
case EXT4_IOC_PRECACHE_EXTENTS:
return ext4_ext_precache(inode);
case EXT4_IOC_SET_ENCRYPTION_POLICY: {
#ifdef CONFIG_EXT4_FS_ENCRYPTION
case EXT4_IOC_SET_ENCRYPTION_POLICY:
if (!ext4_has_feature_encrypt(sb))
return -EOPNOTSUPP;
return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
#else
return -EOPNOTSUPP;
#endif
}
case EXT4_IOC_GET_ENCRYPTION_PWSALT: {
#ifdef CONFIG_EXT4_FS_ENCRYPTION
int err, err2;

View File

@ -29,7 +29,6 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
#include "ext4_ice.h"
static struct kmem_cache *io_end_cachep;
@ -483,9 +482,9 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
gfp_t gfp_flags = GFP_NOFS;
retry_encrypt:
if (!ext4_should_be_processed_by_ice(inode))
data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE,
0, page->index, gfp_flags);
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)) {
ret = PTR_ERR(data_page);
if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {

View File

@ -1235,6 +1235,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,
@ -1242,6 +1247,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

View File

@ -439,6 +439,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);
@ -448,6 +449,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;
@ -467,6 +471,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));
@ -490,6 +497,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;
@ -500,6 +510,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) &&
@ -511,6 +526,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;
}
@ -577,6 +595,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;
@ -1436,6 +1457,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;
@ -1513,6 +1536,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)) {
@ -1520,7 +1551,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;
@ -1590,6 +1622,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))

View File

@ -3279,9 +3279,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

View File

@ -1940,6 +1940,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,
@ -1947,6 +1952,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

View File

@ -3742,11 +3742,9 @@ int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, u
error = dir->i_op->mknod(dir, dentry, mode, dev);
if (error)
return error;
error = security_inode_post_create(dir, dentry, mode);
if (error)
return error;
if (!error)
fsnotify_create(dir, dentry);
return error;

View File

@ -69,6 +69,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))
/*
* Return the data direction, READ or WRITE.
@ -173,6 +176,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;
iter->bi_done += bytes;

View File

@ -100,6 +100,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 */
@ -115,12 +119,8 @@ struct bio {
struct bio_set *bi_pool;
/*
* When using dircet-io (O_DIRECT), we can't get the inode from a bio
* by walking bio->bi_io_vec->bv_page->mapping->host
* since the page is anon.
*/
struct inode *bi_dio_inode;
/*
* We can inline a number of vecs at the end of the bio, to avoid
* double allocations for a small number of bio_vecs. This member

View File

@ -652,6 +652,7 @@ struct request_queue {
#define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */
#define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */
#define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */
#define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_STACKABLE) | \
@ -751,6 +752,8 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
#define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
#define blk_queue_scsi_passthrough(q) \
test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(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| \

View File

@ -44,6 +44,7 @@ struct bvec_iter {
unsigned int bi_bvec_done; /* number of bytes completed in
current bvec */
u64 bi_dun; /* DUN setting for bio */
};
/*

View File

@ -17,10 +17,16 @@
#include <linux/fs.h>
#define FS_CRYPTO_BLOCK_SIZE 16
#define FS_ENCRYPTION_MODE_PRIVATE 127
#define FS_AES_256_XTS_KEY_SIZE 64
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 {
@ -44,8 +50,6 @@ struct fscrypt_name {
/* Maximum value for the third parameter of fscrypt_operations.set_context(). */
#define FSCRYPT_SET_CONTEXT_MAX_SIZE 28
extern int fs_using_hardware_encryption(struct inode *inode);
#if __FS_HAS_ENCRYPTION
#include <linux/fscrypt_supp.h>
#else

View File

@ -184,6 +184,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)

View File

@ -30,6 +30,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 {
@ -196,6 +197,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);

View File

@ -19,8 +19,22 @@ 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);
struct ice_crypto_setting *ice_setting,
bool *is_pfe, bool async);
int pfk_load_key_end(const struct bio *bio, bool *is_pfe);
int pfk_remove_key(const unsigned char *key, size_t key_size);
bool pfk_allow_merge_bio(const struct bio *bio1, const struct bio *bio2);

View File

@ -668,8 +668,8 @@ static inline int security_inode_create(struct inode *dir,
}
static inline int security_inode_post_create(struct inode *dir,
struct dentry *dentry,
umode_t mode)
struct dentry *dentry,
umode_t mode)
{
return 0;
}

View File

@ -663,6 +663,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;

View File

@ -277,6 +277,7 @@ struct fsxattr {
#define FS_ENCRYPTION_MODE_AES_128_CTS 6
#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7
#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8
#define FS_ENCRYPTION_MODE_PRIVATE 127
struct fscrypt_policy {
__u8 version;

View File

@ -10,7 +10,6 @@ if ARCH_QCOM
source security/pfe/Kconfig
endif
config SECURITY_DMESG_RESTRICT
bool "Restrict unprivileged access to the kernel syslog"
default n

View File

@ -10,7 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
subdir-$(CONFIG_SECURITY_YAMA) += yama
subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
subdir-$(CONFIG_ARCH_QCOM) += pfe
subdir-$(CONFIG_ARCH_QCOM) += pfe
# always enable default capabilities
obj-y += commoncap.o
@ -26,8 +26,8 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
obj-$(CONFIG_SECURITY_YAMA) += yama/
obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
obj-$(CONFIG_ARCH_QCOM) += pfe/
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
obj-$(CONFIG_ARCH_QCOM) += pfe/
# Object integrity file lists
subdir-$(CONFIG_INTEGRITY) += integrity

View File

@ -25,4 +25,15 @@ config PFK
Information is used when file is encrypted later using
ICE or dm crypto engine
config PFK_WRAPPED_KEY_SUPPORTED
bool "Per-File-Key driver with wrapped key support"
depends on SECURITY
depends on SECURITY_SELINUX
depends on QSEECOM
depends on PFK
default n
help
Adds wrapped key support in PFK driver. Instead of setting
the key directly in ICE, it unwraps the key and sets the key
in ICE.
endmenu

View File

@ -3,8 +3,8 @@
#
ccflags-y += -Isecurity/selinux -Isecurity/selinux/include
ccflags-y += -Ifs/ext4
ccflags-y += -Ifs/crypto
ccflags-y += -Idrivers/misc
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

View File

@ -37,6 +37,9 @@
*
*/
/* Uncomment the line below to enable debug messages */
/* #define DEBUG 1 */
#define pr_fmt(fmt) "pfk [%s]: " fmt, __func__
#include <linux/module.h>
@ -45,24 +48,27 @@
#include <linux/printk.h>
#include <linux/bio.h>
#include <linux/security.h>
#include <linux/pfk.h>
#include <crypto/algapi.h>
#include <crypto/ice.h>
#include "ext4.h"
#include "objsec.h"
#include <linux/pfk.h>
#include "pfk_kc.h"
#include "objsec.h"
#include "pfk_ice.h"
#include "pfk_ext4.h"
#include "pfk_f2fs.h"
#include "pfk_internal.h"
static bool pfk_ready;
/* might be replaced by a table when more than one cipher is supported */
#define PFK_SUPPORTED_KEY_SIZE 32
#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,
@ -76,31 +82,40 @@ 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();
}
static int __init pfk_init(void)
{
int ret = 0;
ret = pfk_ext4_init();
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;
}
@ -126,6 +141,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;
}
@ -142,6 +160,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";
@ -176,30 +197,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 */
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;
@ -250,6 +271,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
@ -279,8 +352,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");
@ -301,26 +372,16 @@ int pfk_load_key_start(const struct bio *bio,
pr_err("ice setting is NULL\n");
return -EINVAL;
}
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;
}
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);
ret = pfk_get_key_for_bio(bio, &key_info, &algo_mode, is_pfe);
if (ret != 0)
return ret;
ret = pfk_key_size_to_key_type(key_info.key_size, &key_size_type);
if (ret != 0)
return ret;
ret = pfk_kc_load_key_start(key_info.key, key_info.key_size,
key_info.salt, key_info.salt_size, &key_index, async);
if (ret) {
@ -338,7 +399,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;
}
@ -357,9 +418,7 @@ int pfk_load_key_start(const struct bio *bio,
int pfk_load_key_end(const struct bio *bio, bool *is_pfe)
{
int ret = 0;
struct pfk_key_info key_info = {0};
enum pfe_type which_pfe = INVALID_PFE;
struct inode *inode = NULL;
struct pfk_key_info key_info = {NULL, NULL, 0, 0};
if (!is_pfe) {
pr_err("is_pfe is NULL\n");
@ -375,20 +434,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;
@ -396,7 +442,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;
}
@ -418,10 +464,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;
@ -432,24 +480,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);
}
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

View File

@ -26,6 +26,9 @@
*
*/
/* Uncomment the line below to enable debug messages */
/* #define DEBUG 1 */
#define pr_fmt(fmt) "pfk_ext4 [%s]: " fmt, __func__
#include <linux/module.h>
@ -33,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;
@ -67,6 +71,29 @@ static inline bool pfk_ext4_is_ready(void)
return pfk_ext4_ready;
}
/**
* pfk_ext4_dump_inode() - dumps all interesting info about inode to the screen
*
*
*/
/*
* static void pfk_ext4_dump_inode(const struct inode* inode)
* {
* struct ext4_crypt_info *ci = ext4_encryption_info((struct inode*)inode);
*
* pr_debug("dumping inode with address 0x%p\n", inode);
* pr_debug("S_ISREG is %d\n", S_ISREG(inode->i_mode));
* pr_debug("EXT4_INODE_ENCRYPT flag is %d\n",
* ext4_test_inode_flag((struct inode*)inode, EXT4_INODE_ENCRYPT));
* if (ci) {
* pr_debug("crypt_info address 0x%p\n", ci);
* pr_debug("ci->ci_data_mode %d\n", ci->ci_data_mode);
* } else {
* pr_debug("crypt_info is NULL\n");
* }
* }
*/
/**
* pfk_is_ext4_type() - return true if inode belongs to ICE EXT4 PFE
* @inode: inode pointer
@ -76,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);
}
/**
@ -98,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;
}
@ -109,6 +136,7 @@ static int pfk_ext4_parse_cipher(const struct inode *inode,
return 0;
}
int pfk_ext4_parse_inode(const struct bio *bio,
const struct inode *inode,
struct pfk_key_info *key_info,
@ -136,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;
@ -180,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
View 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
View 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_ */

View File

@ -24,7 +24,7 @@
#include <soc/qcom/qseecomi.h>
#include <crypto/ice.h>
#include "pfk_ice.h"
#include "qseecom_kernel.h"
/**********************************/
/** global definitions **/
@ -55,48 +55,120 @@
TZ_SYSCALL_CREATE_PARAM_ID_1( \
TZ_SYSCALL_PARAM_TYPE_VAL)
#define CONTEXT_SIZE 0x1000
#define KEYMASTER_UTILS_CMD_ID 0x200UL
#define KEYMASTER_SET_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 18UL)
#define KEYMASTER_CLEAR_ICE_KEY (KEYMASTER_UTILS_CMD_ID + 19UL)
#define ICE_KEY_SIZE 32
#define ICE_SALT_SIZE 32
static uint8_t ice_key[ICE_KEY_SIZE];
static uint8_t ice_salt[ICE_KEY_SIZE];
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt,
char *storage_type)
static struct qseecom_handle *qhandle;
static int set_wrapped_key(uint32_t index, const uint8_t *key,
const uint8_t *salt)
{
int ret = 0;
u32 set_req_len = 0;
u32 set_rsp_len = 0;
struct pfk_ice_key_req *set_req_buf;
struct pfk_ice_key_rsp *set_rsp_buf;
memcpy(ice_key, key, sizeof(ice_key));
memcpy(ice_salt, salt, sizeof(ice_salt));
if (!qhandle) {
ret = qseecom_start_app(&qhandle, "keymaster64",
CONTEXT_SIZE);
if (ret) {
pr_err("Qseecom start app failed\n");
return ret;
}
}
set_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf;
set_req_buf->cmd_id = KEYMASTER_SET_ICE_KEY;
set_req_buf->index = index;
set_req_buf->ice_key_offset = sizeof(struct pfk_ice_key_req);
set_req_buf->ice_key_size = ICE_KEY_SIZE;
set_req_buf->ice_salt_offset = set_req_buf->ice_key_offset +
set_req_buf->ice_key_size;
set_req_buf->ice_salt_size = ICE_SALT_SIZE;
memcpy((uint8_t *) set_req_buf + set_req_buf->ice_key_offset, ice_key,
set_req_buf->ice_key_size);
memcpy((uint8_t *) set_req_buf + set_req_buf->ice_salt_offset, ice_salt,
set_req_buf->ice_salt_size);
set_req_len = sizeof(struct pfk_ice_key_req) + set_req_buf->ice_key_size
+ set_req_buf->ice_salt_size;
set_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf +
set_req_len);
set_rsp_len = sizeof(struct pfk_ice_key_rsp);
ret = qseecom_send_command(qhandle,
set_req_buf, set_req_len,
set_rsp_buf, set_rsp_len);
if (ret)
pr_err("%s: Set wrapped key error: Status %d\n", __func__,
set_rsp_buf->ret);
return ret;
}
static int clear_wrapped_key(uint32_t index)
{
int ret = 0;
u32 clear_req_len = 0;
u32 clear_rsp_len = 0;
struct pfk_ice_key_req *clear_req_buf;
struct pfk_ice_key_rsp *clear_rsp_buf;
clear_req_buf = (struct pfk_ice_key_req *) qhandle->sbuf;
memset(clear_req_buf, 0, sizeof(qhandle->sbuf));
clear_req_buf->cmd_id = KEYMASTER_CLEAR_ICE_KEY;
clear_req_buf->index = index;
clear_req_len = sizeof(struct pfk_ice_key_req);
clear_rsp_buf = (struct pfk_ice_key_rsp *) (qhandle->sbuf +
QSEECOM_ALIGN(clear_req_len));
clear_rsp_len = sizeof(struct pfk_ice_key_rsp);
ret = qseecom_send_command(qhandle, clear_req_buf, clear_req_len,
clear_rsp_buf, clear_rsp_len);
if (ret)
pr_err("%s: Clear wrapped key error: Status %d\n", __func__,
clear_rsp_buf->ret);
return ret;
}
static int set_key(uint32_t index, const uint8_t *key, const uint8_t *salt)
{
struct scm_desc desc = {0};
int ret, ret1;
int ret = 0;
uint32_t smc_id = 0;
char *tzbuf_key = (char *)ice_key;
char *tzbuf_salt = (char *)ice_salt;
char *s_type = storage_type;
uint32_t smc_id = 0;
u32 tzbuflen_key = sizeof(ice_key);
u32 tzbuflen_salt = sizeof(ice_salt);
if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) {
pr_err("%s Invalid index %d\n", __func__, index);
return -EINVAL;
}
if (!key || !salt) {
pr_err("%s Invalid key/salt\n", __func__);
return -EINVAL;
}
if (!tzbuf_key || !tzbuf_salt) {
pr_err("%s No Memory\n", __func__);
return -ENOMEM;
}
if (s_type == NULL) {
pr_err("%s Invalid Storage type\n", __func__);
return -EINVAL;
}
memset(tzbuf_key, 0, tzbuflen_key);
memset(tzbuf_salt, 0, tzbuflen_salt);
memcpy(ice_key, key, tzbuflen_key);
memcpy(ice_salt, salt, tzbuflen_salt);
memcpy(ice_key, key, sizeof(ice_key));
memcpy(ice_salt, salt, sizeof(ice_salt));
dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key);
dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt);
@ -110,33 +182,84 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt,
desc.args[3] = virt_to_phys(tzbuf_salt);
desc.args[4] = tzbuflen_salt;
ret = scm_call2(smc_id, &desc);
if (ret)
pr_err("%s:SCM call Error: 0x%x\n", __func__, ret);
return ret;
}
static int clear_key(uint32_t index)
{
struct scm_desc desc = {0};
int ret = 0;
uint32_t smc_id = 0;
smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID;
desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID;
desc.args[0] = index;
ret = scm_call2(smc_id, &desc);
if (ret)
pr_err("%s:SCM call Error: 0x%x\n", __func__, ret);
return ret;
}
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt,
char *storage_type)
{
int ret = 0, ret1 = 0;
char *s_type = storage_type;
if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) {
pr_err("%s Invalid index %d\n", __func__, index);
return -EINVAL;
}
if (!key || !salt) {
pr_err("%s Invalid key/salt\n", __func__);
return -EINVAL;
}
if (s_type == NULL) {
pr_err("%s Invalid Storage type\n", __func__);
return -EINVAL;
}
ret = qcom_ice_setup_ice_hw((const char *)s_type, true);
if (ret) {
pr_err("%s: could not enable clocks: %d\n", __func__, ret);
goto out;
}
ret = scm_call2(smc_id, &desc);
if (pfk_wrapped_key_supported()) {
pr_debug("%s: Setting wrapped key\n", __func__);
ret = set_wrapped_key(index, key, salt);
} else {
pr_debug("%s: Setting keys with QSEE kernel\n", __func__);
ret = set_key(index, key, salt);
}
if (ret) {
pr_err("%s: Set Key Error: %d\n", __func__, ret);
if (ret == -EBUSY) {
if (qcom_ice_setup_ice_hw((const char *)s_type, false))
pr_err("%s: clock disable failed\n", __func__);
goto out;
goto out;
}
/* Try to invalidate the key to keep ICE in proper state */
smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID;
desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID;
desc.args[0] = index;
ret1 = scm_call2(smc_id, &desc);
if (pfk_wrapped_key_supported())
ret1 = clear_wrapped_key(index);
else
ret1 = clear_key(index);
if (ret1)
pr_err("%s: Invalidate Key Error: %d\n", __func__,
ret1);
pr_err("%s: Invalidate key error: %d\n", __func__, ret);
}
ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false);
if (ret1)
pr_err("%s: Error %d disabling clocks\n", __func__, ret1);
if (ret)
pr_err("%s: Error %d disabling clocks\n", __func__, ret);
out:
return ret;
@ -144,11 +267,8 @@ out:
int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type)
{
struct scm_desc desc = {0};
int ret = 0;
uint32_t smc_id = 0;
if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX) {
pr_err("%s Invalid index %d\n", __func__, index);
return -EINVAL;
@ -159,20 +279,22 @@ int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type)
return -EINVAL;
}
smc_id = TZ_ES_INVALIDATE_ICE_KEY_ID;
desc.arginfo = TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID;
desc.args[0] = index;
ret = qcom_ice_setup_ice_hw((const char *)storage_type, true);
if (ret) {
pr_err("%s: could not enable clocks: 0x%x\n", __func__, ret);
return ret;
}
ret = scm_call2(smc_id, &desc);
if (pfk_wrapped_key_supported()) {
ret = clear_wrapped_key(index);
pr_debug("%s: Clearing wrapped key\n", __func__);
} else {
pr_debug("%s: Clearing keys with QSEE kernel\n", __func__);
ret = clear_key(index);
}
if (ret)
pr_err("%s: Error: 0x%x\n", __func__, ret);
pr_err("%s: Invalidate key error: %d\n", __func__, ret);
if (qcom_ice_setup_ice_hw((const char *)storage_type, false))
pr_err("%s: could not disable clocks\n", __func__);

View File

@ -22,9 +22,35 @@
#include <linux/types.h>
struct __attribute__ ((__packed__)) pfk_ice_key_req {
uint32_t cmd_id;
uint32_t index;
uint32_t ice_key_offset;
uint32_t ice_key_size;
uint32_t ice_salt_offset;
uint32_t ice_salt_size;
};
struct __attribute__ ((__packed__)) pfk_ice_key_rsp {
uint32_t ret;
uint32_t cmd_id;
};
int pfk_ice_init(void);
int pfk_ice_deinit(void);
#ifdef CONFIG_PFK_WRAPPED_KEY_SUPPORTED
static inline bool pfk_wrapped_key_supported(void)
{
return true;
}
#else
static inline bool pfk_wrapped_key_supported(void)
{
return false;
}
#endif
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt,
char *storage_type);
int qti_pfk_ice_invalidate_key(uint32_t index, char *storage_type);

View File

@ -435,6 +435,7 @@ int pfk_kc_init(void)
}
kc_ready = true;
kc_spin_unlock();
return 0;
}
@ -448,6 +449,7 @@ int pfk_kc_deinit(void)
int res = pfk_kc_clear();
kc_ready = false;
return res;
}

View File

@ -613,7 +613,7 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode
EXPORT_SYMBOL_GPL(security_inode_create);
int security_inode_post_create(struct inode *dir, struct dentry *dentry,
umode_t mode)
umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;

View File

@ -66,7 +66,7 @@ struct inode_security_struct {
u16 sclass; /* security class of this object */
unsigned char initialized; /* initialization flag */
u32 tag; /* Per-File-Encryption tag */
void *pfk_data; /* Per-File-Key data from ecryptfs */
void *pfk_data; /* Per-File-Key data from ecryptfs */
spinlock_t lock;
};

View File

@ -13,6 +13,7 @@
#include <linux/dcache.h>
#include <linux/magic.h>
#include <linux/types.h>
//#include "flask.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */
#define SECSID_WILD 0xffffffff /* wildcard SID */