Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.15.y' into android14-5.15
* aosp/upstream-f2fs-stable-linux-5.15.y:
f2fs: let's avoid panic if extent_tree is not created
f2fs: should use a temp extent_info for lookup
f2fs: don't mix to use union values in extent_info
f2fs: initialize extent_cache parameter
f2fs: fix to avoid NULL pointer dereference in f2fs_issue_flush()
fs: account for group membership
fs: fix acl translation
fs: support mapped mounts of mapped filesystems
fs: add i_user_ns() helper
fs: port higher-level mapping helpers
fs: remove unused low-level mapping helpers
fs: use low-level mapping helpers
docs: update mapping documentation
fs: account for filesystem mappings
fs: tweak fsuidgid_has_mapping()
fs: move mapping helpers
fs: add is_idmapped_mnt() helper
Revert "fs: add is_idmapped_mnt() helper"
Revert "fs: move mapping helpers"
Revert "fs: tweak fsuidgid_has_mapping()"
Revert "fs: account for filesystem mappings"
Revert "docs: update mapping documentation"
Revert "fs: use low-level mapping helpers"
Revert "fs: remove unused low-level mapping helpers"
Revert "fs: add i_user_ns() helper"
Revert "fs: account for group membership"
fsverity: simplify fsverity_get_digest()
fsverity: stop using PG_error to track error status
fs-verity: use kmap_local_page() instead of kmap()
highmem: Make __kunmap_{local,atomic}() take const void pointer
fs-verity: use memcpy_from_page()
fs-verity: Use struct_size() helper in enable_verity()
fs-verity: remove unused parameter desc_size in fsverity_create_info()
fs-verity: define a function to return the integrity protected file digest
fscrypt: add additional documentation for SM4 support
fscrypt: remove unused Speck definitions
fscrypt: Add SM4 XTS/CTS symmetric algorithm support
blk-crypto: Add support for SM4-XTS blk crypto mode
fscrypt: add comment for fscrypt_valid_enc_modes_v1()
blk-crypto: Add a missing include directive
blk-crypto: move internal only declarations to blk-crypto-internal.h
blk-crypto: add a blk_crypto_config_supported_natively helper
blk-crypto: don't use struct request_queue for public interfaces
fscrypt: pass super_block to fscrypt_put_master_key_activeref()
fscrypt: add fscrypt_context_for_new_inode
fscrypt: export fscrypt_fname_encrypt and fscrypt_fname_encrypted_size
fscrypt: Add HCTR2 support for filename encryption
fs: account for group membership
fs: add i_user_ns() helper
fs: remove unused low-level mapping helpers
fs: use low-level mapping helpers
docs: update mapping documentation
fs: account for filesystem mappings
fs: tweak fsuidgid_has_mapping()
fs: move mapping helpers
fs: add is_idmapped_mnt() helper
Bug: 256243893
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
Change-Id: Ia7b419ef516dee40be32968cd7c60ce0adabca99
This commit is contained in:
@@ -338,6 +338,7 @@ Currently, the following pairs of encryption modes are supported:
|
|||||||
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames
|
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames
|
||||||
- Adiantum for both contents and filenames
|
- Adiantum for both contents and filenames
|
||||||
- AES-256-XTS for contents and AES-256-HCTR2 for filenames (v2 policies only)
|
- AES-256-XTS for contents and AES-256-HCTR2 for filenames (v2 policies only)
|
||||||
|
- SM4-XTS for contents and SM4-CTS-CBC for filenames (v2 policies only)
|
||||||
|
|
||||||
If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
|
If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair.
|
||||||
|
|
||||||
@@ -369,6 +370,12 @@ CONFIG_CRYPTO_HCTR2 must be enabled. Also, fast implementations of XCTR and
|
|||||||
POLYVAL should be enabled, e.g. CRYPTO_POLYVAL_ARM64_CE and
|
POLYVAL should be enabled, e.g. CRYPTO_POLYVAL_ARM64_CE and
|
||||||
CRYPTO_AES_ARM64_CE_BLK for ARM64.
|
CRYPTO_AES_ARM64_CE_BLK for ARM64.
|
||||||
|
|
||||||
|
SM4 is a Chinese block cipher that is an alternative to AES. It has
|
||||||
|
not seen as much security review as AES, and it only has a 128-bit key
|
||||||
|
size. It may be useful in cases where its use is mandated.
|
||||||
|
Otherwise, it should not be used. For SM4 support to be available, it
|
||||||
|
also needs to be enabled in the kernel crypto API.
|
||||||
|
|
||||||
New encryption modes can be added relatively easily, without changes
|
New encryption modes can be added relatively easily, without changes
|
||||||
to individual filesystems. However, authenticated encryption (AE)
|
to individual filesystems. However, authenticated encryption (AE)
|
||||||
modes are not currently supported because of the difficulty of dealing
|
modes are not currently supported because of the difficulty of dealing
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void flush_kernel_icache_range_asm(unsigned long, unsigned long);
|
|||||||
void flush_user_dcache_range_asm(unsigned long, unsigned long);
|
void flush_user_dcache_range_asm(unsigned long, unsigned long);
|
||||||
void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
|
void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
|
||||||
void purge_kernel_dcache_range_asm(unsigned long, unsigned long);
|
void purge_kernel_dcache_range_asm(unsigned long, unsigned long);
|
||||||
void flush_kernel_dcache_page_asm(void *);
|
void flush_kernel_dcache_page_asm(const void *addr);
|
||||||
void flush_kernel_icache_page(void *);
|
void flush_kernel_icache_page(void *);
|
||||||
|
|
||||||
/* Cache flush operations */
|
/* Cache flush operations */
|
||||||
@@ -36,7 +36,7 @@ void flush_cache_all_local(void);
|
|||||||
void flush_cache_all(void);
|
void flush_cache_all(void);
|
||||||
void flush_cache_mm(struct mm_struct *mm);
|
void flush_cache_mm(struct mm_struct *mm);
|
||||||
|
|
||||||
void flush_kernel_dcache_page_addr(void *addr);
|
void flush_kernel_dcache_page_addr(const void *addr);
|
||||||
|
|
||||||
#define flush_kernel_dcache_range(start,size) \
|
#define flush_kernel_dcache_range(start,size) \
|
||||||
flush_kernel_dcache_range_asm((start), (start)+(size));
|
flush_kernel_dcache_range_asm((start), (start)+(size));
|
||||||
@@ -97,7 +97,7 @@ flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vma
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define ARCH_HAS_FLUSH_ON_KUNMAP
|
#define ARCH_HAS_FLUSH_ON_KUNMAP
|
||||||
static inline void kunmap_flush_on_unmap(void *addr)
|
static inline void kunmap_flush_on_unmap(const void *addr)
|
||||||
{
|
{
|
||||||
flush_kernel_dcache_page_addr(addr);
|
flush_kernel_dcache_page_addr(addr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ extern void purge_kernel_dcache_page_asm(unsigned long);
|
|||||||
extern void clear_user_page_asm(void *, unsigned long);
|
extern void clear_user_page_asm(void *, unsigned long);
|
||||||
extern void copy_user_page_asm(void *, void *, unsigned long);
|
extern void copy_user_page_asm(void *, void *, unsigned long);
|
||||||
|
|
||||||
void flush_kernel_dcache_page_addr(void *addr)
|
void flush_kernel_dcache_page_addr(const void *addr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ const struct blk_crypto_mode blk_crypto_modes[] = {
|
|||||||
.security_strength = 32,
|
.security_strength = 32,
|
||||||
.ivsize = 32,
|
.ivsize = 32,
|
||||||
},
|
},
|
||||||
|
[BLK_ENCRYPTION_MODE_SM4_XTS] = {
|
||||||
|
.name = "SM4-XTS",
|
||||||
|
.cipher_str = "xts(sm4)",
|
||||||
|
.keysize = 32,
|
||||||
|
.security_strength = 16,
|
||||||
|
.ivsize = 16,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
|||||||
/**
|
/**
|
||||||
* fscrypt_fname_encrypt() - encrypt a filename
|
* fscrypt_fname_encrypt() - encrypt a filename
|
||||||
* @inode: inode of the parent directory (for regular filenames)
|
* @inode: inode of the parent directory (for regular filenames)
|
||||||
* or of the symlink (for symlink targets)
|
* or of the symlink (for symlink targets). Key must already be
|
||||||
|
* set up.
|
||||||
* @iname: the filename to encrypt
|
* @iname: the filename to encrypt
|
||||||
* @out: (output) the encrypted filename
|
* @out: (output) the encrypted filename
|
||||||
* @olen: size of the encrypted filename. It must be at least @iname->len.
|
* @olen: size of the encrypted filename. It must be at least @iname->len.
|
||||||
@@ -137,6 +138,7 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fscrypt_fname_encrypt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fname_decrypt() - decrypt a filename
|
* fname_decrypt() - decrypt a filename
|
||||||
@@ -264,9 +266,9 @@ static int fscrypt_base64url_decode(const char *src, int srclen, u8 *dst)
|
|||||||
return bp - dst;
|
return bp - dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
||||||
u32 orig_len, u32 max_len,
|
u32 orig_len, u32 max_len,
|
||||||
u32 *encrypted_len_ret)
|
u32 *encrypted_len_ret)
|
||||||
{
|
{
|
||||||
int padding = 4 << (fscrypt_policy_flags(policy) &
|
int padding = 4 << (fscrypt_policy_flags(policy) &
|
||||||
FSCRYPT_POLICY_FLAGS_PAD_MASK);
|
FSCRYPT_POLICY_FLAGS_PAD_MASK);
|
||||||
@@ -280,6 +282,29 @@ bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fscrypt_fname_encrypted_size() - calculate length of encrypted filename
|
||||||
|
* @inode: parent inode of dentry name being encrypted. Key must
|
||||||
|
* already be set up.
|
||||||
|
* @orig_len: length of the original filename
|
||||||
|
* @max_len: maximum length to return
|
||||||
|
* @encrypted_len_ret: where calculated length should be returned (on success)
|
||||||
|
*
|
||||||
|
* Filenames that are shorter than the maximum length may have their lengths
|
||||||
|
* increased slightly by encryption, due to padding that is applied.
|
||||||
|
*
|
||||||
|
* Return: false if the orig_len is greater than max_len. Otherwise, true and
|
||||||
|
* fill out encrypted_len_ret with the length (up to max_len).
|
||||||
|
*/
|
||||||
|
bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
|
||||||
|
u32 max_len, u32 *encrypted_len_ret)
|
||||||
|
{
|
||||||
|
return __fscrypt_fname_encrypted_size(&inode->i_crypt_info->ci_policy,
|
||||||
|
orig_len, max_len,
|
||||||
|
encrypted_len_ret);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fscrypt_fname_encrypted_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames
|
* fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames
|
||||||
* @max_encrypted_len: maximum length of encrypted filenames the buffer will be
|
* @max_encrypted_len: maximum length of encrypted filenames the buffer will be
|
||||||
@@ -435,8 +460,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (fscrypt_has_encryption_key(dir)) {
|
if (fscrypt_has_encryption_key(dir)) {
|
||||||
if (!fscrypt_fname_encrypted_size(&dir->i_crypt_info->ci_policy,
|
if (!fscrypt_fname_encrypted_size(dir, iname->len, NAME_MAX,
|
||||||
iname->len, NAME_MAX,
|
|
||||||
&fname->crypto_buf.len))
|
&fname->crypto_buf.len))
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
|
fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
|
||||||
|
|||||||
@@ -318,14 +318,11 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
|
|||||||
const struct fscrypt_info *ci);
|
const struct fscrypt_info *ci);
|
||||||
|
|
||||||
/* fname.c */
|
/* fname.c */
|
||||||
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
bool __fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
||||||
u8 *out, unsigned int olen);
|
u32 orig_len, u32 max_len,
|
||||||
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy,
|
u32 *encrypted_len_ret);
|
||||||
u32 orig_len, u32 max_len,
|
|
||||||
u32 *encrypted_len_ret);
|
|
||||||
|
|
||||||
/* hkdf.c */
|
/* hkdf.c */
|
||||||
|
|
||||||
struct fscrypt_hkdf {
|
struct fscrypt_hkdf {
|
||||||
struct crypto_shash *hmac_tfm;
|
struct crypto_shash *hmac_tfm;
|
||||||
};
|
};
|
||||||
@@ -498,13 +495,7 @@ struct fscrypt_master_key_secret {
|
|||||||
struct fscrypt_master_key {
|
struct fscrypt_master_key {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Back-pointer to the super_block of the filesystem to which this
|
* Link in ->s_master_keys->key_hashtable.
|
||||||
* master key has been added. Only valid if ->mk_active_refs > 0.
|
|
||||||
*/
|
|
||||||
struct super_block *mk_sb;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Link in ->mk_sb->s_master_keys->key_hashtable.
|
|
||||||
* Only valid if ->mk_active_refs > 0.
|
* Only valid if ->mk_active_refs > 0.
|
||||||
*/
|
*/
|
||||||
struct hlist_node mk_node;
|
struct hlist_node mk_node;
|
||||||
@@ -515,7 +506,7 @@ struct fscrypt_master_key {
|
|||||||
/*
|
/*
|
||||||
* Active and structural reference counts. An active ref guarantees
|
* Active and structural reference counts. An active ref guarantees
|
||||||
* that the struct continues to exist, continues to be in the keyring
|
* that the struct continues to exist, continues to be in the keyring
|
||||||
* ->mk_sb->s_master_keys, and that any embedded subkeys (e.g.
|
* ->s_master_keys, and that any embedded subkeys (e.g.
|
||||||
* ->mk_direct_keys) that have been prepared continue to exist.
|
* ->mk_direct_keys) that have been prepared continue to exist.
|
||||||
* A structural ref only guarantees that the struct continues to exist.
|
* A structural ref only guarantees that the struct continues to exist.
|
||||||
*
|
*
|
||||||
@@ -628,7 +619,8 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec)
|
|||||||
|
|
||||||
void fscrypt_put_master_key(struct fscrypt_master_key *mk);
|
void fscrypt_put_master_key(struct fscrypt_master_key *mk);
|
||||||
|
|
||||||
void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk);
|
void fscrypt_put_master_key_activeref(struct super_block *sb,
|
||||||
|
struct fscrypt_master_key *mk);
|
||||||
|
|
||||||
struct fscrypt_master_key *
|
struct fscrypt_master_key *
|
||||||
fscrypt_find_master_key(struct super_block *sb,
|
fscrypt_find_master_key(struct super_block *sb,
|
||||||
|
|||||||
@@ -224,9 +224,9 @@ int fscrypt_prepare_symlink(struct inode *dir, const char *target,
|
|||||||
* counting it (even though it is meaningless for ciphertext) is simpler
|
* counting it (even though it is meaningless for ciphertext) is simpler
|
||||||
* for now since filesystems will assume it is there and subtract it.
|
* for now since filesystems will assume it is there and subtract it.
|
||||||
*/
|
*/
|
||||||
if (!fscrypt_fname_encrypted_size(policy, len,
|
if (!__fscrypt_fname_encrypted_size(policy, len,
|
||||||
max_len - sizeof(struct fscrypt_symlink_data),
|
max_len - sizeof(struct fscrypt_symlink_data),
|
||||||
&disk_link->len))
|
&disk_link->len))
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
disk_link->len += sizeof(struct fscrypt_symlink_data);
|
disk_link->len += sizeof(struct fscrypt_symlink_data);
|
||||||
|
|
||||||
|
|||||||
@@ -79,10 +79,9 @@ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
|
|||||||
call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
|
call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk)
|
void fscrypt_put_master_key_activeref(struct super_block *sb,
|
||||||
|
struct fscrypt_master_key *mk)
|
||||||
{
|
{
|
||||||
struct super_block *sb = mk->mk_sb;
|
|
||||||
struct fscrypt_keyring *keyring = sb->s_master_keys;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!refcount_dec_and_test(&mk->mk_active_refs))
|
if (!refcount_dec_and_test(&mk->mk_active_refs))
|
||||||
@@ -93,9 +92,9 @@ void fscrypt_put_master_key_activeref(struct fscrypt_master_key *mk)
|
|||||||
* destroying any subkeys embedded in it.
|
* destroying any subkeys embedded in it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spin_lock(&keyring->lock);
|
spin_lock(&sb->s_master_keys->lock);
|
||||||
hlist_del_rcu(&mk->mk_node);
|
hlist_del_rcu(&mk->mk_node);
|
||||||
spin_unlock(&keyring->lock);
|
spin_unlock(&sb->s_master_keys->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ->mk_active_refs == 0 implies that ->mk_secret is not present and
|
* ->mk_active_refs == 0 implies that ->mk_secret is not present and
|
||||||
@@ -243,7 +242,7 @@ void fscrypt_destroy_keyring(struct super_block *sb)
|
|||||||
WARN_ON(refcount_read(&mk->mk_struct_refs) != 1);
|
WARN_ON(refcount_read(&mk->mk_struct_refs) != 1);
|
||||||
WARN_ON(!is_master_key_secret_present(&mk->mk_secret));
|
WARN_ON(!is_master_key_secret_present(&mk->mk_secret));
|
||||||
wipe_master_key_secret(&mk->mk_secret);
|
wipe_master_key_secret(&mk->mk_secret);
|
||||||
fscrypt_put_master_key_activeref(mk);
|
fscrypt_put_master_key_activeref(sb, mk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree_sensitive(keyring);
|
kfree_sensitive(keyring);
|
||||||
@@ -424,7 +423,6 @@ static int add_new_master_key(struct super_block *sb,
|
|||||||
if (!mk)
|
if (!mk)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
mk->mk_sb = sb;
|
|
||||||
init_rwsem(&mk->mk_sem);
|
init_rwsem(&mk->mk_sem);
|
||||||
refcount_set(&mk->mk_struct_refs, 1);
|
refcount_set(&mk->mk_struct_refs, 1);
|
||||||
mk->mk_spec = *mk_spec;
|
mk->mk_spec = *mk_spec;
|
||||||
@@ -1099,7 +1097,7 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
|
|||||||
err = -ENOKEY;
|
err = -ENOKEY;
|
||||||
if (is_master_key_secret_present(&mk->mk_secret)) {
|
if (is_master_key_secret_present(&mk->mk_secret)) {
|
||||||
wipe_master_key_secret(&mk->mk_secret);
|
wipe_master_key_secret(&mk->mk_secret);
|
||||||
fscrypt_put_master_key_activeref(mk);
|
fscrypt_put_master_key_activeref(sb, mk);
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
inodes_remain = refcount_read(&mk->mk_active_refs) > 0;
|
inodes_remain = refcount_read(&mk->mk_active_refs) > 0;
|
||||||
|
|||||||
@@ -44,6 +44,21 @@ struct fscrypt_mode fscrypt_modes[] = {
|
|||||||
.security_strength = 16,
|
.security_strength = 16,
|
||||||
.ivsize = 16,
|
.ivsize = 16,
|
||||||
},
|
},
|
||||||
|
[FSCRYPT_MODE_SM4_XTS] = {
|
||||||
|
.friendly_name = "SM4-XTS",
|
||||||
|
.cipher_str = "xts(sm4)",
|
||||||
|
.keysize = 32,
|
||||||
|
.security_strength = 16,
|
||||||
|
.ivsize = 16,
|
||||||
|
.blk_crypto_mode = BLK_ENCRYPTION_MODE_SM4_XTS,
|
||||||
|
},
|
||||||
|
[FSCRYPT_MODE_SM4_CTS] = {
|
||||||
|
.friendly_name = "SM4-CTS-CBC",
|
||||||
|
.cipher_str = "cts(cbc(sm4))",
|
||||||
|
.keysize = 16,
|
||||||
|
.security_strength = 16,
|
||||||
|
.ivsize = 16,
|
||||||
|
},
|
||||||
[FSCRYPT_MODE_ADIANTUM] = {
|
[FSCRYPT_MODE_ADIANTUM] = {
|
||||||
.friendly_name = "Adiantum",
|
.friendly_name = "Adiantum",
|
||||||
.cipher_str = "adiantum(xchacha12,aes)",
|
.cipher_str = "adiantum(xchacha12,aes)",
|
||||||
@@ -556,7 +571,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
|
|||||||
spin_lock(&mk->mk_decrypted_inodes_lock);
|
spin_lock(&mk->mk_decrypted_inodes_lock);
|
||||||
list_del(&ci->ci_master_key_link);
|
list_del(&ci->ci_master_key_link);
|
||||||
spin_unlock(&mk->mk_decrypted_inodes_lock);
|
spin_unlock(&mk->mk_decrypted_inodes_lock);
|
||||||
fscrypt_put_master_key_activeref(mk);
|
fscrypt_put_master_key_activeref(ci->ci_inode->i_sb, mk);
|
||||||
}
|
}
|
||||||
memzero_explicit(ci, sizeof(*ci));
|
memzero_explicit(ci, sizeof(*ci));
|
||||||
kmem_cache_free(fscrypt_info_cachep, ci);
|
kmem_cache_free(fscrypt_info_cachep, ci);
|
||||||
|
|||||||
@@ -61,6 +61,13 @@ fscrypt_get_dummy_policy(struct super_block *sb)
|
|||||||
return sb->s_cop->get_dummy_policy(sb);
|
return sb->s_cop->get_dummy_policy(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return %true if the given combination of encryption modes is supported for v1
|
||||||
|
* (and later) encryption policies.
|
||||||
|
*
|
||||||
|
* Do *not* add anything new here, since v1 encryption policies are deprecated.
|
||||||
|
* New combinations of modes should go in fscrypt_valid_enc_modes_v2() only.
|
||||||
|
*/
|
||||||
static bool fscrypt_valid_enc_modes_v1(u32 contents_mode, u32 filenames_mode)
|
static bool fscrypt_valid_enc_modes_v1(u32 contents_mode, u32 filenames_mode)
|
||||||
{
|
{
|
||||||
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
||||||
@@ -83,6 +90,11 @@ static bool fscrypt_valid_enc_modes_v2(u32 contents_mode, u32 filenames_mode)
|
|||||||
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
if (contents_mode == FSCRYPT_MODE_AES_256_XTS &&
|
||||||
filenames_mode == FSCRYPT_MODE_AES_256_HCTR2)
|
filenames_mode == FSCRYPT_MODE_AES_256_HCTR2)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (contents_mode == FSCRYPT_MODE_SM4_XTS &&
|
||||||
|
filenames_mode == FSCRYPT_MODE_SM4_CTS)
|
||||||
|
return true;
|
||||||
|
|
||||||
return fscrypt_valid_enc_modes_v1(contents_mode, filenames_mode);
|
return fscrypt_valid_enc_modes_v1(contents_mode, filenames_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,6 +705,32 @@ const union fscrypt_policy *fscrypt_policy_to_inherit(struct inode *dir)
|
|||||||
return fscrypt_get_dummy_policy(dir->i_sb);
|
return fscrypt_get_dummy_policy(dir->i_sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fscrypt_context_for_new_inode() - create an encryption context for a new inode
|
||||||
|
* @ctx: where context should be written
|
||||||
|
* @inode: inode from which to fetch policy and nonce
|
||||||
|
*
|
||||||
|
* Given an in-core "prepared" (via fscrypt_prepare_new_inode) inode,
|
||||||
|
* generate a new context and write it to ctx. ctx _must_ be at least
|
||||||
|
* FSCRYPT_SET_CONTEXT_MAX_SIZE bytes.
|
||||||
|
*
|
||||||
|
* Return: size of the resulting context or a negative error code.
|
||||||
|
*/
|
||||||
|
int fscrypt_context_for_new_inode(void *ctx, struct inode *inode)
|
||||||
|
{
|
||||||
|
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(sizeof(union fscrypt_context) !=
|
||||||
|
FSCRYPT_SET_CONTEXT_MAX_SIZE);
|
||||||
|
|
||||||
|
/* fscrypt_prepare_new_inode() should have set up the key already. */
|
||||||
|
if (WARN_ON_ONCE(!ci))
|
||||||
|
return -ENOKEY;
|
||||||
|
|
||||||
|
return fscrypt_new_context(ctx, &ci->ci_policy, ci->ci_nonce);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(fscrypt_context_for_new_inode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fscrypt_set_context() - Set the fscrypt context of a new inode
|
* fscrypt_set_context() - Set the fscrypt context of a new inode
|
||||||
* @inode: a new inode
|
* @inode: a new inode
|
||||||
@@ -709,12 +747,9 @@ int fscrypt_set_context(struct inode *inode, void *fs_data)
|
|||||||
union fscrypt_context ctx;
|
union fscrypt_context ctx;
|
||||||
int ctxsize;
|
int ctxsize;
|
||||||
|
|
||||||
/* fscrypt_prepare_new_inode() should have set up the key already. */
|
ctxsize = fscrypt_context_for_new_inode(&ctx, inode);
|
||||||
if (WARN_ON_ONCE(!ci))
|
if (ctxsize < 0)
|
||||||
return -ENOKEY;
|
return ctxsize;
|
||||||
|
|
||||||
BUILD_BUG_ON(sizeof(ctx) != FSCRYPT_SET_CONTEXT_MAX_SIZE);
|
|
||||||
ctxsize = fscrypt_new_context(&ctx, &ci->ci_policy, ci->ci_nonce);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This may be the first time the inode number is available, so do any
|
* This may be the first time the inode number is available, so do any
|
||||||
|
|||||||
@@ -76,14 +76,10 @@ static void __read_end_io(struct bio *bio)
|
|||||||
bio_for_each_segment_all(bv, bio, iter_all) {
|
bio_for_each_segment_all(bv, bio, iter_all) {
|
||||||
page = bv->bv_page;
|
page = bv->bv_page;
|
||||||
|
|
||||||
/* PG_error was set if verity failed. */
|
if (bio->bi_status)
|
||||||
if (bio->bi_status || PageError(page)) {
|
|
||||||
ClearPageUptodate(page);
|
ClearPageUptodate(page);
|
||||||
/* will re-read again later */
|
else
|
||||||
ClearPageError(page);
|
|
||||||
} else {
|
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
}
|
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
}
|
}
|
||||||
if (bio->bi_private)
|
if (bio->bi_private)
|
||||||
|
|||||||
@@ -1707,50 +1707,27 @@ static void f2fs_put_dic(struct decompress_io_ctx *dic, bool in_task)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Update and unlock the cluster's pagecache pages, and release the reference to
|
|
||||||
* the decompress_io_ctx that was being held for I/O completion.
|
|
||||||
*/
|
|
||||||
static void __f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
|
|
||||||
bool in_task)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < dic->cluster_size; i++) {
|
|
||||||
struct page *rpage = dic->rpages[i];
|
|
||||||
|
|
||||||
if (!rpage)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* PG_error was set if verity failed. */
|
|
||||||
if (failed || PageError(rpage)) {
|
|
||||||
ClearPageUptodate(rpage);
|
|
||||||
/* will re-read again later */
|
|
||||||
ClearPageError(rpage);
|
|
||||||
} else {
|
|
||||||
SetPageUptodate(rpage);
|
|
||||||
}
|
|
||||||
unlock_page(rpage);
|
|
||||||
}
|
|
||||||
|
|
||||||
f2fs_put_dic(dic, in_task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f2fs_verify_cluster(struct work_struct *work)
|
static void f2fs_verify_cluster(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct decompress_io_ctx *dic =
|
struct decompress_io_ctx *dic =
|
||||||
container_of(work, struct decompress_io_ctx, verity_work);
|
container_of(work, struct decompress_io_ctx, verity_work);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Verify the cluster's decompressed pages with fs-verity. */
|
/* Verify, update, and unlock the decompressed pages. */
|
||||||
for (i = 0; i < dic->cluster_size; i++) {
|
for (i = 0; i < dic->cluster_size; i++) {
|
||||||
struct page *rpage = dic->rpages[i];
|
struct page *rpage = dic->rpages[i];
|
||||||
|
|
||||||
if (rpage && !fsverity_verify_page(rpage))
|
if (!rpage)
|
||||||
SetPageError(rpage);
|
continue;
|
||||||
|
|
||||||
|
if (fsverity_verify_page(rpage))
|
||||||
|
SetPageUptodate(rpage);
|
||||||
|
else
|
||||||
|
ClearPageUptodate(rpage);
|
||||||
|
unlock_page(rpage);
|
||||||
}
|
}
|
||||||
|
|
||||||
__f2fs_decompress_end_io(dic, false, true);
|
f2fs_put_dic(dic, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1760,6 +1737,8 @@ static void f2fs_verify_cluster(struct work_struct *work)
|
|||||||
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
|
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
|
||||||
bool in_task)
|
bool in_task)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!failed && dic->need_verity) {
|
if (!failed && dic->need_verity) {
|
||||||
/*
|
/*
|
||||||
* Note that to avoid deadlocks, the verity work can't be done
|
* Note that to avoid deadlocks, the verity work can't be done
|
||||||
@@ -1769,9 +1748,28 @@ void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed,
|
|||||||
*/
|
*/
|
||||||
INIT_WORK(&dic->verity_work, f2fs_verify_cluster);
|
INIT_WORK(&dic->verity_work, f2fs_verify_cluster);
|
||||||
fsverity_enqueue_verify_work(&dic->verity_work);
|
fsverity_enqueue_verify_work(&dic->verity_work);
|
||||||
} else {
|
return;
|
||||||
__f2fs_decompress_end_io(dic, failed, in_task);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update and unlock the cluster's pagecache pages. */
|
||||||
|
for (i = 0; i < dic->cluster_size; i++) {
|
||||||
|
struct page *rpage = dic->rpages[i];
|
||||||
|
|
||||||
|
if (!rpage)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (failed)
|
||||||
|
ClearPageUptodate(rpage);
|
||||||
|
else
|
||||||
|
SetPageUptodate(rpage);
|
||||||
|
unlock_page(rpage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Release the reference to the decompress_io_ctx that was being held
|
||||||
|
* for I/O completion.
|
||||||
|
*/
|
||||||
|
f2fs_put_dic(dic, in_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -115,43 +115,56 @@ struct bio_post_read_ctx {
|
|||||||
struct f2fs_sb_info *sbi;
|
struct f2fs_sb_info *sbi;
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
unsigned int enabled_steps;
|
unsigned int enabled_steps;
|
||||||
|
/*
|
||||||
|
* decompression_attempted keeps track of whether
|
||||||
|
* f2fs_end_read_compressed_page() has been called on the pages in the
|
||||||
|
* bio that belong to a compressed cluster yet.
|
||||||
|
*/
|
||||||
|
bool decompression_attempted;
|
||||||
block_t fs_blkaddr;
|
block_t fs_blkaddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update and unlock a bio's pages, and free the bio.
|
||||||
|
*
|
||||||
|
* This marks pages up-to-date only if there was no error in the bio (I/O error,
|
||||||
|
* decryption error, or verity error), as indicated by bio->bi_status.
|
||||||
|
*
|
||||||
|
* "Compressed pages" (pagecache pages backed by a compressed cluster on-disk)
|
||||||
|
* aren't marked up-to-date here, as decompression is done on a per-compression-
|
||||||
|
* cluster basis rather than a per-bio basis. Instead, we only must do two
|
||||||
|
* things for each compressed page here: call f2fs_end_read_compressed_page()
|
||||||
|
* with failed=true if an error occurred before it would have normally gotten
|
||||||
|
* called (i.e., I/O error or decryption error, but *not* verity error), and
|
||||||
|
* release the bio's reference to the decompress_io_ctx of the page's cluster.
|
||||||
|
*/
|
||||||
static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
|
static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
|
||||||
{
|
{
|
||||||
struct bio_vec *bv;
|
struct bio_vec *bv;
|
||||||
struct bvec_iter_all iter_all;
|
struct bvec_iter_all iter_all;
|
||||||
|
struct bio_post_read_ctx *ctx = bio->bi_private;
|
||||||
|
|
||||||
/*
|
|
||||||
* Update and unlock the bio's pagecache pages, and put the
|
|
||||||
* decompression context for any compressed pages.
|
|
||||||
*/
|
|
||||||
bio_for_each_segment_all(bv, bio, iter_all) {
|
bio_for_each_segment_all(bv, bio, iter_all) {
|
||||||
struct page *page = bv->bv_page;
|
struct page *page = bv->bv_page;
|
||||||
|
|
||||||
if (f2fs_is_compressed_page(page)) {
|
if (f2fs_is_compressed_page(page)) {
|
||||||
if (bio->bi_status)
|
if (ctx && !ctx->decompression_attempted)
|
||||||
f2fs_end_read_compressed_page(page, true, 0,
|
f2fs_end_read_compressed_page(page, true, 0,
|
||||||
in_task);
|
in_task);
|
||||||
f2fs_put_page_dic(page, in_task);
|
f2fs_put_page_dic(page, in_task);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PG_error was set if verity failed. */
|
if (bio->bi_status)
|
||||||
if (bio->bi_status || PageError(page)) {
|
|
||||||
ClearPageUptodate(page);
|
ClearPageUptodate(page);
|
||||||
/* will re-read again later */
|
else
|
||||||
ClearPageError(page);
|
|
||||||
} else {
|
|
||||||
SetPageUptodate(page);
|
SetPageUptodate(page);
|
||||||
}
|
|
||||||
dec_page_count(F2FS_P_SB(page), __read_io_type(page));
|
dec_page_count(F2FS_P_SB(page), __read_io_type(page));
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bio->bi_private)
|
if (ctx)
|
||||||
mempool_free(bio->bi_private, bio_post_read_ctx_pool);
|
mempool_free(ctx, bio_post_read_ctx_pool);
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,8 +197,10 @@ static void f2fs_verify_bio(struct work_struct *work)
|
|||||||
struct page *page = bv->bv_page;
|
struct page *page = bv->bv_page;
|
||||||
|
|
||||||
if (!f2fs_is_compressed_page(page) &&
|
if (!f2fs_is_compressed_page(page) &&
|
||||||
!fsverity_verify_page(page))
|
!fsverity_verify_page(page)) {
|
||||||
SetPageError(page);
|
bio->bi_status = BLK_STS_IOERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fsverity_verify_bio(bio);
|
fsverity_verify_bio(bio);
|
||||||
@@ -244,6 +259,8 @@ static void f2fs_handle_step_decompress(struct bio_post_read_ctx *ctx,
|
|||||||
blkaddr++;
|
blkaddr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx->decompression_attempted = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optimization: if all the bio's pages are compressed, then scheduling
|
* Optimization: if all the bio's pages are compressed, then scheduling
|
||||||
* the per-bio verity work is unnecessary, as verity will be fully
|
* the per-bio verity work is unnecessary, as verity will be fully
|
||||||
@@ -1066,6 +1083,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
|
|||||||
ctx->sbi = sbi;
|
ctx->sbi = sbi;
|
||||||
ctx->enabled_steps = post_read_steps;
|
ctx->enabled_steps = post_read_steps;
|
||||||
ctx->fs_blkaddr = blkaddr;
|
ctx->fs_blkaddr = blkaddr;
|
||||||
|
ctx->decompression_attempted = false;
|
||||||
bio->bi_private = ctx;
|
bio->bi_private = ctx;
|
||||||
}
|
}
|
||||||
iostat_alloc_and_bind_ctx(sbi, bio, ctx);
|
iostat_alloc_and_bind_ctx(sbi, bio, ctx);
|
||||||
@@ -1092,7 +1110,6 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
|
|||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
ClearPageError(page);
|
|
||||||
inc_page_count(sbi, F2FS_RD_DATA);
|
inc_page_count(sbi, F2FS_RD_DATA);
|
||||||
f2fs_update_iostat(sbi, NULL, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
f2fs_update_iostat(sbi, NULL, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||||
__submit_bio(sbi, bio, DATA);
|
__submit_bio(sbi, bio, DATA);
|
||||||
@@ -2157,7 +2174,6 @@ submit_and_realloc:
|
|||||||
inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
|
inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
|
||||||
f2fs_update_iostat(F2FS_I_SB(inode), NULL, FS_DATA_READ_IO,
|
f2fs_update_iostat(F2FS_I_SB(inode), NULL, FS_DATA_READ_IO,
|
||||||
F2FS_BLKSIZE);
|
F2FS_BLKSIZE);
|
||||||
ClearPageError(page);
|
|
||||||
*last_block_in_bio = block_nr;
|
*last_block_in_bio = block_nr;
|
||||||
goto out;
|
goto out;
|
||||||
confused:
|
confused:
|
||||||
@@ -2184,7 +2200,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
|||||||
sector_t last_block_in_file;
|
sector_t last_block_in_file;
|
||||||
const unsigned blocksize = blks_to_bytes(inode, 1);
|
const unsigned blocksize = blks_to_bytes(inode, 1);
|
||||||
struct decompress_io_ctx *dic = NULL;
|
struct decompress_io_ctx *dic = NULL;
|
||||||
struct extent_info ei = {0, };
|
struct extent_info ei = {};
|
||||||
bool from_dnode = true;
|
bool from_dnode = true;
|
||||||
int i;
|
int i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -2311,7 +2327,6 @@ submit_and_realloc:
|
|||||||
|
|
||||||
inc_page_count(sbi, F2FS_RD_DATA);
|
inc_page_count(sbi, F2FS_RD_DATA);
|
||||||
f2fs_update_iostat(sbi, inode, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
f2fs_update_iostat(sbi, inode, FS_DATA_READ_IO, F2FS_BLKSIZE);
|
||||||
ClearPageError(page);
|
|
||||||
*last_block_in_bio = blkaddr;
|
*last_block_in_bio = blkaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2328,7 +2343,6 @@ out:
|
|||||||
for (i = 0; i < cc->cluster_size; i++) {
|
for (i = 0; i < cc->cluster_size; i++) {
|
||||||
if (cc->rpages[i]) {
|
if (cc->rpages[i]) {
|
||||||
ClearPageUptodate(cc->rpages[i]);
|
ClearPageUptodate(cc->rpages[i]);
|
||||||
ClearPageError(cc->rpages[i]);
|
|
||||||
unlock_page(cc->rpages[i]);
|
unlock_page(cc->rpages[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2425,7 +2439,6 @@ read_single_page:
|
|||||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||||
set_error_page:
|
set_error_page:
|
||||||
#endif
|
#endif
|
||||||
SetPageError(page);
|
|
||||||
zero_user_segment(page, 0, PAGE_SIZE);
|
zero_user_segment(page, 0, PAGE_SIZE);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -546,7 +546,8 @@ static bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
|
|||||||
struct extent_node *en;
|
struct extent_node *en;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
f2fs_bug_on(sbi, !et);
|
if (!et)
|
||||||
|
return false;
|
||||||
|
|
||||||
trace_f2fs_lookup_extent_tree_start(inode, pgofs, type);
|
trace_f2fs_lookup_extent_tree_start(inode, pgofs, type);
|
||||||
|
|
||||||
@@ -881,12 +882,14 @@ static unsigned long long __calculate_block_age(unsigned long long new,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This returns a new age and allocated blocks in ei */
|
/* This returns a new age and allocated blocks in ei */
|
||||||
static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
|
static int __get_new_block_age(struct inode *inode, struct extent_info *ei,
|
||||||
|
block_t blkaddr)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
loff_t f_size = i_size_read(inode);
|
loff_t f_size = i_size_read(inode);
|
||||||
unsigned long long cur_blocks =
|
unsigned long long cur_blocks =
|
||||||
atomic64_read(&sbi->allocated_data_blocks);
|
atomic64_read(&sbi->allocated_data_blocks);
|
||||||
|
struct extent_info tei = *ei; /* only fofs and len are valid */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When I/O is not aligned to a PAGE_SIZE, update will happen to the last
|
* When I/O is not aligned to a PAGE_SIZE, update will happen to the last
|
||||||
@@ -894,20 +897,20 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
|
|||||||
* block here.
|
* block here.
|
||||||
*/
|
*/
|
||||||
if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) &&
|
if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) &&
|
||||||
ei->blk == NEW_ADDR)
|
blkaddr == NEW_ADDR)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (__lookup_extent_tree(inode, ei->fofs, ei, EX_BLOCK_AGE)) {
|
if (__lookup_extent_tree(inode, ei->fofs, &tei, EX_BLOCK_AGE)) {
|
||||||
unsigned long long cur_age;
|
unsigned long long cur_age;
|
||||||
|
|
||||||
if (cur_blocks >= ei->last_blocks)
|
if (cur_blocks >= tei.last_blocks)
|
||||||
cur_age = cur_blocks - ei->last_blocks;
|
cur_age = cur_blocks - tei.last_blocks;
|
||||||
else
|
else
|
||||||
/* allocated_data_blocks overflow */
|
/* allocated_data_blocks overflow */
|
||||||
cur_age = ULLONG_MAX - ei->last_blocks + cur_blocks;
|
cur_age = ULLONG_MAX - tei.last_blocks + cur_blocks;
|
||||||
|
|
||||||
if (ei->age)
|
if (tei.age)
|
||||||
ei->age = __calculate_block_age(cur_age, ei->age);
|
ei->age = __calculate_block_age(cur_age, tei.age);
|
||||||
else
|
else
|
||||||
ei->age = cur_age;
|
ei->age = cur_age;
|
||||||
ei->last_blocks = cur_blocks;
|
ei->last_blocks = cur_blocks;
|
||||||
@@ -915,14 +918,14 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
f2fs_bug_on(sbi, ei->blk == NULL_ADDR);
|
f2fs_bug_on(sbi, blkaddr == NULL_ADDR);
|
||||||
|
|
||||||
/* the data block was allocated for the first time */
|
/* the data block was allocated for the first time */
|
||||||
if (ei->blk == NEW_ADDR)
|
if (blkaddr == NEW_ADDR)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (__is_valid_data_blkaddr(ei->blk) &&
|
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||||
!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC_ENHANCE)) {
|
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
|
||||||
f2fs_bug_on(sbi, 1);
|
f2fs_bug_on(sbi, 1);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@@ -938,7 +941,7 @@ out:
|
|||||||
|
|
||||||
static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type type)
|
static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type type)
|
||||||
{
|
{
|
||||||
struct extent_info ei;
|
struct extent_info ei = {};
|
||||||
|
|
||||||
if (!__may_extent_tree(dn->inode, type))
|
if (!__may_extent_tree(dn->inode, type))
|
||||||
return;
|
return;
|
||||||
@@ -953,8 +956,7 @@ static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type typ
|
|||||||
else
|
else
|
||||||
ei.blk = dn->data_blkaddr;
|
ei.blk = dn->data_blkaddr;
|
||||||
} else if (type == EX_BLOCK_AGE) {
|
} else if (type == EX_BLOCK_AGE) {
|
||||||
ei.blk = dn->data_blkaddr;
|
if (__get_new_block_age(dn->inode, &ei, dn->data_blkaddr))
|
||||||
if (__get_new_block_age(dn->inode, &ei))
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
__update_extent_tree_range(dn->inode, &ei, type);
|
__update_extent_tree_range(dn->inode, &ei, type);
|
||||||
|
|||||||
@@ -2548,7 +2548,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
|||||||
struct f2fs_map_blocks map = { .m_next_extent = NULL,
|
struct f2fs_map_blocks map = { .m_next_extent = NULL,
|
||||||
.m_seg_type = NO_CHECK_TYPE,
|
.m_seg_type = NO_CHECK_TYPE,
|
||||||
.m_may_create = false };
|
.m_may_create = false };
|
||||||
struct extent_info ei = {0, };
|
struct extent_info ei = {};
|
||||||
pgoff_t pg_start, pg_end, next_pgofs;
|
pgoff_t pg_start, pg_end, next_pgofs;
|
||||||
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
||||||
unsigned int total = 0, sec_num;
|
unsigned int total = 0, sec_num;
|
||||||
|
|||||||
@@ -662,8 +662,7 @@ init_thread:
|
|||||||
if (IS_ERR(fcc->f2fs_issue_flush)) {
|
if (IS_ERR(fcc->f2fs_issue_flush)) {
|
||||||
int err = PTR_ERR(fcc->f2fs_issue_flush);
|
int err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||||
|
|
||||||
kfree(fcc);
|
fcc->f2fs_issue_flush = NULL;
|
||||||
SM_I(sbi)->fcc_info = NULL;
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3162,7 +3161,7 @@ static int __get_segment_type_4(struct f2fs_io_info *fio)
|
|||||||
static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
|
static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
|
||||||
{
|
{
|
||||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||||
struct extent_info ei;
|
struct extent_info ei = {};
|
||||||
|
|
||||||
if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
|
if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
|
||||||
if (!ei.age)
|
if (!ei.age)
|
||||||
@@ -5139,11 +5138,9 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
|
|||||||
|
|
||||||
init_f2fs_rwsem(&sm_info->curseg_lock);
|
init_f2fs_rwsem(&sm_info->curseg_lock);
|
||||||
|
|
||||||
if (!f2fs_readonly(sbi->sb)) {
|
err = f2fs_create_flush_cmd_control(sbi);
|
||||||
err = f2fs_create_flush_cmd_control(sbi);
|
if (err)
|
||||||
if (err)
|
return err;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = create_discard_cmd_control(sbi);
|
err = create_discard_cmd_control(sbi);
|
||||||
if (err)
|
if (err)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
config FS_VERITY
|
config FS_VERITY
|
||||||
bool "FS Verity (read-only file-based authenticity protection)"
|
bool "FS Verity (read-only file-based authenticity protection)"
|
||||||
select CRYPTO
|
select CRYPTO
|
||||||
|
select CRYPTO_HASH_INFO
|
||||||
# SHA-256 is implied as it's intended to be the default hash algorithm.
|
# SHA-256 is implied as it's intended to be the default hash algorithm.
|
||||||
# To avoid bloat, other wanted algorithms must be selected explicitly.
|
# To avoid bloat, other wanted algorithms must be selected explicitly.
|
||||||
# Note that CRYPTO_SHA256 denotes the generic C implementation, but
|
# Note that CRYPTO_SHA256 denotes the generic C implementation, but
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ static int enable_verity(struct file *filp,
|
|||||||
const struct fsverity_operations *vops = inode->i_sb->s_vop;
|
const struct fsverity_operations *vops = inode->i_sb->s_vop;
|
||||||
struct merkle_tree_params params = { };
|
struct merkle_tree_params params = { };
|
||||||
struct fsverity_descriptor *desc;
|
struct fsverity_descriptor *desc;
|
||||||
size_t desc_size = sizeof(*desc) + arg->sig_size;
|
size_t desc_size = struct_size(desc, signature, arg->sig_size);
|
||||||
struct fsverity_info *vi;
|
struct fsverity_info *vi;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ static int enable_verity(struct file *filp,
|
|||||||
* from disk. This is simpler, and it serves as an extra check that the
|
* from disk. This is simpler, and it serves as an extra check that the
|
||||||
* metadata we're writing is valid before actually enabling verity.
|
* metadata we're writing is valid before actually enabling verity.
|
||||||
*/
|
*/
|
||||||
vi = fsverity_create_info(inode, desc, desc_size);
|
vi = fsverity_create_info(inode, desc);
|
||||||
if (IS_ERR(vi)) {
|
if (IS_ERR(vi)) {
|
||||||
err = PTR_ERR(vi);
|
err = PTR_ERR(vi);
|
||||||
goto rollback;
|
goto rollback;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#define pr_fmt(fmt) "fs-verity: " fmt
|
#define pr_fmt(fmt) "fs-verity: " fmt
|
||||||
|
|
||||||
#include <crypto/sha2.h>
|
|
||||||
#include <linux/fsverity.h>
|
#include <linux/fsverity.h>
|
||||||
#include <linux/mempool.h>
|
#include <linux/mempool.h>
|
||||||
|
|
||||||
@@ -26,12 +25,6 @@ struct ahash_request;
|
|||||||
*/
|
*/
|
||||||
#define FS_VERITY_MAX_LEVELS 8
|
#define FS_VERITY_MAX_LEVELS 8
|
||||||
|
|
||||||
/*
|
|
||||||
* Largest digest size among all hash algorithms supported by fs-verity.
|
|
||||||
* Currently assumed to be <= size of fsverity_descriptor::root_hash.
|
|
||||||
*/
|
|
||||||
#define FS_VERITY_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
|
|
||||||
|
|
||||||
/* A hash algorithm supported by fs-verity */
|
/* A hash algorithm supported by fs-verity */
|
||||||
struct fsverity_hash_alg {
|
struct fsverity_hash_alg {
|
||||||
struct crypto_ahash *tfm; /* hash tfm, allocated on demand */
|
struct crypto_ahash *tfm; /* hash tfm, allocated on demand */
|
||||||
@@ -39,6 +32,11 @@ struct fsverity_hash_alg {
|
|||||||
unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
|
unsigned int digest_size; /* digest size in bytes, e.g. 32 for SHA-256 */
|
||||||
unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */
|
unsigned int block_size; /* block size in bytes, e.g. 64 for SHA-256 */
|
||||||
mempool_t req_pool; /* mempool with a preallocated hash request */
|
mempool_t req_pool; /* mempool with a preallocated hash request */
|
||||||
|
/*
|
||||||
|
* The HASH_ALGO_* constant for this algorithm. This is different from
|
||||||
|
* FS_VERITY_HASH_ALG_*, which uses a different numbering scheme.
|
||||||
|
*/
|
||||||
|
enum hash_algo algo_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Merkle tree parameters: hash algorithm, initial hash state, and topology */
|
/* Merkle tree parameters: hash algorithm, initial hash state, and topology */
|
||||||
@@ -122,16 +120,14 @@ int fsverity_init_merkle_tree_params(struct merkle_tree_params *params,
|
|||||||
const u8 *salt, size_t salt_size);
|
const u8 *salt, size_t salt_size);
|
||||||
|
|
||||||
struct fsverity_info *fsverity_create_info(const struct inode *inode,
|
struct fsverity_info *fsverity_create_info(const struct inode *inode,
|
||||||
struct fsverity_descriptor *desc,
|
struct fsverity_descriptor *desc);
|
||||||
size_t desc_size);
|
|
||||||
|
|
||||||
void fsverity_set_info(struct inode *inode, struct fsverity_info *vi);
|
void fsverity_set_info(struct inode *inode, struct fsverity_info *vi);
|
||||||
|
|
||||||
void fsverity_free_info(struct fsverity_info *vi);
|
void fsverity_free_info(struct fsverity_info *vi);
|
||||||
|
|
||||||
int fsverity_get_descriptor(struct inode *inode,
|
int fsverity_get_descriptor(struct inode *inode,
|
||||||
struct fsverity_descriptor **desc_ret,
|
struct fsverity_descriptor **desc_ret);
|
||||||
size_t *desc_size_ret);
|
|
||||||
|
|
||||||
int __init fsverity_init_info_cache(void);
|
int __init fsverity_init_info_cache(void);
|
||||||
void __init fsverity_exit_info_cache(void);
|
void __init fsverity_exit_info_cache(void);
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ struct fsverity_hash_alg fsverity_hash_algs[] = {
|
|||||||
.name = "sha256",
|
.name = "sha256",
|
||||||
.digest_size = SHA256_DIGEST_SIZE,
|
.digest_size = SHA256_DIGEST_SIZE,
|
||||||
.block_size = SHA256_BLOCK_SIZE,
|
.block_size = SHA256_BLOCK_SIZE,
|
||||||
|
.algo_id = HASH_ALGO_SHA256,
|
||||||
},
|
},
|
||||||
[FS_VERITY_HASH_ALG_SHA512] = {
|
[FS_VERITY_HASH_ALG_SHA512] = {
|
||||||
.name = "sha512",
|
.name = "sha512",
|
||||||
.digest_size = SHA512_DIGEST_SIZE,
|
.digest_size = SHA512_DIGEST_SIZE,
|
||||||
.block_size = SHA512_BLOCK_SIZE,
|
.block_size = SHA512_BLOCK_SIZE,
|
||||||
|
.algo_id = HASH_ALGO_SHA512,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -324,5 +326,9 @@ void __init fsverity_check_hash_algs(void)
|
|||||||
*/
|
*/
|
||||||
BUG_ON(!is_power_of_2(alg->digest_size));
|
BUG_ON(!is_power_of_2(alg->digest_size));
|
||||||
BUG_ON(!is_power_of_2(alg->block_size));
|
BUG_ON(!is_power_of_2(alg->block_size));
|
||||||
|
|
||||||
|
/* Verify that there is a valid mapping to HASH_ALGO_*. */
|
||||||
|
BUG_ON(alg->algo_id == 0);
|
||||||
|
BUG_ON(alg->digest_size != hash_digest_size[alg->algo_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,3 +57,31 @@ int fsverity_ioctl_measure(struct file *filp, void __user *_uarg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
|
EXPORT_SYMBOL_GPL(fsverity_ioctl_measure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fsverity_get_digest() - get a verity file's digest
|
||||||
|
* @inode: inode to get digest of
|
||||||
|
* @digest: (out) pointer to the digest
|
||||||
|
* @alg: (out) pointer to the hash algorithm enumeration
|
||||||
|
*
|
||||||
|
* Return the file hash algorithm and digest of an fsverity protected file.
|
||||||
|
* Assumption: before calling this, the file must have been opened.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, -errno on failure
|
||||||
|
*/
|
||||||
|
int fsverity_get_digest(struct inode *inode,
|
||||||
|
u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
|
||||||
|
enum hash_algo *alg)
|
||||||
|
{
|
||||||
|
const struct fsverity_info *vi;
|
||||||
|
const struct fsverity_hash_alg *hash_alg;
|
||||||
|
|
||||||
|
vi = fsverity_get_info(inode);
|
||||||
|
if (!vi)
|
||||||
|
return -ENODATA; /* not a verity file */
|
||||||
|
|
||||||
|
hash_alg = vi->tree_params.hash_alg;
|
||||||
|
memcpy(digest, vi->file_digest, hash_alg->digest_size);
|
||||||
|
*alg = hash_alg->algo_id;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -147,8 +147,7 @@ static int compute_file_digest(struct fsverity_hash_alg *hash_alg,
|
|||||||
* fsverity_descriptor must have already undergone basic validation.
|
* fsverity_descriptor must have already undergone basic validation.
|
||||||
*/
|
*/
|
||||||
struct fsverity_info *fsverity_create_info(const struct inode *inode,
|
struct fsverity_info *fsverity_create_info(const struct inode *inode,
|
||||||
struct fsverity_descriptor *desc,
|
struct fsverity_descriptor *desc)
|
||||||
size_t desc_size)
|
|
||||||
{
|
{
|
||||||
struct fsverity_info *vi;
|
struct fsverity_info *vi;
|
||||||
int err;
|
int err;
|
||||||
@@ -264,8 +263,7 @@ static bool validate_fsverity_descriptor(struct inode *inode,
|
|||||||
* the filesystem, and do basic validation of it.
|
* the filesystem, and do basic validation of it.
|
||||||
*/
|
*/
|
||||||
int fsverity_get_descriptor(struct inode *inode,
|
int fsverity_get_descriptor(struct inode *inode,
|
||||||
struct fsverity_descriptor **desc_ret,
|
struct fsverity_descriptor **desc_ret)
|
||||||
size_t *desc_size_ret)
|
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct fsverity_descriptor *desc;
|
struct fsverity_descriptor *desc;
|
||||||
@@ -297,7 +295,6 @@ int fsverity_get_descriptor(struct inode *inode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*desc_ret = desc;
|
*desc_ret = desc;
|
||||||
*desc_size_ret = res;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,17 +303,16 @@ static int ensure_verity_info(struct inode *inode)
|
|||||||
{
|
{
|
||||||
struct fsverity_info *vi = fsverity_get_info(inode);
|
struct fsverity_info *vi = fsverity_get_info(inode);
|
||||||
struct fsverity_descriptor *desc;
|
struct fsverity_descriptor *desc;
|
||||||
size_t desc_size;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (vi)
|
if (vi)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = fsverity_get_descriptor(inode, &desc, &desc_size);
|
err = fsverity_get_descriptor(inode, &desc);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
vi = fsverity_create_info(inode, desc, desc_size);
|
vi = fsverity_create_info(inode, desc);
|
||||||
if (IS_ERR(vi)) {
|
if (IS_ERR(vi)) {
|
||||||
err = PTR_ERR(vi);
|
err = PTR_ERR(vi);
|
||||||
goto out_free_desc;
|
goto out_free_desc;
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ static int fsverity_read_merkle_tree(struct inode *inode,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
virt = kmap(page);
|
virt = kmap_local_page(page);
|
||||||
if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) {
|
if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) {
|
||||||
kunmap(page);
|
kunmap_local(virt);
|
||||||
put_page(page);
|
put_page(page);
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
kunmap(page);
|
kunmap_local(virt);
|
||||||
put_page(page);
|
put_page(page);
|
||||||
|
|
||||||
retval += bytes_to_copy;
|
retval += bytes_to_copy;
|
||||||
@@ -101,7 +101,7 @@ static int fsverity_read_descriptor(struct inode *inode,
|
|||||||
size_t desc_size;
|
size_t desc_size;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = fsverity_get_descriptor(inode, &desc, &desc_size);
|
res = fsverity_get_descriptor(inode, &desc);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
@@ -119,10 +119,9 @@ static int fsverity_read_signature(struct inode *inode,
|
|||||||
void __user *buf, u64 offset, int length)
|
void __user *buf, u64 offset, int length)
|
||||||
{
|
{
|
||||||
struct fsverity_descriptor *desc;
|
struct fsverity_descriptor *desc;
|
||||||
size_t desc_size;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = fsverity_get_descriptor(inode, &desc, &desc_size);
|
res = fsverity_get_descriptor(inode, &desc);
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
|||||||
@@ -39,16 +39,6 @@ static void hash_at_level(const struct merkle_tree_params *params,
|
|||||||
(params->log_blocksize - params->log_arity);
|
(params->log_blocksize - params->log_arity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract a hash from a hash page */
|
|
||||||
static void extract_hash(struct page *hpage, unsigned int hoffset,
|
|
||||||
unsigned int hsize, u8 *out)
|
|
||||||
{
|
|
||||||
void *virt = kmap_atomic(hpage);
|
|
||||||
|
|
||||||
memcpy(out, virt + hoffset, hsize);
|
|
||||||
kunmap_atomic(virt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int cmp_hashes(const struct fsverity_info *vi,
|
static inline int cmp_hashes(const struct fsverity_info *vi,
|
||||||
const u8 *want_hash, const u8 *real_hash,
|
const u8 *want_hash, const u8 *real_hash,
|
||||||
pgoff_t index, int level)
|
pgoff_t index, int level)
|
||||||
@@ -129,7 +119,7 @@ static bool verify_page(struct inode *inode, const struct fsverity_info *vi,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PageChecked(hpage)) {
|
if (PageChecked(hpage)) {
|
||||||
extract_hash(hpage, hoffset, hsize, _want_hash);
|
memcpy_from_page(_want_hash, hpage, hoffset, hsize);
|
||||||
want_hash = _want_hash;
|
want_hash = _want_hash;
|
||||||
put_page(hpage);
|
put_page(hpage);
|
||||||
pr_debug_ratelimited("Hash page already checked, want %s:%*phN\n",
|
pr_debug_ratelimited("Hash page already checked, want %s:%*phN\n",
|
||||||
@@ -158,7 +148,7 @@ descend:
|
|||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
SetPageChecked(hpage);
|
SetPageChecked(hpage);
|
||||||
extract_hash(hpage, hoffset, hsize, _want_hash);
|
memcpy_from_page(_want_hash, hpage, hoffset, hsize);
|
||||||
want_hash = _want_hash;
|
want_hash = _want_hash;
|
||||||
put_page(hpage);
|
put_page(hpage);
|
||||||
pr_debug("Verified hash page at level %d, now want %s:%*phN\n",
|
pr_debug("Verified hash page at level %d, now want %s:%*phN\n",
|
||||||
@@ -210,9 +200,8 @@ EXPORT_SYMBOL_GPL(fsverity_verify_page);
|
|||||||
* @bio: the bio to verify
|
* @bio: the bio to verify
|
||||||
*
|
*
|
||||||
* Verify a set of pages that have just been read from a verity file. The pages
|
* Verify a set of pages that have just been read from a verity file. The pages
|
||||||
* must be pagecache pages that are still locked and not yet uptodate. Pages
|
* must be pagecache pages that are still locked and not yet uptodate. If a
|
||||||
* that fail verification are set to the Error state. Verification is skipped
|
* page fails verification, then bio->bi_status is set to an error status.
|
||||||
* for pages already in the Error state, e.g. due to fscrypt decryption failure.
|
|
||||||
*
|
*
|
||||||
* This is a helper function for use by the ->readpages() method of filesystems
|
* This is a helper function for use by the ->readpages() method of filesystems
|
||||||
* that issue bios to read data directly into the page cache. Filesystems that
|
* that issue bios to read data directly into the page cache. Filesystems that
|
||||||
@@ -254,9 +243,10 @@ void fsverity_verify_bio(struct bio *bio)
|
|||||||
unsigned long level0_ra_pages =
|
unsigned long level0_ra_pages =
|
||||||
min(max_ra_pages, params->level0_blocks - level0_index);
|
min(max_ra_pages, params->level0_blocks - level0_index);
|
||||||
|
|
||||||
if (!PageError(page) &&
|
if (!verify_page(inode, vi, req, page, level0_ra_pages)) {
|
||||||
!verify_page(inode, vi, req, page, level0_ra_pages))
|
bio->bi_status = BLK_STS_IOERR;
|
||||||
SetPageError(page);
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fsverity_free_hash_request(params->hash_alg, req);
|
fsverity_free_hash_request(params->hash_alg, req);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ enum blk_crypto_mode_num {
|
|||||||
BLK_ENCRYPTION_MODE_AES_256_XTS,
|
BLK_ENCRYPTION_MODE_AES_256_XTS,
|
||||||
BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV,
|
BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV,
|
||||||
BLK_ENCRYPTION_MODE_ADIANTUM,
|
BLK_ENCRYPTION_MODE_ADIANTUM,
|
||||||
|
BLK_ENCRYPTION_MODE_SM4_XTS,
|
||||||
BLK_ENCRYPTION_MODE_MAX,
|
BLK_ENCRYPTION_MODE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg);
|
|||||||
int fscrypt_ioctl_get_policy_ex(struct file *filp, void __user *arg);
|
int fscrypt_ioctl_get_policy_ex(struct file *filp, void __user *arg);
|
||||||
int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg);
|
int fscrypt_ioctl_get_nonce(struct file *filp, void __user *arg);
|
||||||
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child);
|
int fscrypt_has_permitted_context(struct inode *parent, struct inode *child);
|
||||||
|
int fscrypt_context_for_new_inode(void *ctx, struct inode *inode);
|
||||||
int fscrypt_set_context(struct inode *inode, void *fs_data);
|
int fscrypt_set_context(struct inode *inode, void *fs_data);
|
||||||
|
|
||||||
struct fscrypt_dummy_policy {
|
struct fscrypt_dummy_policy {
|
||||||
@@ -331,6 +332,10 @@ void fscrypt_free_inode(struct inode *inode);
|
|||||||
int fscrypt_drop_inode(struct inode *inode);
|
int fscrypt_drop_inode(struct inode *inode);
|
||||||
|
|
||||||
/* fname.c */
|
/* fname.c */
|
||||||
|
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
|
||||||
|
u8 *out, unsigned int olen);
|
||||||
|
bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
|
||||||
|
u32 max_len, u32 *encrypted_len_ret);
|
||||||
int fscrypt_setup_filename(struct inode *inode, const struct qstr *iname,
|
int fscrypt_setup_filename(struct inode *inode, const struct qstr *iname,
|
||||||
int lookup, struct fscrypt_name *fname);
|
int lookup, struct fscrypt_name *fname);
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,16 @@
|
|||||||
#define _LINUX_FSVERITY_H
|
#define _LINUX_FSVERITY_H
|
||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <crypto/hash_info.h>
|
||||||
|
#include <crypto/sha2.h>
|
||||||
#include <uapi/linux/fsverity.h>
|
#include <uapi/linux/fsverity.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Largest digest size among all hash algorithms supported by fs-verity.
|
||||||
|
* Currently assumed to be <= size of fsverity_descriptor::root_hash.
|
||||||
|
*/
|
||||||
|
#define FS_VERITY_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
|
||||||
|
|
||||||
/* Verity operations for filesystems */
|
/* Verity operations for filesystems */
|
||||||
struct fsverity_operations {
|
struct fsverity_operations {
|
||||||
|
|
||||||
@@ -131,6 +139,9 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *arg);
|
|||||||
/* measure.c */
|
/* measure.c */
|
||||||
|
|
||||||
int fsverity_ioctl_measure(struct file *filp, void __user *arg);
|
int fsverity_ioctl_measure(struct file *filp, void __user *arg);
|
||||||
|
int fsverity_get_digest(struct inode *inode,
|
||||||
|
u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
|
||||||
|
enum hash_algo *alg);
|
||||||
|
|
||||||
/* open.c */
|
/* open.c */
|
||||||
|
|
||||||
@@ -170,6 +181,13 @@ static inline int fsverity_ioctl_measure(struct file *filp, void __user *arg)
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int fsverity_get_digest(struct inode *inode,
|
||||||
|
u8 digest[FS_VERITY_MAX_DIGEST_SIZE],
|
||||||
|
enum hash_algo *alg)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
/* open.c */
|
/* open.c */
|
||||||
|
|
||||||
static inline int fsverity_file_open(struct inode *inode, struct file *filp)
|
static inline int fsverity_file_open(struct inode *inode, struct file *filp)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#ifdef CONFIG_KMAP_LOCAL
|
#ifdef CONFIG_KMAP_LOCAL
|
||||||
void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot);
|
void *__kmap_local_pfn_prot(unsigned long pfn, pgprot_t prot);
|
||||||
void *__kmap_local_page_prot(struct page *page, pgprot_t prot);
|
void *__kmap_local_page_prot(struct page *page, pgprot_t prot);
|
||||||
void kunmap_local_indexed(void *vaddr);
|
void kunmap_local_indexed(const void *vaddr);
|
||||||
void kmap_local_fork(struct task_struct *tsk);
|
void kmap_local_fork(struct task_struct *tsk);
|
||||||
void __kmap_local_sched_out(void);
|
void __kmap_local_sched_out(void);
|
||||||
void __kmap_local_sched_in(void);
|
void __kmap_local_sched_in(void);
|
||||||
@@ -83,7 +83,7 @@ static inline void *kmap_local_pfn(unsigned long pfn)
|
|||||||
return __kmap_local_pfn_prot(pfn, kmap_prot);
|
return __kmap_local_pfn_prot(pfn, kmap_prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __kunmap_local(void *vaddr)
|
static inline void __kunmap_local(const void *vaddr)
|
||||||
{
|
{
|
||||||
kunmap_local_indexed(vaddr);
|
kunmap_local_indexed(vaddr);
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ static inline void *kmap_atomic_pfn(unsigned long pfn)
|
|||||||
return __kmap_local_pfn_prot(pfn, kmap_prot);
|
return __kmap_local_pfn_prot(pfn, kmap_prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __kunmap_atomic(void *addr)
|
static inline void __kunmap_atomic(const void *addr)
|
||||||
{
|
{
|
||||||
kunmap_local_indexed(addr);
|
kunmap_local_indexed(addr);
|
||||||
pagefault_enable();
|
pagefault_enable();
|
||||||
@@ -181,7 +181,7 @@ static inline void *kmap_local_pfn(unsigned long pfn)
|
|||||||
return kmap_local_page(pfn_to_page(pfn));
|
return kmap_local_page(pfn_to_page(pfn));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __kunmap_local(void *addr)
|
static inline void __kunmap_local(const void *addr)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
|
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
|
||||||
kunmap_flush_on_unmap(addr);
|
kunmap_flush_on_unmap(addr);
|
||||||
@@ -208,7 +208,7 @@ static inline void *kmap_atomic_pfn(unsigned long pfn)
|
|||||||
return kmap_atomic(pfn_to_page(pfn));
|
return kmap_atomic(pfn_to_page(pfn));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __kunmap_atomic(void *addr)
|
static inline void __kunmap_atomic(const void *addr)
|
||||||
{
|
{
|
||||||
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
|
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
|
||||||
kunmap_flush_on_unmap(addr);
|
kunmap_flush_on_unmap(addr);
|
||||||
|
|||||||
@@ -26,6 +26,8 @@
|
|||||||
#define FSCRYPT_MODE_AES_256_CTS 4
|
#define FSCRYPT_MODE_AES_256_CTS 4
|
||||||
#define FSCRYPT_MODE_AES_128_CBC 5
|
#define FSCRYPT_MODE_AES_128_CBC 5
|
||||||
#define FSCRYPT_MODE_AES_128_CTS 6
|
#define FSCRYPT_MODE_AES_128_CTS 6
|
||||||
|
#define FSCRYPT_MODE_SM4_XTS 7
|
||||||
|
#define FSCRYPT_MODE_SM4_CTS 8
|
||||||
#define FSCRYPT_MODE_ADIANTUM 9
|
#define FSCRYPT_MODE_ADIANTUM 9
|
||||||
#define FSCRYPT_MODE_AES_256_HCTR2 10
|
#define FSCRYPT_MODE_AES_256_HCTR2 10
|
||||||
/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
|
/* If adding a mode number > 10, update FSCRYPT_MODE_MAX in fscrypt_private.h */
|
||||||
@@ -188,8 +190,6 @@ struct fscrypt_get_key_status_arg {
|
|||||||
#define FS_ENCRYPTION_MODE_AES_256_CTS FSCRYPT_MODE_AES_256_CTS
|
#define FS_ENCRYPTION_MODE_AES_256_CTS FSCRYPT_MODE_AES_256_CTS
|
||||||
#define FS_ENCRYPTION_MODE_AES_128_CBC FSCRYPT_MODE_AES_128_CBC
|
#define FS_ENCRYPTION_MODE_AES_128_CBC FSCRYPT_MODE_AES_128_CBC
|
||||||
#define FS_ENCRYPTION_MODE_AES_128_CTS FSCRYPT_MODE_AES_128_CTS
|
#define FS_ENCRYPTION_MODE_AES_128_CTS FSCRYPT_MODE_AES_128_CTS
|
||||||
#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* removed */
|
|
||||||
#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* removed */
|
|
||||||
#define FS_ENCRYPTION_MODE_ADIANTUM FSCRYPT_MODE_ADIANTUM
|
#define FS_ENCRYPTION_MODE_ADIANTUM FSCRYPT_MODE_ADIANTUM
|
||||||
#define FS_KEY_DESC_PREFIX FSCRYPT_KEY_DESC_PREFIX
|
#define FS_KEY_DESC_PREFIX FSCRYPT_KEY_DESC_PREFIX
|
||||||
#define FS_KEY_DESC_PREFIX_SIZE FSCRYPT_KEY_DESC_PREFIX_SIZE
|
#define FS_KEY_DESC_PREFIX_SIZE FSCRYPT_KEY_DESC_PREFIX_SIZE
|
||||||
|
|||||||
@@ -564,7 +564,7 @@ void *__kmap_local_page_prot(struct page *page, pgprot_t prot)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__kmap_local_page_prot);
|
EXPORT_SYMBOL(__kmap_local_page_prot);
|
||||||
|
|
||||||
void kunmap_local_indexed(void *vaddr)
|
void kunmap_local_indexed(const void *vaddr)
|
||||||
{
|
{
|
||||||
unsigned long addr = (unsigned long) vaddr & PAGE_MASK;
|
unsigned long addr = (unsigned long) vaddr & PAGE_MASK;
|
||||||
pte_t *kmap_pte;
|
pte_t *kmap_pte;
|
||||||
|
|||||||
Reference in New Issue
Block a user