Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd59ccc5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fscrypt updates from Ted Ts'o:
 "Add bunch of cleanups, and add support for the Speck128/256
  algorithms.

  Yes, Speck is contrversial, but the intention is to use them only for
  the lowest end Android devices, where the alternative *really* is no
  encryption at all for data stored at rest"

* tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt:
  fscrypt: log the crypto algorithm implementations
  fscrypt: add Speck128/256 support
  fscrypt: only derive the needed portion of the key
  fscrypt: separate key lookup from key derivation
  fscrypt: use a common logging function
  fscrypt: remove internal key size constants
  fscrypt: remove unnecessary check for non-logon key type
  fscrypt: make fscrypt_operations.max_namelen an integer
  fscrypt: drop empty name check from fname_decrypt()
  fscrypt: drop max_namelen check from fname_decrypt()
  fscrypt: don't special-case EOPNOTSUPP from fscrypt_get_encryption_info()
  fscrypt: don't clear flags on crypto transform
  fscrypt: remove stale comment from fscrypt_d_revalidate()
  fscrypt: remove error messages for skcipher_request_alloc() failure
  fscrypt: remove unnecessary NULL check when allocating skcipher
  fscrypt: clean up after fscrypt_prepare_lookup() conversions
  fs, fscrypt: only define ->s_cop when FS_ENCRYPTION is enabled
  fscrypt: use unbound workqueue for decryption
parents 6567af78 e1cc40e5
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -191,11 +191,21 @@ Currently, the following pairs of encryption modes are supported:


- AES-256-XTS for contents and AES-256-CTS-CBC for filenames
- AES-256-XTS for contents and AES-256-CTS-CBC for filenames
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames
- Speck128/256-XTS for contents and Speck128/256-CTS-CBC for filenames


It is strongly recommended to use AES-256-XTS for contents encryption.
It is strongly recommended to use AES-256-XTS for contents encryption.
AES-128-CBC was added only for low-powered embedded devices with
AES-128-CBC was added only for low-powered embedded devices with
crypto accelerators such as CAAM or CESA that do not support XTS.
crypto accelerators such as CAAM or CESA that do not support XTS.


Similarly, Speck128/256 support was only added for older or low-end
CPUs which cannot do AES fast enough -- especially ARM CPUs which have
NEON instructions but not the Cryptography Extensions -- and for which
it would not otherwise be feasible to use encryption at all.  It is
not recommended to use Speck on CPUs that have AES instructions.
Speck support is only available if it has been enabled in the crypto
API via CONFIG_CRYPTO_SPECK.  Also, on ARM platforms, to get
acceptable performance CONFIG_CRYPTO_SPECK_NEON must be enabled.

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
+36 −11
Original line number Original line Diff line number Diff line
@@ -156,12 +156,8 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
	}
	}


	req = skcipher_request_alloc(tfm, gfp_flags);
	req = skcipher_request_alloc(tfm, gfp_flags);
	if (!req) {
	if (!req)
		printk_ratelimited(KERN_ERR
				"%s: crypto_request_alloc() failed\n",
				__func__);
		return -ENOMEM;
		return -ENOMEM;
	}


	skcipher_request_set_callback(
	skcipher_request_set_callback(
		req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
		req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
@@ -178,9 +174,10 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
		res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
		res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
	skcipher_request_free(req);
	skcipher_request_free(req);
	if (res) {
	if (res) {
		printk_ratelimited(KERN_ERR
		fscrypt_err(inode->i_sb,
			"%s: crypto_skcipher_encrypt() returned %d\n",
			    "%scryption failed for inode %lu, block %llu: %d",
			__func__, res);
			    (rw == FS_DECRYPT ? "de" : "en"),
			    inode->i_ino, lblk_num, res);
		return res;
		return res;
	}
	}
	return 0;
	return 0;
@@ -326,7 +323,6 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
		return 0;
		return 0;
	}
	}


	/* this should eventually be an flag in d_flags */
	spin_lock(&dentry->d_lock);
	spin_lock(&dentry->d_lock);
	cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
	cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
	spin_unlock(&dentry->d_lock);
	spin_unlock(&dentry->d_lock);
@@ -353,7 +349,6 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
const struct dentry_operations fscrypt_d_ops = {
const struct dentry_operations fscrypt_d_ops = {
	.d_revalidate = fscrypt_d_revalidate,
	.d_revalidate = fscrypt_d_revalidate,
};
};
EXPORT_SYMBOL(fscrypt_d_ops);


void fscrypt_restore_control_page(struct page *page)
void fscrypt_restore_control_page(struct page *page)
{
{
@@ -422,13 +417,43 @@ int fscrypt_initialize(unsigned int cop_flags)
	return res;
	return res;
}
}


void fscrypt_msg(struct super_block *sb, const char *level,
		 const char *fmt, ...)
{
	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
				      DEFAULT_RATELIMIT_BURST);
	struct va_format vaf;
	va_list args;

	if (!__ratelimit(&rs))
		return;

	va_start(args, fmt);
	vaf.fmt = fmt;
	vaf.va = &args;
	if (sb)
		printk("%sfscrypt (%s): %pV\n", level, sb->s_id, &vaf);
	else
		printk("%sfscrypt: %pV\n", level, &vaf);
	va_end(args);
}

/**
/**
 * fscrypt_init() - Set up for fs encryption.
 * fscrypt_init() - Set up for fs encryption.
 */
 */
static int __init fscrypt_init(void)
static int __init fscrypt_init(void)
{
{
	/*
	 * Use an unbound workqueue to allow bios to be decrypted in parallel
	 * even when they happen to complete on the same CPU.  This sacrifices
	 * locality, but it's worthwhile since decryption is CPU-intensive.
	 *
	 * Also use a high-priority workqueue to prioritize decryption work,
	 * which blocks reads from completing, over regular application tasks.
	 */
	fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
	fscrypt_read_workqueue = alloc_workqueue("fscrypt_read_queue",
							WQ_HIGHPRI, 0);
						 WQ_UNBOUND | WQ_HIGHPRI,
						 num_online_cpus());
	if (!fscrypt_read_workqueue)
	if (!fscrypt_read_workqueue)
		goto fail;
		goto fail;


+11 −21
Original line number Original line Diff line number Diff line
@@ -59,11 +59,8 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,


	/* Set up the encryption request */
	/* Set up the encryption request */
	req = skcipher_request_alloc(tfm, GFP_NOFS);
	req = skcipher_request_alloc(tfm, GFP_NOFS);
	if (!req) {
	if (!req)
		printk_ratelimited(KERN_ERR
			"%s: skcipher_request_alloc() failed\n", __func__);
		return -ENOMEM;
		return -ENOMEM;
	}
	skcipher_request_set_callback(req,
	skcipher_request_set_callback(req,
			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
			crypto_req_done, &wait);
			crypto_req_done, &wait);
@@ -74,8 +71,9 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
	res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
	res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
	skcipher_request_free(req);
	skcipher_request_free(req);
	if (res < 0) {
	if (res < 0) {
		printk_ratelimited(KERN_ERR
		fscrypt_err(inode->i_sb,
				"%s: Error (error code %d)\n", __func__, res);
			    "Filename encryption failed for inode %lu: %d",
			    inode->i_ino, res);
		return res;
		return res;
	}
	}


@@ -96,23 +94,14 @@ static int fname_decrypt(struct inode *inode,
	struct skcipher_request *req = NULL;
	struct skcipher_request *req = NULL;
	DECLARE_CRYPTO_WAIT(wait);
	DECLARE_CRYPTO_WAIT(wait);
	struct scatterlist src_sg, dst_sg;
	struct scatterlist src_sg, dst_sg;
	struct fscrypt_info *ci = inode->i_crypt_info;
	struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
	struct crypto_skcipher *tfm = ci->ci_ctfm;
	int res = 0;
	int res = 0;
	char iv[FS_CRYPTO_BLOCK_SIZE];
	char iv[FS_CRYPTO_BLOCK_SIZE];
	unsigned lim;

	lim = inode->i_sb->s_cop->max_namelen(inode);
	if (iname->len <= 0 || iname->len > lim)
		return -EIO;


	/* Allocate request */
	/* Allocate request */
	req = skcipher_request_alloc(tfm, GFP_NOFS);
	req = skcipher_request_alloc(tfm, GFP_NOFS);
	if (!req) {
	if (!req)
		printk_ratelimited(KERN_ERR
			"%s: crypto_request_alloc() failed\n",  __func__);
		return -ENOMEM;
		return -ENOMEM;
	}
	skcipher_request_set_callback(req,
	skcipher_request_set_callback(req,
		CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
		CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
		crypto_req_done, &wait);
		crypto_req_done, &wait);
@@ -127,8 +116,9 @@ static int fname_decrypt(struct inode *inode,
	res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
	res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
	skcipher_request_free(req);
	skcipher_request_free(req);
	if (res < 0) {
	if (res < 0) {
		printk_ratelimited(KERN_ERR
		fscrypt_err(inode->i_sb,
				"%s: Error (error code %d)\n", __func__, res);
			    "Filename decryption failed for inode %lu: %d",
			    inode->i_ino, res);
		return res;
		return res;
	}
	}


@@ -341,12 +331,12 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
		return 0;
		return 0;
	}
	}
	ret = fscrypt_get_encryption_info(dir);
	ret = fscrypt_get_encryption_info(dir);
	if (ret && ret != -EOPNOTSUPP)
	if (ret)
		return ret;
		return ret;


	if (dir->i_crypt_info) {
	if (dir->i_crypt_info) {
		if (!fscrypt_fname_encrypted_size(dir, iname->len,
		if (!fscrypt_fname_encrypted_size(dir, iname->len,
						  dir->i_sb->s_cop->max_namelen(dir),
						  dir->i_sb->s_cop->max_namelen,
						  &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,
+14 −9
Original line number Original line Diff line number Diff line
@@ -18,14 +18,6 @@


/* Encryption parameters */
/* Encryption parameters */
#define FS_IV_SIZE			16
#define FS_IV_SIZE			16
#define FS_AES_128_ECB_KEY_SIZE		16
#define FS_AES_128_CBC_KEY_SIZE		16
#define FS_AES_128_CTS_KEY_SIZE		16
#define FS_AES_256_GCM_KEY_SIZE		32
#define FS_AES_256_CBC_KEY_SIZE		32
#define FS_AES_256_CTS_KEY_SIZE		32
#define FS_AES_256_XTS_KEY_SIZE		64

#define FS_KEY_DERIVATION_NONCE_SIZE	16
#define FS_KEY_DERIVATION_NONCE_SIZE	16


/**
/**
@@ -91,6 +83,10 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
	    filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
	    filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
		return true;
		return true;


	if (contents_mode == FS_ENCRYPTION_MODE_SPECK128_256_XTS &&
	    filenames_mode == FS_ENCRYPTION_MODE_SPECK128_256_CTS)
		return true;

	return false;
	return false;
}
}


@@ -106,6 +102,15 @@ extern int fscrypt_do_page_crypto(const struct inode *inode,
				  gfp_t gfp_flags);
				  gfp_t gfp_flags);
extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
					      gfp_t gfp_flags);
					      gfp_t gfp_flags);
extern const struct dentry_operations fscrypt_d_ops;

extern void __printf(3, 4) __cold
fscrypt_msg(struct super_block *sb, const char *level, const char *fmt, ...);

#define fscrypt_warn(sb, fmt, ...)		\
	fscrypt_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
#define fscrypt_err(sb, fmt, ...)		\
	fscrypt_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)


/* fname.c */
/* fname.c */
extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
+3 −2
Original line number Original line Diff line number Diff line
@@ -39,7 +39,8 @@ int fscrypt_file_open(struct inode *inode, struct file *filp)
	dir = dget_parent(file_dentry(filp));
	dir = dget_parent(file_dentry(filp));
	if (IS_ENCRYPTED(d_inode(dir)) &&
	if (IS_ENCRYPTED(d_inode(dir)) &&
	    !fscrypt_has_permitted_context(d_inode(dir), inode)) {
	    !fscrypt_has_permitted_context(d_inode(dir), inode)) {
		pr_warn_ratelimited("fscrypt: inconsistent encryption contexts: %lu/%lu",
		fscrypt_warn(inode->i_sb,
			     "inconsistent encryption contexts: %lu/%lu",
			     d_inode(dir)->i_ino, inode->i_ino);
			     d_inode(dir)->i_ino, inode->i_ino);
		err = -EPERM;
		err = -EPERM;
	}
	}
Loading