#include <linux/bit_spinlock.h>
#include <linux/pagevec.h>
#include <trace/events/block.h>
+#include <linux/fscrypt.h> /* for CONFIG_CRYPTO_DISKCIPHER_DEBUG */
static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
op_flags |= REQ_PRIO;
bio_set_op_attrs(bio, op, op_flags);
+ crypto_diskcipher_debug(BLK_BH, op_flags);
if (bio->bi_opf & REQ_AUX_PRIV)
bio->bi_aux_private = bh->b_private;
submit_bio(bio);
BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE);
- if (fscrypt_disk_encrypted(inode)) {
+ if (__fscrypt_disk_encrypted(inode)) {
ciphertext_page = fscrypt_alloc_bounce_page(NULL, GFP_NOWAIT);
if (!ciphertext_page || IS_ERR(ciphertext_page)) {
err = PTR_ERR(ciphertext_page);
err = -EIO;
goto errout;
}
-#ifdef CONFIG_CRYPTO_DISKCIPHER
- if (fscrypt_has_encryption_key(inode))
- fscrypt_set_bio(inode, bio);
-#endif
+ fscrypt_set_bio(inode, bio);
+ crypto_diskcipher_debug(FS_ZEROPAGE, bio->bi_opf);
err = submit_bio_wait(bio);
if (err == 0 && bio->bi_status)
err = -EIO;
}
EXPORT_SYMBOL(fscrypt_zeroout_range);
+int fscrypt_disk_encrypted(const struct inode *inode)
+{
+ return __fscrypt_disk_encrypted(inode);
+}
+
void fscrypt_set_bio(const struct inode *inode, struct bio *bio)
{
#ifdef CONFIG_CRYPTO_DISKCIPHER
- if (inode->i_crypt_info->ci_dtfm)
+ if (__fscrypt_disk_encrypted(inode))
crypto_diskcipher_set(bio, inode->i_crypt_info->ci_dtfm);
-#else
+#endif
return;
+}
+
+void *fscrypt_get_diskcipher(const struct inode *inode)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ if (fscrypt_has_encryption_key(inode))
+ return inode->i_crypt_info->ci_dtfm;
#endif
+ return NULL;
}
if (ci == NULL)
return ERR_PTR(-ENOKEY);
- if (fscrypt_disk_encrypted(inode))
+ if (__fscrypt_disk_encrypted(inode))
return NULL;
/*
struct page *ciphertext_page = page;
int err;
- if (fscrypt_disk_encrypted(inode))
- return NULL;
+#ifdef CONFIG_CRYPTO_DISKCIPHER_DEBUG
+ if (__fscrypt_disk_encrypted(inode))
+ crypto_diskcipher_debug(FS_ENC_WARN, 0);
+#endif
if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
/* with inplace-encryption we just encrypt the page */
int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs, u64 lblk_num)
{
+#ifdef CONFIG_CRYPTO_DISKCIPHER_DEBUG
+ if (__fscrypt_disk_encrypted(inode))
+ crypto_diskcipher_debug(FS_DEC_WARN, 0);
+#endif
if (WARN_ON_ONCE(!PageLocked(page) &&
!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES)))
return -EINVAL;
- if (fscrypt_disk_encrypted(page->mapping->host))
- return 0;
return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
len, offs, GFP_NOFS);
}
#define __FS_HAS_ENCRYPTION 1
#include <linux/fscrypt.h>
#include <crypto/hash.h>
-#include <crypto/diskcipher.h>
/* Encryption parameters */
#define FS_IV_SIZE 16
/* keyinfo.c */
extern void __exit fscrypt_essiv_cleanup(void);
-static inline int fscrypt_disk_encrypted(const struct inode *inode)
+static inline int __fscrypt_disk_encrypted(const struct inode *inode)
{
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
#if IS_ENABLED(CONFIG_CRYPTO_DISKCIPHER)
#if defined(CONFIG_CRYPTO_DISKCIPHER)
if (ci->ci_dtfm)
- crypto_free_diskcipher(ci->ci_dtfm);
+ crypto_free_req_diskcipher(ci->ci_dtfm);
#endif
crypto_free_skcipher(ci->ci_ctfm);
crypto_free_cipher(ci->ci_essiv_tfm);
if (!res) {
if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
crypt_info = NULL;
- pr_debug("%s: (inode %lu) uses diskcipher tfm\n",
- __func__, inode->i_ino);
+ pr_debug("%s: (inode %p:%lu, fscrypt:%p) uses diskcipher tfm\n",
+ __func__, inode, inode->i_ino, inode->i_crypt_info);
goto out;
} else {
pr_warn("%s: error %d fails to set diskciher key\n",
spin_unlock_irqrestore(&dio->bio_lock, flags);
#if defined(CONFIG_EXT4_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER)
- if (dio->inode && fscrypt_has_encryption_key(dio->inode))
+ if (dio->inode && fscrypt_has_encryption_key(dio->inode)) {
fscrypt_set_bio(dio->inode, bio);
+ crypto_diskcipher_debug(FS_DIO, bio->bi_opf);
+ }
#endif
if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty)
bio_set_pages_dirty(bio);
if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
!buffer_unwritten(bh) &&
(block_start < from || block_end > to)) {
- ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+ int bi_opf = 0;
+
+ if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode)
+ && fscrypt_has_encryption_key(inode)) {
+ bh->b_private = fscrypt_get_diskcipher(inode);
+ if (bh->b_private)
+ bi_opf = REQ_CRYPT | REQ_AUX_PRIV;
+ }
+ ll_rw_block(REQ_OP_READ, bi_opf, 1, &bh);
+ crypto_diskcipher_debug(FS_BLOCK_WRITE, bi_opf);
*wait_bh++ = bh;
decrypt = ext4_encrypted_inode(inode) &&
- S_ISREG(inode->i_mode);
+ S_ISREG(inode->i_mode) && !bh->b_private;
}
}
/*
ssize_t ret;
int rw = iov_iter_rw(iter);
-#if defined(CONFIG_EXT4_FS_ENCRYPTION) && !defined(CONFIG_CRYPTO_DISKCIPHER)
- if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
+ if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)
+ && !fscrypt_disk_encrypted(inode))
return 0;
-#elif defined(CONFIG_CRYPTO_DISKCIPHER)
- if (ext4_encrypted_inode(inode) && !fscrypt_has_encryption_key(inode))
- return 0;
-#endif
-
/*
* If we are doing data journalling we don't support O_DIRECT
*/
if (!buffer_uptodate(bh)) {
err = -EIO;
- ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+ if (S_ISREG(inode->i_mode) && ext4_encrypted_inode(inode)
+ && fscrypt_has_encryption_key(inode))
+ bh->b_private = fscrypt_get_diskcipher(inode);
+ if (bh->b_private)
+ ll_rw_block(REQ_OP_READ, REQ_CRYPT, 1, &bh);
+ else
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+
wait_on_buffer(bh);
/* Uhhuh. Read error. Complain and punt. */
if (!buffer_uptodate(bh))
/* We expect the key to be set. */
BUG_ON(!fscrypt_has_encryption_key(inode));
BUG_ON(blocksize != PAGE_SIZE);
- WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host,
+
+ if (!bh->b_private)
+ WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host,
page, PAGE_SIZE, 0, page->index));
}
}
int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ?
REQ_SYNC : 0;
io->io_bio->bi_write_hint = io->io_end->inode->i_write_hint;
- if (bio->bi_opf & REQ_CRYPT)
- io_op_flags |= (REQ_CRYPT | REQ_AUX_PRIV);
bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags);
+ if (ext4_encrypted_inode(io->io_end->inode) &&
+ S_ISREG(io->io_end->inode->i_mode)) {
+ fscrypt_set_bio(io->io_end->inode, io->io_bio);
+ crypto_diskcipher_debug(FS_PAGEIO, io->io_bio->bi_opf);
+ }
submit_bio(io->io_bio);
}
io->io_bio = NULL;
ret = io_submit_init_bio(io, bh);
if (ret)
return ret;
-#if defined(CONFIG_EXT4_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER)
- if (ext4_encrypted_inode(inode) &&
- S_ISREG(inode->i_mode) && fscrypt_has_encryption_key(inode))
- fscrypt_set_bio(inode, io->io_bio);
-#endif
io->io_bio->bi_write_hint = inode->i_write_hint;
}
ret = bio_add_page(io->io_bio, page, bh->b_size, bh_offset(bh));
bh = head = page_buffers(page);
if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) &&
- nr_to_submit) {
+ nr_to_submit && !fscrypt_disk_encrypted(inode)) {
gfp_t gfp_flags = GFP_NOFS;
/*
bio->bi_end_io = mpage_end_io;
bio->bi_private = ctx;
bio_set_op_attrs(bio, REQ_OP_READ, 0);
-#if defined(CONFIG_EXT4_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER)
- if (ext4_encrypted_inode(inode) &&
- S_ISREG(inode->i_mode) && fscrypt_has_encryption_key(inode))
+ if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
fscrypt_set_bio(inode, bio);
-#endif
+ crypto_diskcipher_debug(FS_READP, bio->bi_opf);
+ }
}
length = first_hole << blkbits;
#define _LINUX_FSCRYPT_H
#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/dcache.h>
+#include <crypto/skcipher.h>
+#include <uapi/linux/fs.h>
+#include <crypto/diskcipher.h>
#define FS_CRYPTO_BLOCK_SIZE 16
return -EOPNOTSUPP;
}
+static inline int fscrypt_disk_encrypted(const struct inode *inode)
+{
+ return;
+}
+
static inline void fscrypt_set_bio(const struct inode *inode, struct bio *bio)
{
return;
}
+static inline void *fscrypt_get_diskcipher(const struct inode *inode)
+{
+ return NULL;
+}
+
static inline int __fscrypt_prepare_symlink(struct inode *dir,
unsigned int len,
unsigned int max_len,
extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
unsigned int);
void fscrypt_set_bio(const struct inode *inode, struct bio *bio);
+void *fscrypt_get_diskcipher(const struct inode *inode);
+int fscrypt_disk_encrypted(const struct inode *inode);
+
/* hooks.c */
extern int fscrypt_file_open(struct inode *inode, struct file *filp);
extern int __fscrypt_prepare_link(struct inode *inode, struct inode *dir);