Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | // SPDX-License-Identifier: GPL-2.0 /* * This contains encryption functions for per-file encryption. * * Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Motorola Mobility * * Written by Michael Halcrow, 2014. * * Filename encryption additions * Uday Savagaonkar, 2014 * Encryption policy handling additions * Ildar Muslukhov, 2014 * Add fscrypt_pullback_bio_page() * Jaegeuk Kim, 2015. * * This has not yet undergone a rigorous security audit. * * The usage of AES-XTS should conform to recommendations in NIST * Special Publication 800-38E and IEEE P1619/D16. */ #include <linux/pagemap.h> #include <linux/module.h> #include <linux/bio.h> #include <linux/namei.h> #include "fscrypt_private.h" /* * Call fscrypt_decrypt_page on every single page, reusing the encryption * context. */ static void completion_pages(struct work_struct *work) { struct fscrypt_ctx *ctx = container_of(work, struct fscrypt_ctx, r.work); struct bio *bio = ctx->r.bio; struct bio_vec *bv; int i; bio_for_each_segment_all(bv, bio, i) { struct page *page = bv->bv_page; int ret = fscrypt_decrypt_page(page->mapping->host, page, PAGE_SIZE, 0, page->index); if (ret) { WARN_ON_ONCE(1); SetPageError(page); } else { SetPageUptodate(page); } unlock_page(page); } fscrypt_release_ctx(ctx); bio_put(bio); } void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) { INIT_WORK(&ctx->r.work, completion_pages); ctx->r.bio = bio; queue_work(fscrypt_read_workqueue, &ctx->r.work); } EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); void fscrypt_pullback_bio_page(struct page **page, bool restore) { struct fscrypt_ctx *ctx; struct page *bounce_page; /* The bounce data pages are unmapped. */ if ((*page)->mapping) return; /* The bounce data page is unmapped. */ bounce_page = *page; ctx = (struct fscrypt_ctx *)page_private(bounce_page); /* restore control page */ *page = ctx->w.control_page; if (restore) fscrypt_restore_control_page(bounce_page); } EXPORT_SYMBOL(fscrypt_pullback_bio_page); int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { struct fscrypt_ctx *ctx; struct page *ciphertext_page = NULL; struct bio *bio; int ret, err = 0; BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); ctx = fscrypt_get_ctx(inode, GFP_NOFS); if (IS_ERR(ctx)) return PTR_ERR(ctx); ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT); if (IS_ERR(ciphertext_page)) { err = PTR_ERR(ciphertext_page); goto errout; } while (len--) { err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk, ZERO_PAGE(0), ciphertext_page, PAGE_SIZE, 0, GFP_NOFS); if (err) goto errout; bio = bio_alloc(GFP_NOWAIT, 1); if (!bio) { err = -ENOMEM; goto errout; } bio_set_dev(bio, inode->i_sb->s_bdev); bio->bi_iter.bi_sector = pblk << (inode->i_sb->s_blocksize_bits - 9); bio_set_op_attrs(bio, REQ_OP_WRITE, 0); ret = bio_add_page(bio, ciphertext_page, inode->i_sb->s_blocksize, 0); if (ret != inode->i_sb->s_blocksize) { /* should never happen! */ WARN_ON(1); bio_put(bio); err = -EIO; goto errout; } err = submit_bio_wait(bio); if (err == 0 && bio->bi_status) err = -EIO; bio_put(bio); if (err) goto errout; lblk++; pblk++; } err = 0; errout: fscrypt_release_ctx(ctx); return err; } EXPORT_SYMBOL(fscrypt_zeroout_range); |