1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 258ae7468SRichard Weinberger /* 358ae7468SRichard Weinberger * This contains encryption functions for per-file encryption. 458ae7468SRichard Weinberger * 558ae7468SRichard Weinberger * Copyright (C) 2015, Google, Inc. 658ae7468SRichard Weinberger * Copyright (C) 2015, Motorola Mobility 758ae7468SRichard Weinberger * 858ae7468SRichard Weinberger * Written by Michael Halcrow, 2014. 958ae7468SRichard Weinberger * 1058ae7468SRichard Weinberger * Filename encryption additions 1158ae7468SRichard Weinberger * Uday Savagaonkar, 2014 1258ae7468SRichard Weinberger * Encryption policy handling additions 1358ae7468SRichard Weinberger * Ildar Muslukhov, 2014 1458ae7468SRichard Weinberger * Add fscrypt_pullback_bio_page() 1558ae7468SRichard Weinberger * Jaegeuk Kim, 2015. 1658ae7468SRichard Weinberger * 1758ae7468SRichard Weinberger * This has not yet undergone a rigorous security audit. 1858ae7468SRichard Weinberger * 1958ae7468SRichard Weinberger * The usage of AES-XTS should conform to recommendations in NIST 2058ae7468SRichard Weinberger * Special Publication 800-38E and IEEE P1619/D16. 2158ae7468SRichard Weinberger */ 2258ae7468SRichard Weinberger 2358ae7468SRichard Weinberger #include <linux/pagemap.h> 2458ae7468SRichard Weinberger #include <linux/module.h> 2558ae7468SRichard Weinberger #include <linux/bio.h> 2658ae7468SRichard Weinberger #include <linux/namei.h> 2758ae7468SRichard Weinberger #include "fscrypt_private.h" 2858ae7468SRichard Weinberger 290cb8dae4SEric Biggers static void __fscrypt_decrypt_bio(struct bio *bio, bool done) 3058ae7468SRichard Weinberger { 3158ae7468SRichard Weinberger struct bio_vec *bv; 326dc4f100SMing Lei struct bvec_iter_all iter_all; 3358ae7468SRichard Weinberger 342b070cfeSChristoph Hellwig bio_for_each_segment_all(bv, bio, iter_all) { 3558ae7468SRichard Weinberger struct page *page = bv->bv_page; 3658ae7468SRichard Weinberger int ret = fscrypt_decrypt_page(page->mapping->host, page, 3758ae7468SRichard Weinberger PAGE_SIZE, 0, page->index); 3858ae7468SRichard Weinberger 39ff5d3a97SEric Biggers if (ret) 4058ae7468SRichard Weinberger SetPageError(page); 41ff5d3a97SEric Biggers else if (done) 4258ae7468SRichard Weinberger SetPageUptodate(page); 430cb8dae4SEric Biggers if (done) 4458ae7468SRichard Weinberger unlock_page(page); 4558ae7468SRichard Weinberger } 460cb8dae4SEric Biggers } 470cb8dae4SEric Biggers 480cb8dae4SEric Biggers void fscrypt_decrypt_bio(struct bio *bio) 490cb8dae4SEric Biggers { 500cb8dae4SEric Biggers __fscrypt_decrypt_bio(bio, false); 510cb8dae4SEric Biggers } 520cb8dae4SEric Biggers EXPORT_SYMBOL(fscrypt_decrypt_bio); 530cb8dae4SEric Biggers 540cb8dae4SEric Biggers static void completion_pages(struct work_struct *work) 550cb8dae4SEric Biggers { 562a415a02SEric Biggers struct fscrypt_ctx *ctx = container_of(work, struct fscrypt_ctx, work); 572a415a02SEric Biggers struct bio *bio = ctx->bio; 580cb8dae4SEric Biggers 590cb8dae4SEric Biggers __fscrypt_decrypt_bio(bio, true); 6058ae7468SRichard Weinberger fscrypt_release_ctx(ctx); 6158ae7468SRichard Weinberger bio_put(bio); 6258ae7468SRichard Weinberger } 6358ae7468SRichard Weinberger 640cb8dae4SEric Biggers void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) 6558ae7468SRichard Weinberger { 662a415a02SEric Biggers INIT_WORK(&ctx->work, completion_pages); 672a415a02SEric Biggers ctx->bio = bio; 682a415a02SEric Biggers fscrypt_enqueue_decrypt_work(&ctx->work); 6958ae7468SRichard Weinberger } 700cb8dae4SEric Biggers EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); 7158ae7468SRichard Weinberger 7258ae7468SRichard Weinberger int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, 7358ae7468SRichard Weinberger sector_t pblk, unsigned int len) 7458ae7468SRichard Weinberger { 75*930d4539SEric Biggers const unsigned int blockbits = inode->i_blkbits; 76*930d4539SEric Biggers const unsigned int blocksize = 1 << blockbits; 77d2d0727bSEric Biggers struct page *ciphertext_page; 7858ae7468SRichard Weinberger struct bio *bio; 7958ae7468SRichard Weinberger int ret, err = 0; 8058ae7468SRichard Weinberger 81d2d0727bSEric Biggers ciphertext_page = fscrypt_alloc_bounce_page(GFP_NOWAIT); 82d2d0727bSEric Biggers if (!ciphertext_page) 83d2d0727bSEric Biggers return -ENOMEM; 8458ae7468SRichard Weinberger 8558ae7468SRichard Weinberger while (len--) { 86f47fcbb2SEric Biggers err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk, 8758ae7468SRichard Weinberger ZERO_PAGE(0), ciphertext_page, 88*930d4539SEric Biggers blocksize, 0, GFP_NOFS); 8958ae7468SRichard Weinberger if (err) 9058ae7468SRichard Weinberger goto errout; 9158ae7468SRichard Weinberger 9258ae7468SRichard Weinberger bio = bio_alloc(GFP_NOWAIT, 1); 9358ae7468SRichard Weinberger if (!bio) { 9458ae7468SRichard Weinberger err = -ENOMEM; 9558ae7468SRichard Weinberger goto errout; 9658ae7468SRichard Weinberger } 9774d46992SChristoph Hellwig bio_set_dev(bio, inode->i_sb->s_bdev); 98*930d4539SEric Biggers bio->bi_iter.bi_sector = pblk << (blockbits - 9); 9958ae7468SRichard Weinberger bio_set_op_attrs(bio, REQ_OP_WRITE, 0); 100*930d4539SEric Biggers ret = bio_add_page(bio, ciphertext_page, blocksize, 0); 101*930d4539SEric Biggers if (WARN_ON(ret != blocksize)) { 10258ae7468SRichard Weinberger /* should never happen! */ 10358ae7468SRichard Weinberger bio_put(bio); 10458ae7468SRichard Weinberger err = -EIO; 10558ae7468SRichard Weinberger goto errout; 10658ae7468SRichard Weinberger } 10758ae7468SRichard Weinberger err = submit_bio_wait(bio); 1084e4cbee9SChristoph Hellwig if (err == 0 && bio->bi_status) 10958ae7468SRichard Weinberger err = -EIO; 11058ae7468SRichard Weinberger bio_put(bio); 11158ae7468SRichard Weinberger if (err) 11258ae7468SRichard Weinberger goto errout; 11358ae7468SRichard Weinberger lblk++; 11458ae7468SRichard Weinberger pblk++; 11558ae7468SRichard Weinberger } 11658ae7468SRichard Weinberger err = 0; 11758ae7468SRichard Weinberger errout: 118d2d0727bSEric Biggers fscrypt_free_bounce_page(ciphertext_page); 11958ae7468SRichard Weinberger return err; 12058ae7468SRichard Weinberger } 12158ae7468SRichard Weinberger EXPORT_SYMBOL(fscrypt_zeroout_range); 122