Commit afdb0f2e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt

Pull fscrypt updates from Eric Biggers:

 - Add the IV_INO_LBLK_32 encryption policy flag which modifies the
   encryption to be optimized for eMMC inline encryption hardware.

 - Make the test_dummy_encryption mount option for ext4 and f2fs support
   v2 encryption policies.

 - Fix kerneldoc warnings and some coding style inconsistencies.

* tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/fs/fscrypt/fscrypt:
  fscrypt: add support for IV_INO_LBLK_32 policies
  fscrypt: make test_dummy_encryption use v2 by default
  fscrypt: support test_dummy_encryption=v2
  fscrypt: add fscrypt_add_test_dummy_key()
  linux/parser.h: add include guards
  fscrypt: remove unnecessary extern keywords
  fscrypt: name all function parameters
  fscrypt: fix all kerneldoc warnings
parents 829f3b94 e3b1078b
...@@ -225,8 +225,12 @@ fsync_mode=%s Control the policy of fsync. Currently supports "posix", ...@@ -225,8 +225,12 @@ fsync_mode=%s Control the policy of fsync. Currently supports "posix",
pass, but the performance will regress. "nobarrier" is pass, but the performance will regress. "nobarrier" is
based on "posix", but doesn't issue flush command for based on "posix", but doesn't issue flush command for
non-atomic files likewise "nobarrier" mount option. non-atomic files likewise "nobarrier" mount option.
test_dummy_encryption Enable dummy encryption, which provides a fake fscrypt test_dummy_encryption
test_dummy_encryption=%s
Enable dummy encryption, which provides a fake fscrypt
context. The fake fscrypt context is used by xfstests. context. The fake fscrypt context is used by xfstests.
The argument may be either "v1" or "v2", in order to
select the corresponding fscrypt policy version.
checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "enable" checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "enable"
to reenable checkpointing. Is enabled by default. While to reenable checkpointing. Is enabled by default. While
disabled, any unmounting or unexpected shutdowns will cause disabled, any unmounting or unexpected shutdowns will cause
......
...@@ -292,8 +292,22 @@ files' data differently, inode numbers are included in the IVs. ...@@ -292,8 +292,22 @@ files' data differently, inode numbers are included in the IVs.
Consequently, shrinking the filesystem may not be allowed. Consequently, shrinking the filesystem may not be allowed.
This format is optimized for use with inline encryption hardware This format is optimized for use with inline encryption hardware
compliant with the UFS or eMMC standards, which support only 64 IV compliant with the UFS standard, which supports only 64 IV bits per
bits per I/O request and may have only a small number of keyslots. I/O request and may have only a small number of keyslots.
IV_INO_LBLK_32 policies
-----------------------
IV_INO_LBLK_32 policies work like IV_INO_LBLK_64, except that for
IV_INO_LBLK_32, the inode number is hashed with SipHash-2-4 (where the
SipHash key is derived from the master key) and added to the file
logical block number mod 2^32 to produce a 32-bit IV.
This format is optimized for use with inline encryption hardware
compliant with the eMMC v5.2 standard, which supports only 32 IV bits
per I/O request and may have only a small number of keyslots. This
format results in some level of IV reuse, so it should only be used
when necessary due to hardware limitations.
Key identifiers Key identifiers
--------------- ---------------
...@@ -369,6 +383,10 @@ a little endian number, except that: ...@@ -369,6 +383,10 @@ a little endian number, except that:
to 32 bits and is placed in bits 0-31 of the IV. The inode number to 32 bits and is placed in bits 0-31 of the IV. The inode number
(which is also limited to 32 bits) is placed in bits 32-63. (which is also limited to 32 bits) is placed in bits 32-63.
- With `IV_INO_LBLK_32 policies`_, the logical block number is limited
to 32 bits and is placed in bits 0-31 of the IV. The inode number
is then hashed and added mod 2^32.
Note that because file logical block numbers are included in the IVs, Note that because file logical block numbers are included in the IVs,
filesystems must enforce that blocks are never shifted around within filesystems must enforce that blocks are never shifted around within
encrypted files, e.g. via "collapse range" or "insert range". encrypted files, e.g. via "collapse range" or "insert range".
...@@ -465,8 +483,15 @@ This structure must be initialized as follows: ...@@ -465,8 +483,15 @@ This structure must be initialized as follows:
(0x3). (0x3).
- FSCRYPT_POLICY_FLAG_DIRECT_KEY: See `DIRECT_KEY policies`_. - FSCRYPT_POLICY_FLAG_DIRECT_KEY: See `DIRECT_KEY policies`_.
- FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: See `IV_INO_LBLK_64 - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: See `IV_INO_LBLK_64
policies`_. This is mutually exclusive with DIRECT_KEY and is not policies`_.
supported on v1 policies. - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32: See `IV_INO_LBLK_32
policies`_.
v1 encryption policies only support the PAD_* and DIRECT_KEY flags.
The other flags are only supported by v2 encryption policies.
The DIRECT_KEY, IV_INO_LBLK_64, and IV_INO_LBLK_32 flags are
mutually exclusive.
- For v2 encryption policies, ``__reserved`` must be zeroed. - For v2 encryption policies, ``__reserved`` must be zeroed.
......
...@@ -54,6 +54,7 @@ struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags) ...@@ -54,6 +54,7 @@ struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags)
/** /**
* fscrypt_free_bounce_page() - free a ciphertext bounce page * fscrypt_free_bounce_page() - free a ciphertext bounce page
* @bounce_page: the bounce page to free, or NULL
* *
* Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(), * Free a bounce page that was allocated by fscrypt_encrypt_pagecache_blocks(),
* or by fscrypt_alloc_bounce_page() directly. * or by fscrypt_alloc_bounce_page() directly.
...@@ -76,8 +77,12 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, ...@@ -76,8 +77,12 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
memset(iv, 0, ci->ci_mode->ivsize); memset(iv, 0, ci->ci_mode->ivsize);
if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
WARN_ON_ONCE((u32)lblk_num != lblk_num); WARN_ON_ONCE(lblk_num > U32_MAX);
WARN_ON_ONCE(ci->ci_inode->i_ino > U32_MAX);
lblk_num |= (u64)ci->ci_inode->i_ino << 32; lblk_num |= (u64)ci->ci_inode->i_ino << 32;
} else if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
WARN_ON_ONCE(lblk_num > U32_MAX);
lblk_num = (u32)(ci->ci_hashed_ino + lblk_num);
} else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) {
memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
} }
...@@ -132,7 +137,8 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw, ...@@ -132,7 +137,8 @@ int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
} }
/** /**
* fscrypt_encrypt_pagecache_blocks() - Encrypt filesystem blocks from a pagecache page * fscrypt_encrypt_pagecache_blocks() - Encrypt filesystem blocks from a
* pagecache page
* @page: The locked pagecache page containing the block(s) to encrypt * @page: The locked pagecache page containing the block(s) to encrypt
* @len: Total size of the block(s) to encrypt. Must be a nonzero * @len: Total size of the block(s) to encrypt. Must be a nonzero
* multiple of the filesystem's block size. * multiple of the filesystem's block size.
...@@ -222,7 +228,8 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page, ...@@ -222,7 +228,8 @@ int fscrypt_encrypt_block_inplace(const struct inode *inode, struct page *page,
EXPORT_SYMBOL(fscrypt_encrypt_block_inplace); EXPORT_SYMBOL(fscrypt_encrypt_block_inplace);
/** /**
* fscrypt_decrypt_pagecache_blocks() - Decrypt filesystem blocks in a pagecache page * fscrypt_decrypt_pagecache_blocks() - Decrypt filesystem blocks in a
* pagecache page
* @page: The locked pagecache page containing the block(s) to decrypt * @page: The locked pagecache page containing the block(s) to decrypt
* @len: Total size of the block(s) to decrypt. Must be a nonzero * @len: Total size of the block(s) to decrypt. Must be a nonzero
* multiple of the filesystem's block size. * multiple of the filesystem's block size.
...@@ -346,6 +353,8 @@ void fscrypt_msg(const struct inode *inode, const char *level, ...@@ -346,6 +353,8 @@ void fscrypt_msg(const struct inode *inode, const char *level,
/** /**
* fscrypt_init() - Set up for fs encryption. * fscrypt_init() - Set up for fs encryption.
*
* Return: 0 on success; -errno on failure
*/ */
static int __init fscrypt_init(void) static int __init fscrypt_init(void)
{ {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <crypto/skcipher.h> #include <crypto/skcipher.h>
#include "fscrypt_private.h" #include "fscrypt_private.h"
/** /*
* struct fscrypt_nokey_name - identifier for directory entry when key is absent * struct fscrypt_nokey_name - identifier for directory entry when key is absent
* *
* When userspace lists an encrypted directory without access to the key, the * When userspace lists an encrypted directory without access to the key, the
...@@ -100,8 +100,11 @@ static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) ...@@ -100,8 +100,11 @@ 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)
* The output buffer must be at least as large as the input buffer. * or of the symlink (for symlink targets)
* @iname: the filename to encrypt
* @out: (output) the encrypted filename
* @olen: size of the encrypted filename. It must be at least @iname->len.
* Any extra space is filled with NUL padding before encryption. * Any extra space is filled with NUL padding before encryption.
* *
* Return: 0 on success, -errno on failure * Return: 0 on success, -errno on failure
...@@ -152,8 +155,11 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, ...@@ -152,8 +155,11 @@ int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
/** /**
* fname_decrypt() - decrypt a filename * fname_decrypt() - decrypt a filename
* * @inode: inode of the parent directory (for regular filenames)
* The caller must have allocated sufficient memory for the @oname string. * or of the symlink (for symlink targets)
* @iname: the encrypted filename to decrypt
* @oname: (output) the decrypted filename. The caller must have allocated
* enough space for this, e.g. using fscrypt_fname_alloc_buffer().
* *
* Return: 0 on success, -errno on failure * Return: 0 on success, -errno on failure
*/ */
...@@ -201,7 +207,10 @@ static const char lookup_table[65] = ...@@ -201,7 +207,10 @@ static const char lookup_table[65] =
#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3) #define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
/** /**
* base64_encode() - * base64_encode() - base64-encode some bytes
* @src: the bytes to encode
* @len: number of bytes to encode
* @dst: (output) the base64-encoded string. Not NUL-terminated.
* *
* Encodes the input string using characters from the set [A-Za-z0-9+,]. * Encodes the input string using characters from the set [A-Za-z0-9+,].
* The encoded string is roughly 4/3 times the size of the input string. * The encoded string is roughly 4/3 times the size of the input string.
...@@ -267,7 +276,12 @@ bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, ...@@ -267,7 +276,12 @@ bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
} }
/** /**
* fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames * fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames
* @inode: inode of the parent directory (for regular filenames)
* or of the symlink (for symlink targets)
* @max_encrypted_len: maximum length of encrypted filenames the buffer will be
* used to present
* @crypto_str: (output) buffer to allocate
* *
* Allocate a buffer that is large enough to hold any decrypted or encoded * Allocate a buffer that is large enough to hold any decrypted or encoded
* filename (null-terminated), for the given maximum encrypted filename length. * filename (null-terminated), for the given maximum encrypted filename length.
...@@ -292,9 +306,10 @@ int fscrypt_fname_alloc_buffer(const struct inode *inode, ...@@ -292,9 +306,10 @@ int fscrypt_fname_alloc_buffer(const struct inode *inode,
EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
/** /**
* fscrypt_fname_free_buffer - free the buffer for presented filenames * fscrypt_fname_free_buffer() - free a buffer for presented filenames
* @crypto_str: the buffer to free
* *
* Free the buffer allocated by fscrypt_fname_alloc_buffer(). * Free a buffer that was allocated by fscrypt_fname_alloc_buffer().
*/ */
void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
{ {
...@@ -306,10 +321,19 @@ void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) ...@@ -306,10 +321,19 @@ void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
EXPORT_SYMBOL(fscrypt_fname_free_buffer); EXPORT_SYMBOL(fscrypt_fname_free_buffer);
/** /**
* fscrypt_fname_disk_to_usr() - converts a filename from disk space to user * fscrypt_fname_disk_to_usr() - convert an encrypted filename to
* space * user-presentable form
* * @inode: inode of the parent directory (for regular filenames)
* The caller must have allocated sufficient memory for the @oname string. * or of the symlink (for symlink targets)
* @hash: first part of the name's dirhash, if applicable. This only needs to
* be provided if the filename is located in an indexed directory whose
* encryption key may be unavailable. Not needed for symlink targets.
* @minor_hash: second part of the name's dirhash, if applicable
* @iname: encrypted filename to convert. May also be "." or "..", which
* aren't actually encrypted.
* @oname: output buffer for the user-presentable filename. The caller must
* have allocated enough space for this, e.g. using
* fscrypt_fname_alloc_buffer().
* *
* If the key is available, we'll decrypt the disk name. Otherwise, we'll * If the key is available, we'll decrypt the disk name. Otherwise, we'll
* encode it for presentation in fscrypt_nokey_name format. * encode it for presentation in fscrypt_nokey_name format.
......
...@@ -43,7 +43,7 @@ struct fscrypt_context_v2 { ...@@ -43,7 +43,7 @@ struct fscrypt_context_v2 {
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
}; };
/** /*
* fscrypt_context - the encryption context of an inode * fscrypt_context - the encryption context of an inode
* *
* This is the on-disk equivalent of an fscrypt_policy, stored alongside each * This is the on-disk equivalent of an fscrypt_policy, stored alongside each
...@@ -157,7 +157,7 @@ fscrypt_policy_flags(const union fscrypt_policy *policy) ...@@ -157,7 +157,7 @@ fscrypt_policy_flags(const union fscrypt_policy *policy)
BUG(); BUG();
} }
/** /*
* For encrypted symlinks, the ciphertext length is stored at the beginning * For encrypted symlinks, the ciphertext length is stored at the beginning
* of the string in little-endian format. * of the string in little-endian format.
*/ */
...@@ -222,6 +222,9 @@ struct fscrypt_info { ...@@ -222,6 +222,9 @@ struct fscrypt_info {
/* This inode's nonce, copied from the fscrypt_context */ /* This inode's nonce, copied from the fscrypt_context */
u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE]; u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE];
/* Hashed inode number. Only set for IV_INO_LBLK_32 */
u32 ci_hashed_ino;
}; };
typedef enum { typedef enum {
...@@ -231,15 +234,14 @@ typedef enum { ...@@ -231,15 +234,14 @@ typedef enum {
/* crypto.c */ /* crypto.c */
extern struct kmem_cache *fscrypt_info_cachep; extern struct kmem_cache *fscrypt_info_cachep;
extern int fscrypt_initialize(unsigned int cop_flags); int fscrypt_initialize(unsigned int cop_flags);
extern int fscrypt_crypt_block(const struct inode *inode, int fscrypt_crypt_block(const struct inode *inode, fscrypt_direction_t rw,
fscrypt_direction_t rw, u64 lblk_num, u64 lblk_num, struct page *src_page,
struct page *src_page, struct page *dest_page, struct page *dest_page, unsigned int len,
unsigned int len, unsigned int offs, unsigned int offs, gfp_t gfp_flags);
gfp_t gfp_flags); struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags);
extern struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags);
void __printf(3, 4) __cold
extern void __printf(3, 4) __cold
fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...); fscrypt_msg(const struct inode *inode, const char *level, const char *fmt, ...);
#define fscrypt_warn(inode, fmt, ...) \ #define fscrypt_warn(inode, fmt, ...) \
...@@ -264,12 +266,10 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, ...@@ -264,12 +266,10 @@ 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 */
extern int fscrypt_fname_encrypt(const struct inode *inode, int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname,
const struct qstr *iname,
u8 *out, unsigned int olen); u8 *out, unsigned int olen);
extern bool fscrypt_fname_encrypted_size(const struct inode *inode, bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
u32 orig_len, u32 max_len, u32 max_len, u32 *encrypted_len_ret);
u32 *encrypted_len_ret);
extern const struct dentry_operations fscrypt_d_ops; extern const struct dentry_operations fscrypt_d_ops;
/* hkdf.c */ /* hkdf.c */
...@@ -278,7 +278,7 @@ struct fscrypt_hkdf { ...@@ -278,7 +278,7 @@ struct fscrypt_hkdf {
struct crypto_shash *hmac_tfm; struct crypto_shash *hmac_tfm;
}; };
extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
unsigned int master_key_size); unsigned int master_key_size);
/* /*
...@@ -293,12 +293,14 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, ...@@ -293,12 +293,14 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
#define HKDF_CONTEXT_DIRECT_KEY 3 #define HKDF_CONTEXT_DIRECT_KEY 3
#define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4 #define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4
#define HKDF_CONTEXT_DIRHASH_KEY 5 #define HKDF_CONTEXT_DIRHASH_KEY 5
#define HKDF_CONTEXT_IV_INO_LBLK_32_KEY 6
#define HKDF_CONTEXT_INODE_HASH_KEY 7
extern int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context, int fscrypt_hkdf_expand(const struct fscrypt_hkdf *hkdf, u8 context,
const u8 *info, unsigned int infolen, const u8 *info, unsigned int infolen,
u8 *okm, unsigned int okmlen); u8 *okm, unsigned int okmlen);
extern void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf); void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);
/* keyring.c */ /* keyring.c */
...@@ -389,14 +391,17 @@ struct fscrypt_master_key { ...@@ -389,14 +391,17 @@ struct fscrypt_master_key {
struct list_head mk_decrypted_inodes; struct list_head mk_decrypted_inodes;
spinlock_t mk_decrypted_inodes_lock; spinlock_t mk_decrypted_inodes_lock;
/* Crypto API transforms for DIRECT_KEY policies, allocated on-demand */
struct crypto_skcipher *mk_direct_tfms[__FSCRYPT_MODE_MAX + 1];
/* /*
* Crypto API transforms for filesystem-layer implementation of * Per-mode encryption keys for the various types of encryption policies
* IV_INO_LBLK_64 policies, allocated on-demand. * that use them. Allocated and derived on-demand.
*/ */
struct crypto_skcipher *mk_iv_ino_lblk_64_tfms[__FSCRYPT_MODE_MAX + 1]; struct crypto_skcipher *mk_direct_keys[__FSCRYPT_MODE_MAX + 1];
struct crypto_skcipher *mk_iv_ino_lblk_64_keys[__FSCRYPT_MODE_MAX + 1];
struct crypto_skcipher *mk_iv_ino_lblk_32_keys[__FSCRYPT_MODE_MAX + 1];
/* Hash key for inode numbers. Initialized only when needed. */
siphash_key_t mk_ino_hash_key;
bool mk_ino_hash_key_initialized;
} __randomize_layout; } __randomize_layout;
...@@ -436,14 +441,17 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec) ...@@ -436,14 +441,17 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec)
return 0; return 0;
} }
extern struct key * struct key *
fscrypt_find_master_key(struct super_block *sb, fscrypt_find_master_key(struct super_block *sb,
const struct fscrypt_key_specifier *mk_spec); const struct fscrypt_key_specifier *mk_spec);
extern int fscrypt_verify_key_added(struct super_block *sb, int fscrypt_add_test_dummy_key(struct super_block *sb,
struct fscrypt_key_specifier *key_spec);
int fscrypt_verify_key_added(struct super_block *sb,
const u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]); const u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]);
extern int __init fscrypt_init_keyring(void); int __init fscrypt_init_keyring(void);
/* keysetup.c */ /* keysetup.c */
...@@ -457,32 +465,31 @@ struct fscrypt_mode { ...@@ -457,32 +465,31 @@ struct fscrypt_mode {
extern struct fscrypt_mode fscrypt_modes[]; extern struct fscrypt_mode fscrypt_modes[];
extern struct crypto_skcipher * struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode,
fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key, const u8 *raw_key,
const struct inode *inode); const struct inode *inode);
extern int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, int fscrypt_set_per_file_enc_key(struct fscrypt_info *ci, const u8 *raw_key);
const u8 *raw_key);
extern int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
const struct fscrypt_master_key *mk); const struct fscrypt_master_key *mk);
/* keysetup_v1.c */ /* keysetup_v1.c */
extern void fscrypt_put_direct_key(struct fscrypt_direct_key *dk); void fscrypt_put_direct_key(struct fscrypt_direct_key *dk);
extern int fscrypt_setup_v1_file_key(struct fscrypt_info *ci, int fscrypt_setup_v1_file_key(struct fscrypt_info *ci,
const u8 *raw_master_key); const u8 *raw_master_key);
extern int fscrypt_setup_v1_file_key_via_subscribed_keyrings( int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci);
struct fscrypt_info *ci);
/* policy.c */ /* policy.c */
extern bool fscrypt_policies_equal(const union fscrypt_policy *policy1, bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
const union fscrypt_policy *policy2); const union fscrypt_policy *policy2);
extern bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
const struct inode *inode); const struct inode *inode);
extern int fscrypt_policy_from_context(union fscrypt_policy *policy_u, int fscrypt_policy_from_context(union fscrypt_policy *policy_u,
const union fscrypt_context *ctx_u, const union fscrypt_context *ctx_u,
int ctx_size); int ctx_size);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include "fscrypt_private.h" #include "fscrypt_private.h"
/** /**
* fscrypt_file_open - prepare to open a possibly-encrypted regular file * fscrypt_file_open() - prepare to open a possibly-encrypted regular file
* @inode: the inode being opened * @inode: the inode being opened
* @filp: the struct file being set up * @filp: the struct file being set up
* *
...@@ -262,7 +262,7 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, ...@@ -262,7 +262,7 @@ int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
/** /**
* fscrypt_get_symlink - get the target of an encrypted symlink * fscrypt_get_symlink() - get the target of an encrypted symlink
* @inode: the symlink inode * @inode: the symlink inode
* @caddr: the on-disk contents of the symlink * @caddr: the on-disk contents of the symlink
* @max_size: size of @caddr buffer * @max_size: size of @caddr buffer
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <crypto/skcipher.h> #include <crypto/skcipher.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <linux/random.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include "fscrypt_private.h" #include "fscrypt_private.h"
...@@ -44,8 +45,9 @@ static void free_master_key(struct fscrypt_master_key *mk) ...@@ -44,8 +45,9 @@ static void free_master_key(struct fscrypt_master_key *mk)
wipe_master_key_secret(&mk->mk_secret); wipe_master_key_secret(&mk->mk_secret);
for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) { for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) {
crypto_free_skcipher(mk->mk_direct_tfms[i]); crypto_free_skcipher(mk->mk_direct_keys[i]);
crypto_free_skcipher(mk->mk_iv_ino_lblk_64_tfms[i]); crypto_free_skcipher(mk->mk_iv_ino_lblk_64_keys[i]);
crypto_free_skcipher(mk->mk_iv_ino_lblk_32_keys[i]);
} }
key_put(mk->mk_users); key_put(mk->mk_users);
...@@ -424,7 +426,7 @@ static int add_existing_master_key(struct fscrypt_master_key *mk, ...@@ -424,7 +426,7 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
return 0; return 0;
} }
static int add_master_key(struct super_block *sb, static int do_add_master_key(struct super_block *sb,
struct fscrypt_master_key_secret *secret, struct fscrypt_master_key_secret *secret,
const struct fscrypt_key_specifier *mk_spec) const struct fscrypt_key_specifier *mk_spec)
{ {
...@@ -465,6 +467,35 @@ static int add_master_key(struct super_block *sb, ...@@ -465,6 +467,35 @@ static int add_master_key(struct super_block *sb,
return err; return err;
} }
static int add_master_key(struct super_block *sb,
struct fscrypt_master_key_secret *secret,
struct fscrypt_key_specifier *key_spec)
{
int err;
if (key_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
err = fscrypt_init_hkdf(&secret->hkdf, secret->raw,
secret->size);
if (err)
return err;
/*
* Now that the HKDF context is initialized, the raw key is no
* longer needed.
*/
memzero_explicit(secret->raw, secret->size);
/* Calculate the key identifier */
err = fscrypt_hkdf_expand(&secret->hkdf,
HKDF_CONTEXT_KEY_IDENTIFIER, NULL, 0,
key_spec->u.identifier,
FSCRYPT_KEY_IDENTIFIER_SIZE);
if (err)
return err;
}
return do_add_master_key(sb, secret, key_spec);
}
static int fscrypt_provisioning_key_preparse(struct key_preparsed_payload *prep) static int fscrypt_provisioning_key_preparse(struct key_preparsed_payload *prep)
{ {
const struct fscrypt_provisioning_key_payload *payload = prep->data; const struct fscrypt_provisioning_key_payload *payload = prep->data;
...@@ -609,6 +640,15 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg) ...@@ -609,6 +640,15 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
if (memchr_inv(arg.__reserved, 0, sizeof(arg.__reserved))) if (memchr_inv(arg.__reserved, 0, sizeof(arg.__reserved)))
return -EINVAL; return -EINVAL;
/*
* Only root can add keys that are identified by an arbitrary descriptor
* rather than by a cryptographic hash --- since otherwise a malicious
* user could add the wrong key.
*/
if (arg.key_spec.type == FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR &&
!capable(CAP_SYS_ADMIN))
return -EACCES;
memset(&secret, 0, sizeof(secret)); memset(&secret, 0, sizeof(secret));
if (arg.key_id) { if (arg.key_id) {
if (arg.raw_size != 0) if (arg.raw_size != 0)
...@@ -626,54 +666,46 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg) ...@@ -626,54 +666,46 @@ int fscrypt_ioctl_add_key(struct file *filp, void __user *_uarg)
goto out_wipe_secret; goto out_wipe_secret;
} }
switch (arg.key_spec.type) { err = add_master_key(sb, &secret, &arg.key_spec);
case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
/*
* Only root can add keys that are identified by an arbitrary
* descriptor rather than by a cryptographic hash --- since
* otherwise a malicious user could add the wrong key.
*/
err = -EACCES;
if (!capable(CAP_SYS_ADMIN))
goto out_wipe_secret;
break;
case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
err = fscrypt_init_hkdf(&secret.hkdf, secret.raw, secret.size);
if (err) if (err)
goto out_wipe_secret; goto out_wipe_secret;
/* /* Return the key identifier to userspace, if applicable */
* Now that the HKDF context is initialized, the raw key is no
* longer needed.
*/
memzero_explicit(secret.raw, secret.size);
/* Calculate the key identifier and return it to userspace. */
err = fscrypt_hkdf_expand(&secret.hkdf,
HKDF_CONTEXT_KEY_IDENTIFIER,
NULL, 0, arg.key_spec.u.identifier,
FSCRYPT_KEY_IDENTIFIER_SIZE);
if (err)
goto out_wipe_secret;
err = -EFAULT; err = -EFAULT;
if (copy_to_user(uarg->key_spec.u.identifier, if (arg.key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER &&
arg.key_spec.u.identifier, copy_to_user(uarg->key_spec.u.identifier, arg.key_spec.u.identifier,
FSCRYPT_KEY_IDENTIFIER_SIZE)) FSCRYPT_KEY_IDENTIFIER_SIZE))
goto out_wipe_secret; goto out_wipe_secret;
break; err = 0;
default:
WARN_ON(1);
err = -EINVAL;
goto out_wipe_secret;
}
err = add_master_key(sb, &secret, &arg.key_spec);
out_wipe_secret: out_wipe_secret:
wipe_master_key_secret(&secret); wipe_master_key_secret(&secret);
return err; return err;
} }
EXPORT_SYMBOL_GPL(fscrypt_ioctl_add_key); EXPORT_SYMBOL_GPL(fscrypt_ioctl_add_key);
/*
* Add the key for '-o test_dummy_encryption' to the filesystem keyring.
*
* Use a per-boot random key to prevent people from misusing this option.
*/
int fscrypt_add_test_dummy_key(struct super_block *sb,
struct fscrypt_key_specifier *key_spec)
{
static u8 test_key[FSCRYPT_MAX_KEY_SIZE];
struct fscrypt_master_key_secret secret;
int err;
get_random_once(test_key, FSCRYPT_MAX_KEY_SIZE);
memset(&secret, 0, sizeof(secret));
secret.size = FSCRYPT_MAX_KEY_SIZE;
memcpy(secret.raw, test_key, FSCRYPT_MAX_KEY_SIZE);
err = add_master_key(sb, &secret, key_spec);
wipe_master_key_secret(&secret);
return err;
}
/* /*
* Verify that the current user has added a master key with the given identifier * Verify that the current user has added a master key with the given identifier
* (returns -ENOKEY if not). This is needed to prevent a user from encrypting * (returns -ENOKEY if not). This is needed to prevent a user from encrypting
......
...@@ -46,6 +46,8 @@ struct fscrypt_mode fscrypt_modes[] = { ...@@ -46,6 +46,8 @@ struct fscrypt_mode fscrypt_modes[] = {
}, },
}; };
static DEFINE_MUTEX(fscrypt_mode_key_setup_mutex);
static struct fscrypt_mode * static struct fscrypt_mode *
select_encryption_mode(const union fscrypt_policy *policy, select_encryption_mode(const union fscrypt_policy *policy,
const struct inode *inode) const struct inode *inode)
...@@ -130,7 +132,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci, ...@@ -130,7 +132,7 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,
const struct super_block *sb = inode->i_sb; const struct super_block *sb = inode->i_sb;
struct fscrypt_mode *mode = ci->ci_mode; struct fscrypt_mode *mode = ci->ci_mode;
const u8 mode_num = mode - fscrypt_modes; const u8 mode_num = mode - fscrypt_modes;
struct crypto_skcipher *tfm, *prev_tfm; struct crypto_skcipher *tfm;
u8 mode_key[FSCRYPT_MAX_KEY_SIZE]; u8 mode_key[FSCRYPT_MAX_KEY_SIZE];
u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)]; u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
unsigned int hkdf_infolen = 0; unsigned int hkdf_infolen = 0;
...@@ -139,10 +141,17 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci, ...@@ -139,10 +141,17 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,
if (WARN_ON(mode_num > __FSCRYPT_MODE_MAX)) if (WARN_ON(mode_num > __FSCRYPT_MODE_MAX))
return -EINVAL; return -EINVAL;
/* pairs with cmpxchg() below */ /* pairs with smp_store_release() below */
tfm = READ_ONCE(tfms[mode_num]); tfm = READ_ONCE(tfms[mode_num]);
if (likely(tfm != NULL)) if (likely(tfm != NULL)) {
goto done; ci->ci_ctfm = tfm;
return 0;
}
mutex_lock(&fscrypt_mode_key_setup_mutex);
if (tfms[mode_num])
goto done_unlock;
BUILD_BUG_ON(sizeof(mode_num) != 1); BUILD_BUG_ON(sizeof(mode_num) != 1);
BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
...@@ -157,21 +166,21 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci, ...@@ -157,21 +166,21 @@ static int setup_per_mode_enc_key(struct fscrypt_info *ci,
hkdf_context, hkdf_info, hkdf_infolen, hkdf_context, hkdf_info, hkdf_infolen,
mode_key, mode->keysize); mode_key, mode->keysize);
if (err) if (err)
return err; goto out_unlock;
tfm = fscrypt_allocate_skcipher(mode, mode_key, inode); tfm = fscrypt_allocate_skcipher(mode, mode_key, inode);
memzero_explicit(mode_key, mode->keysize); memzero_explicit(mode_key, mode->keysize);
if (IS_ERR(tfm)) if (IS_ERR(tfm)) {
return PTR_ERR(tfm); err = PTR_ERR(tfm);
goto out_unlock;
/* pairs with READ_ONCE() above */
prev_tfm = cmpxchg(&tfms[mode_num], NULL, tfm);
if (prev_tfm != NULL) {
crypto_free_skcipher(tfm);
tfm = prev_tfm;
} }
done: /* pairs with READ_ONCE() above */
smp_store_release(&tfms[mode_num], tfm);
done_unlock:
ci->ci_ctfm = tfm; ci->ci_ctfm = tfm;
return 0; err = 0;
out_unlock:
mutex_unlock(&fscrypt_mode_key_setup_mutex);
return err;
} }
int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
...@@ -189,6 +198,43 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci, ...@@ -189,6 +198,43 @@ int fscrypt_derive_dirhash_key(struct fscrypt_info *ci,
return 0; return 0;
} }
static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_info *ci,
struct fscrypt_master_key *mk)
{
int err;
err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys,
HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true);
if (err)
return err;
/* pairs with smp_store_release() below */
if (!smp_load_acquire(&mk->mk_ino_hash_key_initialized)) {
mutex_lock(&fscrypt_mode_key_setup_mutex);
if (mk->mk_ino_hash_key_initialized)
goto unlock;
err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf,
HKDF_CONTEXT_INODE_HASH_KEY, NULL, 0,
(u8 *)&mk->mk_ino_hash_key,
sizeof(mk->mk_ino_hash_key));
if (err)
goto unlock;
/* pairs with smp_load_acquire() above */
smp_store_release(&mk->mk_ino_hash_key_initialized, true);
unlock:
mutex_unlock(&fscrypt_mode_key_setup_mutex);
if (err)
return err;
}
ci->ci_hashed_ino = (u32)siphash_1u64(ci->ci_inode->i_ino,
&mk->mk_ino_hash_key);
return 0;
}
static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
struct fscrypt_master_key *mk) struct fscrypt_master_key *mk)
{ {
...@@ -203,7 +249,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, ...@@ -203,7 +249,7 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
* encryption key. This ensures that the master key is * encryption key. This ensures that the master key is
* consistently used only for HKDF, avoiding key reuse issues. * consistently used only for HKDF, avoiding key reuse issues.
*/ */
err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_tfms, err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
HKDF_CONTEXT_DIRECT_KEY, false); HKDF_CONTEXT_DIRECT_KEY, false);
} else if (ci->ci_policy.v2.flags & } else if (ci->ci_policy.v2.flags &
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
...@@ -211,11 +257,14 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, ...@@ -211,11 +257,14 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci,
* IV_INO_LBLK_64: encryption keys are derived from (master_key, * IV_INO_LBLK_64: encryption keys are derived from (master_key,
* mode_num, filesystem_uuid), and inode number is included in * mode_num, filesystem_uuid), and inode number is included in
* the IVs. This format is optimized for use with inline * the IVs. This format is optimized for use with inline
* encryption hardware compliant with the UFS or eMMC standards. * encryption hardware compliant with the UFS standard.
*/ */
err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_tfms, err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
HKDF_CONTEXT_IV_INO_LBLK_64_KEY, HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
true); true);
} else if (ci->ci_policy.v2.flags &
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk);
} else { } else {
u8 derived_key[FSCRYPT_MAX_KEY_SIZE]; u8 derived_key[FSCRYPT_MAX_KEY_SIZE];
...@@ -395,21 +444,18 @@ int fscrypt_get_encryption_info(struct inode *inode) ...@@ -395,21 +444,18 @@ int fscrypt_get_encryption_info(struct inode *inode)
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx)); res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
if (res < 0) { if (res < 0) {
if (!fscrypt_dummy_context_enabled(inode) || const union fscrypt_context *dummy_ctx =
IS_ENCRYPTED(inode)) { fscrypt_get_dummy_context(inode->i_sb);
if (IS_ENCRYPTED(inode) || !dummy_ctx) {
fscrypt_warn(inode, fscrypt_warn(inode,
"Error %d getting encryption context", "Error %d getting encryption context",
res); res);
return res; return res;
} }
/* Fake up a context for an unencrypted directory */ /* Fake up a context for an unencrypted directory */
memset(&ctx, 0, sizeof(ctx)); res = fscrypt_context_size(dummy_ctx);
ctx.version = FSCRYPT_CONTEXT_V1; memcpy(&ctx, dummy_ctx, res);
ctx.v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
ctx.v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
memset(ctx.v1.master_key_descriptor, 0x42,
FSCRYPT_KEY_DESCRIPTOR_SIZE);
res = sizeof(ctx.v1);
} }
crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_NOFS); crypt_info = kmem_cache_zalloc(fscrypt_info_cachep, GFP_NOFS);
...@@ -475,7 +521,8 @@ int fscrypt_get_encryption_info(struct inode *inode) ...@@ -475,7 +521,8 @@ int fscrypt_get_encryption_info(struct inode *inode)
EXPORT_SYMBOL(fscrypt_get_encryption_info); EXPORT_SYMBOL(fscrypt_get_encryption_info);
/** /**
* fscrypt_put_encryption_info - free most of an inode's fscrypt data * fscrypt_put_encryption_info() - free most of an inode's fscrypt data
* @inode: an inode being evicted
* *
* Free the inode's fscrypt_info. Filesystems must call this when the inode is * Free the inode's fscrypt_info. Filesystems must call this when the inode is
* being evicted. An RCU grace period need not have elapsed yet. * being evicted. An RCU grace period need not have elapsed yet.
...@@ -488,7 +535,8 @@ void fscrypt_put_encryption_info(struct inode *inode) ...@@ -488,7 +535,8 @@ void fscrypt_put_encryption_info(struct inode *inode)
EXPORT_SYMBOL(fscrypt_put_encryption_info); EXPORT_SYMBOL(fscrypt_put_encryption_info);
/** /**
* fscrypt_free_inode - free an inode's fscrypt data requiring RCU delay * fscrypt_free_inode() - free an inode's fscrypt data requiring RCU delay
* @inode: an inode being freed
* *
* Free the inode's cached decrypted symlink target, if any. Filesystems must * Free the inode's cached decrypted symlink target, if any. Filesystems must
* call this after an RCU grace period, just before they free the inode. * call this after an RCU grace period, just before they free the inode.
...@@ -503,7 +551,8 @@ void fscrypt_free_inode(struct inode *inode) ...@@ -503,7 +551,8 @@ void fscrypt_free_inode(struct inode *inode)
EXPORT_SYMBOL(fscrypt_free_inode); EXPORT_SYMBOL(fscrypt_free_inode);
/** /**
* fscrypt_drop_inode - check whether the inode's master key has been removed * fscrypt_drop_inode() - check whether the inode's master key has been removed
* @inode: an inode being considered for eviction
* *
* Filesystems supporting fscrypt must call this from their ->drop_inode() * Filesystems supporting fscrypt must call this from their ->drop_inode()
* method so that encrypted inodes are evicted as soon as they're no longer in * method so that encrypted inodes are evicted as soon as they're no longer in
......
...@@ -11,12 +11,15 @@ ...@@ -11,12 +11,15 @@
*/ */
#include <linux/random.h> #include <linux/random.h>
#include <linux/seq_file.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/mount.h> #include <linux/mount.h>
#include "fscrypt_private.h" #include "fscrypt_private.h"
/** /**
* fscrypt_policies_equal - check whether two encryption policies are the same * fscrypt_policies_equal() - check whether two encryption policies are the same
* @policy1: the first policy
* @policy2: the second policy
* *
* Return: %true if equal, else %false * Return: %true if equal, else %false
*/ */
...@@ -66,18 +69,14 @@ static bool supported_direct_key_modes(const struct inode *inode, ...@@ -66,18 +69,14 @@ static bool supported_direct_key_modes(const struct inode *inode,
return true; return true;
} }
static bool supported_iv_ino_lblk_64_policy( static bool supported_iv_ino_lblk_policy(const struct fscrypt_policy_v2 *policy,
const struct fscrypt_policy_v2 *policy, const struct inode *inode,
const struct inode *inode) const char *type,
int max_ino_bits, int max_lblk_bits)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int ino_bits = 64, lblk_bits = 64; int ino_bits = 64, lblk_bits = 64;
if (policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) {
fscrypt_warn(inode,
"The DIRECT_KEY and IV_INO_LBLK_64 flags are mutually exclusive");
return false;
}
/* /*
* It's unsafe to include inode numbers in the IVs if the filesystem can * It's unsafe to include inode numbers in the IVs if the filesystem can
* potentially renumber inodes, e.g. via filesystem shrinking. * potentially renumber inodes, e.g. via filesystem shrinking.
...@@ -85,16 +84,22 @@ static bool supported_iv_ino_lblk_64_policy( ...@@ -85,16 +84,22 @@ static bool supported_iv_ino_lblk_64_policy(
if (!sb->s_cop->has_stable_inodes || if (!sb->s_cop->has_stable_inodes ||
!sb->s_cop->has_stable_inodes(sb)) { !sb->s_cop->has_stable_inodes(sb)) {
fscrypt_warn(inode, fscrypt_warn(inode,
"Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't have stable inode numbers", "Can't use %s policy on filesystem '%s' because it doesn't have stable inode numbers",
sb->s_id); type, sb->s_id);
return false; return false;
} }
if (sb->s_cop->get_ino_and_lblk_bits) if (sb->s_cop->get_ino_and_lblk_bits)
sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits); sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits);
if (ino_bits > 32 || lblk_bits > 32) { if (ino_bits > max_ino_bits) {
fscrypt_warn(inode,
"Can't use %s policy on filesystem '%s' because its inode numbers are too long",
type, sb->s_id);
return false;
}
if (lblk_bits > max_lblk_bits) {
fscrypt_warn(inode, fscrypt_warn(inode,
"Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't use 32-bit inode and block numbers", "Can't use %s policy on filesystem '%s' because its block numbers are too long",
sb->s_id); type, sb->s_id);
return false; return false;
} }
return true; return true;
...@@ -137,6 +142,8 @@ static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy, ...@@ -137,6 +142,8 @@ static bool fscrypt_supported_v1_policy(const struct fscrypt_policy_v1 *policy,
static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
const struct inode *inode) const struct inode *inode)
{ {
int count = 0;
if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode, if (!fscrypt_valid_enc_modes(policy->contents_encryption_mode,
policy->filenames_encryption_mode)) { policy->filenames_encryption_mode)) {
fscrypt_warn(inode, fscrypt_warn(inode,
...@@ -152,13 +159,29 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, ...@@ -152,13 +159,29 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
return false; return false;
} }
count += !!(policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY);
count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64);
count += !!(policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32);
if (count > 1) {
fscrypt_warn(inode, "Mutually exclusive encryption flags (0x%02x)",
policy->flags);
return false;
}
if ((policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) && if ((policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) &&
!supported_direct_key_modes(inode, policy->contents_encryption_mode, !supported_direct_key_modes(inode, policy->contents_encryption_mode,
policy->filenames_encryption_mode)) policy->filenames_encryption_mode))
return false; return false;
if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) && if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) &&
!supported_iv_ino_lblk_64_policy(policy, inode)) !supported_iv_ino_lblk_policy(policy, inode, "IV_INO_LBLK_64",
32, 32))
return false;
if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) &&
/* This uses hashed inode numbers, so ino_bits doesn't matter. */
!supported_iv_ino_lblk_policy(policy, inode, "IV_INO_LBLK_32",
INT_MAX, 32))
return false; return false;
if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) { if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) {
...@@ -170,7 +193,9 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy, ...@@ -170,7 +193,9 @@ static bool fscrypt_supported_v2_policy(const struct fscrypt_policy_v2 *policy,
} }
/** /**
* fscrypt_supported_policy - check whether an encryption policy is supported * fscrypt_supported_policy() - check whether an encryption policy is supported
* @policy_u: the encryption policy
* @inode: the inode on which the policy will be used
* *
* Given an encryption policy, check whether all its encryption modes and other * Given an encryption policy, check whether all its encryption modes and other
* settings are supported by this kernel on the given inode. (But we don't * settings are supported by this kernel on the given inode. (But we don't
...@@ -192,7 +217,10 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, ...@@ -192,7 +217,10 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
} }
/** /**
* fscrypt_new_context_from_policy - create a new fscrypt_context from a policy * fscrypt_new_context_from_policy() - create a new fscrypt_context from
* an fscrypt_policy
* @ctx_u: output context
* @policy_u: input policy
* *
* Create an fscrypt_context for an inode that is being assigned the given * Create an fscrypt_context for an inode that is being assigned the given
* encryption policy. A new nonce is randomly generated. * encryption policy. A new nonce is randomly generated.
...@@ -242,7 +270,11 @@ static int fscrypt_new_context_from_policy(union fscrypt_context *ctx_u, ...@@ -242,7 +270,11 @@ static int fscrypt_new_context_from_policy(union fscrypt_context *ctx_u,
} }
/** /**
* fscrypt_policy_from_context - convert an fscrypt_context to an fscrypt_policy * fscrypt_policy_from_context() - convert an fscrypt_context to
* an fscrypt_policy
* @policy_u: output policy
* @ctx_u: input context
* @ctx_size: size of input context in bytes
* *
* Given an fscrypt_context, build the corresponding fscrypt_policy. * Given an fscrypt_context, build the corresponding fscrypt_policy.
* *
...@@ -354,6 +386,9 @@ static int set_encryption_policy(struct inode *inode, ...@@ -354,6 +386,9 @@ static int set_encryption_policy(struct inode *inode,
policy->v2.master_key_identifier); policy->v2.master_key_identifier);
if (err) if (err)
return err; return err;
if (policy->v2.flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32)
pr_warn_once("%s (pid %d) is setting an IV_INO_LBLK_32 encryption policy. This should only be used if there are certain hardware limitations.\n",
current->comm, current->pid);
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
...@@ -605,3 +640,127 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child, ...@@ -605,3 +640,127 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
return preload ? fscrypt_get_encryption_info(child): 0; return preload ? fscrypt_get_encryption_info(child): 0;
} }
EXPORT_SYMBOL(fscrypt_inherit_context); EXPORT_SYMBOL(fscrypt_inherit_context);
/**
* fscrypt_set_test_dummy_encryption() - handle '-o test_dummy_encryption'
* @sb: the filesystem on which test_dummy_encryption is being specified
* @arg: the argument to the test_dummy_encryption option.
* If no argument was specified, then @arg->from == NULL.
* @dummy_ctx: the filesystem's current dummy context (input/output, see below)
*
* Handle the test_dummy_encryption mount option by creating a dummy encryption
* context, saving it in @dummy_ctx, and adding the corresponding dummy
* encryption key to the filesystem. If the @dummy_ctx is already set, then
* instead validate that it matches @arg. Don't support changing it via
* remount, as that is difficult to do safely.
*
* The reason we use an fscrypt_context rather than an fscrypt_policy is because
* we mustn't generate a new nonce each time we access a dummy-encrypted
* directory, as that would change the way filenames are encrypted.
*
* Return: 0 on success (dummy context set, or the same context is already set);
* -EEXIST if a different dummy context is already set;
* or another -errno value.
*/
int fscrypt_set_test_dummy_encryption(struct super_block *sb,
const substring_t *arg,
struct fscrypt_dummy_context *dummy_ctx)
{
const char *argstr = "v2";
const char *argstr_to_free = NULL;
struct fscrypt_key_specifier key_spec = { 0 };
int version;
union fscrypt_context *ctx = NULL;
int err;
if (arg->from) {
argstr = argstr_to_free = match_strdup(arg);
if (!argstr)
return -ENOMEM;
}
if (!strcmp(argstr, "v1")) {
version = FSCRYPT_CONTEXT_V1;
key_spec.type = FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR;
memset(key_spec.u.descriptor, 0x42,
FSCRYPT_KEY_DESCRIPTOR_SIZE);
} else if (!strcmp(argstr, "v2")) {
version = FSCRYPT_CONTEXT_V2;
key_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
/* key_spec.u.identifier gets filled in when adding the key */
} else {
err = -EINVAL;
goto out;
}
if (dummy_ctx->ctx) {
/*
* Note: if we ever make test_dummy_encryption support
* specifying other encryption settings, such as the encryption
* modes, we'll need to compare those settings here.
*/
if (dummy_ctx->ctx->version == version)
err = 0;
else
err = -EEXIST;
goto out;
}
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
err = -ENOMEM;
goto out;
}
err = fscrypt_add_test_dummy_key(sb, &key_spec);
if (err)
goto out;
ctx->version = version;
switch (ctx->version) {
case FSCRYPT_CONTEXT_V1:
ctx->v1.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
ctx->v1.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
memcpy(ctx->v1.master_key_descriptor, key_spec.u.descriptor,
FSCRYPT_KEY_DESCRIPTOR_SIZE);
break;
case FSCRYPT_CONTEXT_V2:
ctx->v2.contents_encryption_mode = FSCRYPT_MODE_AES_256_XTS;
ctx->v2.filenames_encryption_mode = FSCRYPT_MODE_AES_256_CTS;
memcpy(ctx->v2.master_key_identifier, key_spec.u.identifier,
FSCRYPT_KEY_IDENTIFIER_SIZE);
break;
default:
WARN_ON(1);
err = -EINVAL;
goto out;
}
dummy_ctx->ctx = ctx;
ctx = NULL;
err = 0;
out:
kfree(ctx);
kfree(argstr_to_free);
return err;
}
EXPORT_SYMBOL_GPL(fscrypt_set_test_dummy_encryption);
/**
* fscrypt_show_test_dummy_encryption() - show '-o test_dummy_encryption'
* @seq: the seq_file to print the option to
* @sep: the separator character to use
* @sb: the filesystem whose options are being shown
*
* Show the test_dummy_encryption mount option, if it was specified.
* This is mainly used for /proc/mounts.
*/
void fscrypt_show_test_dummy_encryption(struct seq_file *seq, char sep,
struct super_block *sb)
{
const union fscrypt_context *ctx = fscrypt_get_dummy_context(sb);
if (!ctx)
return;
seq_printf(seq, "%ctest_dummy_encryption=v%d", sep, ctx->version);
}
EXPORT_SYMBOL_GPL(fscrypt_show_test_dummy_encryption);
...@@ -1357,11 +1357,9 @@ struct ext4_super_block { ...@@ -1357,11 +1357,9 @@ struct ext4_super_block {
*/ */
#define EXT4_MF_MNTDIR_SAMPLED 0x0001 #define EXT4_MF_MNTDIR_SAMPLED 0x0001
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
#define EXT4_MF_TEST_DUMMY_ENCRYPTION 0x0004
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
#define DUMMY_ENCRYPTION_ENABLED(sbi) (unlikely((sbi)->s_mount_flags & \ #define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_ctx.ctx != NULL)
EXT4_MF_TEST_DUMMY_ENCRYPTION))
#else #else
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0) #define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
#endif #endif
...@@ -1551,6 +1549,9 @@ struct ext4_sb_info { ...@@ -1551,6 +1549,9 @@ struct ext4_sb_info {
struct ratelimit_state s_warning_ratelimit_state; struct ratelimit_state s_warning_ratelimit_state;
struct ratelimit_state s_msg_ratelimit_state; struct ratelimit_state s_msg_ratelimit_state;
/* Encryption context for '-o test_dummy_encryption' */
struct fscrypt_dummy_context s_dummy_enc_ctx;
/* /*
* Barrier between writepages ops and changing any inode's JOURNAL_DATA * Barrier between writepages ops and changing any inode's JOURNAL_DATA
* or EXTENTS flag. * or EXTENTS flag.
......
...@@ -1106,6 +1106,7 @@ static void ext4_put_super(struct super_block *sb) ...@@ -1106,6 +1106,7 @@ static void ext4_put_super(struct super_block *sb)
crypto_free_shash(sbi->s_chksum_driver); crypto_free_shash(sbi->s_chksum_driver);
kfree(sbi->s_blockgroup_lock); kfree(sbi->s_blockgroup_lock);
fs_put_dax(sbi->s_daxdev); fs_put_dax(sbi->s_daxdev);
fscrypt_free_dummy_context(&sbi->s_dummy_enc_ctx);
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
utf8_unload(sbi->s_encoding); utf8_unload(sbi->s_encoding);
#endif #endif
...@@ -1389,9 +1390,10 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len, ...@@ -1389,9 +1390,10 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
return res; return res;
} }
static bool ext4_dummy_context(struct inode *inode) static const union fscrypt_context *
ext4_get_dummy_context(struct super_block *sb)
{ {
return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb)); return EXT4_SB(sb)->s_dummy_enc_ctx.ctx;
} }
static bool ext4_has_stable_inodes(struct super_block *sb) static bool ext4_has_stable_inodes(struct super_block *sb)
...@@ -1410,7 +1412,7 @@ static const struct fscrypt_operations ext4_cryptops = { ...@@ -1410,7 +1412,7 @@ static const struct fscrypt_operations ext4_cryptops = {
.key_prefix = "ext4:", .key_prefix = "ext4:",
.get_context = ext4_get_context, .get_context = ext4_get_context,
.set_context = ext4_set_context, .set_context = ext4_set_context,
.dummy_context = ext4_dummy_context, .get_dummy_context = ext4_get_dummy_context,
.empty_dir = ext4_empty_dir, .empty_dir = ext4_empty_dir,
.max_namelen = EXT4_NAME_LEN, .max_namelen = EXT4_NAME_LEN,
.has_stable_inodes = ext4_has_stable_inodes, .has_stable_inodes = ext4_has_stable_inodes,
...@@ -1605,6 +1607,7 @@ static const match_table_t tokens = { ...@@ -1605,6 +1607,7 @@ static const match_table_t tokens = {
{Opt_init_itable, "init_itable"}, {Opt_init_itable, "init_itable"},
{Opt_noinit_itable, "noinit_itable"}, {Opt_noinit_itable, "noinit_itable"},
{Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
{Opt_test_dummy_encryption, "test_dummy_encryption=%s"},
{Opt_test_dummy_encryption, "test_dummy_encryption"}, {Opt_test_dummy_encryption, "test_dummy_encryption"},
{Opt_nombcache, "nombcache"}, {Opt_nombcache, "nombcache"},
{Opt_nombcache, "no_mbcache"}, /* for backward compatibility */ {Opt_nombcache, "no_mbcache"}, /* for backward compatibility */
...@@ -1816,7 +1819,7 @@ static const struct mount_opts { ...@@ -1816,7 +1819,7 @@ static const struct mount_opts {
{Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT},
{Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
{Opt_max_dir_size_kb, 0, MOPT_GTE0}, {Opt_max_dir_size_kb, 0, MOPT_GTE0},
{Opt_test_dummy_encryption, 0, MOPT_GTE0}, {Opt_test_dummy_encryption, 0, MOPT_STRING},
{Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET}, {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
{Opt_err, 0, 0} {Opt_err, 0, 0}
}; };
...@@ -1851,6 +1854,48 @@ static int ext4_sb_read_encoding(const struct ext4_super_block *es, ...@@ -1851,6 +1854,48 @@ static int ext4_sb_read_encoding(const struct ext4_super_block *es,
} }
#endif #endif
static int ext4_set_test_dummy_encryption(struct super_block *sb,
const char *opt,
const substring_t *arg,
bool is_remount)
{
#ifdef CONFIG_FS_ENCRYPTION
struct ext4_sb_info *sbi = EXT4_SB(sb);
int err;
/*
* This mount option is just for testing, and it's not worthwhile to
* implement the extra complexity (e.g. RCU protection) that would be
* needed to allow it to be set or changed during remount. We do allow
* it to be specified during remount, but only if there is no change.
*/
if (is_remount && !sbi->s_dummy_enc_ctx.ctx) {
ext4_msg(sb, KERN_WARNING,
"Can't set test_dummy_encryption on remount");
return -1;
}
err = fscrypt_set_test_dummy_encryption(sb, arg, &sbi->s_dummy_enc_ctx);
if (err) {
if (err == -EEXIST)
ext4_msg(sb, KERN_WARNING,
"Can't change test_dummy_encryption on remount");
else if (err == -EINVAL)
ext4_msg(sb, KERN_WARNING,
"Value of option \"%s\" is unrecognized", opt);
else
ext4_msg(sb, KERN_WARNING,
"Error processing option \"%s\" [%d]",
opt, err);
return -1;
}
ext4_msg(sb, KERN_WARNING, "Test dummy encryption mode enabled");
#else
ext4_msg(sb, KERN_WARNING,
"Test dummy encryption mount option ignored");
#endif
return 1;
}
static int handle_mount_opt(struct super_block *sb, char *opt, int token, static int handle_mount_opt(struct super_block *sb, char *opt, int token,
substring_t *args, unsigned long *journal_devnum, substring_t *args, unsigned long *journal_devnum,
unsigned int *journal_ioprio, int is_remount) unsigned int *journal_ioprio, int is_remount)
...@@ -2047,14 +2092,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, ...@@ -2047,14 +2092,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
*journal_ioprio = *journal_ioprio =
IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg); IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg);
} else if (token == Opt_test_dummy_encryption) { } else if (token == Opt_test_dummy_encryption) {
#ifdef CONFIG_FS_ENCRYPTION return ext4_set_test_dummy_encryption(sb, opt, &args[0],
sbi->s_mount_flags |= EXT4_MF_TEST_DUMMY_ENCRYPTION; is_remount);
ext4_msg(sb, KERN_WARNING,
"Test dummy encryption mode enabled");
#else
ext4_msg(sb, KERN_WARNING,
"Test dummy encryption mount option ignored");
#endif
} else if (m->flags & MOPT_DATAJ) { } else if (m->flags & MOPT_DATAJ) {
if (is_remount) { if (is_remount) {
if (!sbi->s_journal) if (!sbi->s_journal)
...@@ -2311,8 +2350,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, ...@@ -2311,8 +2350,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb); SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
if (test_opt(sb, DATA_ERR_ABORT)) if (test_opt(sb, DATA_ERR_ABORT))
SEQ_OPTS_PUTS("data_err=abort"); SEQ_OPTS_PUTS("data_err=abort");
if (DUMMY_ENCRYPTION_ENABLED(sbi))
SEQ_OPTS_PUTS("test_dummy_encryption"); fscrypt_show_test_dummy_encryption(seq, sep, sb);
ext4_show_quota_options(seq, sb); ext4_show_quota_options(seq, sb);
return 0; return 0;
...@@ -4780,6 +4819,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ...@@ -4780,6 +4819,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
for (i = 0; i < EXT4_MAXQUOTAS; i++) for (i = 0; i < EXT4_MAXQUOTAS; i++)
kfree(get_qf_name(sb, sbi, i)); kfree(get_qf_name(sb, sbi, i));
#endif #endif
fscrypt_free_dummy_context(&sbi->s_dummy_enc_ctx);
ext4_blkdev_remove(sbi); ext4_blkdev_remove(sbi);
brelse(bh); brelse(bh);
out_fail: out_fail:
......
...@@ -293,6 +293,7 @@ EXT4_ATTR_FEATURE(batched_discard); ...@@ -293,6 +293,7 @@ EXT4_ATTR_FEATURE(batched_discard);
EXT4_ATTR_FEATURE(meta_bg_resize); EXT4_ATTR_FEATURE(meta_bg_resize);
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
EXT4_ATTR_FEATURE(encryption); EXT4_ATTR_FEATURE(encryption);
EXT4_ATTR_FEATURE(test_dummy_encryption_v2);
#endif #endif
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
EXT4_ATTR_FEATURE(casefold); EXT4_ATTR_FEATURE(casefold);
...@@ -308,6 +309,7 @@ static struct attribute *ext4_feat_attrs[] = { ...@@ -308,6 +309,7 @@ static struct attribute *ext4_feat_attrs[] = {
ATTR_LIST(meta_bg_resize), ATTR_LIST(meta_bg_resize),
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
ATTR_LIST(encryption), ATTR_LIST(encryption),
ATTR_LIST(test_dummy_encryption_v2),
#endif #endif
#ifdef CONFIG_UNICODE #ifdef CONFIG_UNICODE
ATTR_LIST(casefold), ATTR_LIST(casefold),
......
...@@ -138,7 +138,7 @@ struct f2fs_mount_info { ...@@ -138,7 +138,7 @@ struct f2fs_mount_info {
int fsync_mode; /* fsync policy */ int fsync_mode; /* fsync policy */
int fs_mode; /* fs mode: LFS or ADAPTIVE */ int fs_mode; /* fs mode: LFS or ADAPTIVE */
int bggc_mode; /* bggc mode: off, on or sync */ int bggc_mode; /* bggc mode: off, on or sync */
bool test_dummy_encryption; /* test dummy encryption */ struct fscrypt_dummy_context dummy_enc_ctx; /* test dummy encryption */
block_t unusable_cap; /* Amount of space allowed to be block_t unusable_cap; /* Amount of space allowed to be
* unusable when disabling checkpoint * unusable when disabling checkpoint
*/ */
...@@ -1259,7 +1259,7 @@ enum fsync_mode { ...@@ -1259,7 +1259,7 @@ enum fsync_mode {
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
#define DUMMY_ENCRYPTION_ENABLED(sbi) \ #define DUMMY_ENCRYPTION_ENABLED(sbi) \
(unlikely(F2FS_OPTION(sbi).test_dummy_encryption)) (unlikely(F2FS_OPTION(sbi).dummy_enc_ctx.ctx != NULL))
#else #else
#define DUMMY_ENCRYPTION_ENABLED(sbi) (0) #define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
#endif #endif
......
...@@ -202,6 +202,7 @@ static match_table_t f2fs_tokens = { ...@@ -202,6 +202,7 @@ static match_table_t f2fs_tokens = {
{Opt_whint, "whint_mode=%s"}, {Opt_whint, "whint_mode=%s"},
{Opt_alloc, "alloc_mode=%s"}, {Opt_alloc, "alloc_mode=%s"},
{Opt_fsync, "fsync_mode=%s"}, {Opt_fsync, "fsync_mode=%s"},
{Opt_test_dummy_encryption, "test_dummy_encryption=%s"},
{Opt_test_dummy_encryption, "test_dummy_encryption"}, {Opt_test_dummy_encryption, "test_dummy_encryption"},
{Opt_checkpoint_disable, "checkpoint=disable"}, {Opt_checkpoint_disable, "checkpoint=disable"},
{Opt_checkpoint_disable_cap, "checkpoint=disable:%u"}, {Opt_checkpoint_disable_cap, "checkpoint=disable:%u"},
...@@ -394,7 +395,52 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) ...@@ -394,7 +395,52 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
} }
#endif #endif
static int parse_options(struct super_block *sb, char *options) static int f2fs_set_test_dummy_encryption(struct super_block *sb,
const char *opt,
const substring_t *arg,
bool is_remount)
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
#ifdef CONFIG_FS_ENCRYPTION
int err;
if (!f2fs_sb_has_encrypt(sbi)) {
f2fs_err(sbi, "Encrypt feature is off");
return -EINVAL;
}
/*
* This mount option is just for testing, and it's not worthwhile to
* implement the extra complexity (e.g. RCU protection) that would be
* needed to allow it to be set or changed during remount. We do allow
* it to be specified during remount, but only if there is no change.
*/
if (is_remount && !F2FS_OPTION(sbi).dummy_enc_ctx.ctx) {
f2fs_warn(sbi, "Can't set test_dummy_encryption on remount");
return -EINVAL;
}
err = fscrypt_set_test_dummy_encryption(
sb, arg, &F2FS_OPTION(sbi).dummy_enc_ctx);
if (err) {
if (err == -EEXIST)
f2fs_warn(sbi,
"Can't change test_dummy_encryption on remount");
else if (err == -EINVAL)
f2fs_warn(sbi, "Value of option \"%s\" is unrecognized",
opt);
else
f2fs_warn(sbi, "Error processing option \"%s\" [%d]",
opt, err);
return -EINVAL;
}
f2fs_warn(sbi, "Test dummy encryption mode enabled");
#else
f2fs_warn(sbi, "Test dummy encryption mount option ignored");
#endif
return 0;
}
static int parse_options(struct super_block *sb, char *options, bool is_remount)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
substring_t args[MAX_OPT_ARGS]; substring_t args[MAX_OPT_ARGS];
...@@ -403,9 +449,7 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -403,9 +449,7 @@ static int parse_options(struct super_block *sb, char *options)
int arg = 0, ext_cnt; int arg = 0, ext_cnt;
kuid_t uid; kuid_t uid;
kgid_t gid; kgid_t gid;
#ifdef CONFIG_QUOTA
int ret; int ret;
#endif
if (!options) if (!options)
return 0; return 0;
...@@ -778,17 +822,10 @@ static int parse_options(struct super_block *sb, char *options) ...@@ -778,17 +822,10 @@ static int parse_options(struct super_block *sb, char *options)
kvfree(name); kvfree(name);
break; break;
case Opt_test_dummy_encryption: case Opt_test_dummy_encryption:
#ifdef CONFIG_FS_ENCRYPTION ret = f2fs_set_test_dummy_encryption(sb, p, &args[0],
if (!f2fs_sb_has_encrypt(sbi)) { is_remount);
f2fs_err(sbi, "Encrypt feature is off"); if (ret)
return -EINVAL; return ret;
}
F2FS_OPTION(sbi).test_dummy_encryption = true;
f2fs_info(sbi, "Test dummy encryption mode enabled");
#else
f2fs_info(sbi, "Test dummy encryption mount option ignored");
#endif
break; break;
case Opt_checkpoint_disable_cap_perc: case Opt_checkpoint_disable_cap_perc:
if (args->from && match_int(args, &arg)) if (args->from && match_int(args, &arg))
...@@ -1213,6 +1250,7 @@ static void f2fs_put_super(struct super_block *sb) ...@@ -1213,6 +1250,7 @@ static void f2fs_put_super(struct super_block *sb)
for (i = 0; i < MAXQUOTAS; i++) for (i = 0; i < MAXQUOTAS; i++)
kvfree(F2FS_OPTION(sbi).s_qf_names[i]); kvfree(F2FS_OPTION(sbi).s_qf_names[i]);
#endif #endif
fscrypt_free_dummy_context(&F2FS_OPTION(sbi).dummy_enc_ctx);
destroy_percpu_info(sbi); destroy_percpu_info(sbi);
for (i = 0; i < NR_PAGE_TYPE; i++) for (i = 0; i < NR_PAGE_TYPE; i++)
kvfree(sbi->write_io[i]); kvfree(sbi->write_io[i]);
...@@ -1543,10 +1581,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) ...@@ -1543,10 +1581,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_printf(seq, ",whint_mode=%s", "user-based"); seq_printf(seq, ",whint_mode=%s", "user-based");
else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS)
seq_printf(seq, ",whint_mode=%s", "fs-based"); seq_printf(seq, ",whint_mode=%s", "fs-based");
#ifdef CONFIG_FS_ENCRYPTION
if (F2FS_OPTION(sbi).test_dummy_encryption) fscrypt_show_test_dummy_encryption(seq, ',', sbi->sb);
seq_puts(seq, ",test_dummy_encryption");
#endif
if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT) if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT)
seq_printf(seq, ",alloc_mode=%s", "default"); seq_printf(seq, ",alloc_mode=%s", "default");
...@@ -1575,7 +1611,6 @@ static void default_options(struct f2fs_sb_info *sbi) ...@@ -1575,7 +1611,6 @@ static void default_options(struct f2fs_sb_info *sbi)
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
F2FS_OPTION(sbi).test_dummy_encryption = false;
F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4; F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4;
...@@ -1734,7 +1769,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) ...@@ -1734,7 +1769,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
default_options(sbi); default_options(sbi);
/* parse mount options */ /* parse mount options */
err = parse_options(sb, data); err = parse_options(sb, data, true);
if (err) if (err)
goto restore_opts; goto restore_opts;
checkpoint_changed = checkpoint_changed =
...@@ -2410,9 +2445,10 @@ static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len, ...@@ -2410,9 +2445,10 @@ static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
ctx, len, fs_data, XATTR_CREATE); ctx, len, fs_data, XATTR_CREATE);
} }
static bool f2fs_dummy_context(struct inode *inode) static const union fscrypt_context *
f2fs_get_dummy_context(struct super_block *sb)
{ {
return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode)); return F2FS_OPTION(F2FS_SB(sb)).dummy_enc_ctx.ctx;
} }
static bool f2fs_has_stable_inodes(struct super_block *sb) static bool f2fs_has_stable_inodes(struct super_block *sb)
...@@ -2431,7 +2467,7 @@ static const struct fscrypt_operations f2fs_cryptops = { ...@@ -2431,7 +2467,7 @@ static const struct fscrypt_operations f2fs_cryptops = {
.key_prefix = "f2fs:", .key_prefix = "f2fs:",
.get_context = f2fs_get_context, .get_context = f2fs_get_context,
.set_context = f2fs_set_context, .set_context = f2fs_set_context,
.dummy_context = f2fs_dummy_context, .get_dummy_context = f2fs_get_dummy_context,
.empty_dir = f2fs_empty_dir, .empty_dir = f2fs_empty_dir,
.max_namelen = F2FS_NAME_LEN, .max_namelen = F2FS_NAME_LEN,
.has_stable_inodes = f2fs_has_stable_inodes, .has_stable_inodes = f2fs_has_stable_inodes,
...@@ -3366,7 +3402,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3366,7 +3402,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
goto free_sb_buf; goto free_sb_buf;
} }
err = parse_options(sb, options); err = parse_options(sb, options, false);
if (err) if (err)
goto free_options; goto free_options;
...@@ -3769,6 +3805,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -3769,6 +3805,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
for (i = 0; i < MAXQUOTAS; i++) for (i = 0; i < MAXQUOTAS; i++)
kvfree(F2FS_OPTION(sbi).s_qf_names[i]); kvfree(F2FS_OPTION(sbi).s_qf_names[i]);
#endif #endif
fscrypt_free_dummy_context(&F2FS_OPTION(sbi).dummy_enc_ctx);
kvfree(options); kvfree(options);
free_sb_buf: free_sb_buf:
kvfree(raw_super); kvfree(raw_super);
......
...@@ -446,6 +446,7 @@ enum feat_id { ...@@ -446,6 +446,7 @@ enum feat_id {
FEAT_SB_CHECKSUM, FEAT_SB_CHECKSUM,
FEAT_CASEFOLD, FEAT_CASEFOLD,
FEAT_COMPRESSION, FEAT_COMPRESSION,
FEAT_TEST_DUMMY_ENCRYPTION_V2,
}; };
static ssize_t f2fs_feature_show(struct f2fs_attr *a, static ssize_t f2fs_feature_show(struct f2fs_attr *a,
...@@ -466,6 +467,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, ...@@ -466,6 +467,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a,
case FEAT_SB_CHECKSUM: case FEAT_SB_CHECKSUM:
case FEAT_CASEFOLD: case FEAT_CASEFOLD:
case FEAT_COMPRESSION: case FEAT_COMPRESSION:
case FEAT_TEST_DUMMY_ENCRYPTION_V2:
return sprintf(buf, "supported\n"); return sprintf(buf, "supported\n");
} }
return 0; return 0;
...@@ -563,6 +565,7 @@ F2FS_GENERAL_RO_ATTR(avg_vblocks); ...@@ -563,6 +565,7 @@ F2FS_GENERAL_RO_ATTR(avg_vblocks);
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO); F2FS_FEATURE_RO_ATTR(encryption, FEAT_CRYPTO);
F2FS_FEATURE_RO_ATTR(test_dummy_encryption_v2, FEAT_TEST_DUMMY_ENCRYPTION_V2);
#endif #endif
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
F2FS_FEATURE_RO_ATTR(block_zoned, FEAT_BLKZONED); F2FS_FEATURE_RO_ATTR(block_zoned, FEAT_BLKZONED);
...@@ -647,6 +650,7 @@ ATTRIBUTE_GROUPS(f2fs); ...@@ -647,6 +650,7 @@ ATTRIBUTE_GROUPS(f2fs);
static struct attribute *f2fs_feat_attrs[] = { static struct attribute *f2fs_feat_attrs[] = {
#ifdef CONFIG_FS_ENCRYPTION #ifdef CONFIG_FS_ENCRYPTION
ATTR_LIST(encryption), ATTR_LIST(encryption),
ATTR_LIST(test_dummy_encryption_v2),
#endif #endif
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
ATTR_LIST(block_zoned), ATTR_LIST(block_zoned),
......
This diff is collapsed.
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
* but could potentially be used anywhere else that simple option=arg * but could potentially be used anywhere else that simple option=arg
* parsing is required. * parsing is required.
*/ */
#ifndef _LINUX_PARSER_H
#define _LINUX_PARSER_H
/* associates an integer enumerator with a pattern string. */ /* associates an integer enumerator with a pattern string. */
struct match_token { struct match_token {
...@@ -34,3 +35,5 @@ int match_hex(substring_t *, int *result); ...@@ -34,3 +35,5 @@ int match_hex(substring_t *, int *result);
bool match_wildcard(const char *pattern, const char *str); bool match_wildcard(const char *pattern, const char *str);
size_t match_strlcpy(char *, const substring_t *, size_t); size_t match_strlcpy(char *, const substring_t *, size_t);
char *match_strdup(const substring_t *); char *match_strdup(const substring_t *);
#endif /* _LINUX_PARSER_H */
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
#define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03 #define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03
#define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04 #define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04
#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08 #define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08
#define FSCRYPT_POLICY_FLAGS_VALID 0x0F #define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 0x10
#define FSCRYPT_POLICY_FLAGS_VALID 0x1F
/* Encryption algorithms */ /* Encryption algorithms */
#define FSCRYPT_MODE_AES_256_XTS 1 #define FSCRYPT_MODE_AES_256_XTS 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment