mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge "Enable hardware based FBE on f2fs and adapt ext4 fs"
This commit is contained in:
commit
7803301623
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -773,4 +773,5 @@ config CRYPTO_DEV_ARTPEC6
|
||||
if ARCH_QCOM
|
||||
source drivers/crypto/msm/Kconfig
|
||||
endif
|
||||
|
||||
endif # CRYPTO_HW
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
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 */
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -2,7 +2,6 @@
|
||||
#
|
||||
# Makefile for the linux ext4-filesystem routines.
|
||||
#
|
||||
ccflags-y += -Ifs/crypto
|
||||
|
||||
obj-$(CONFIG_EXT4_FS) += ext4.o
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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| \
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
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_ */
|
@ -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__);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user