Various cleanups for the file system encryption feature.
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAlirP6wACgkQ8vlZVpUN gaMwpQgApR67CxzlstxYjZpWPAqC8McJ2FBDX+mCOle5Vkc1WQDklwr0oCfQThTj eDSFRhNfIvyPh0DJ589PxBCsWOqN5h6Si7hD5ZinomVNI+IL89OytaU5EV2OpWaW iKdJgO9Tm8U7LuY6FOIoVdX57kUXVdkWoj61rC056B1SNhnNiVeofi7lYDM8Ix4q IGSQ9W24iQKmCk4hCwgObhJBRK9RnlOH0GLUmpMaS+jnfnj/uePwdxWEFsPuCOob 8acAJ49lr55kjIw79E0BAyWxhEZ2aiArHk8PaWynT/DyNq3ftcapPlpftoeba8vo glBJRX70QxPvt0iHEp0ykfExkhWhFA== =Joki -----END PGP SIGNATURE----- Merge tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt Pull fscrypt updates from Ted Ts'o: "Various cleanups for the file system encryption feature" * tag 'fscrypt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt: fscrypt: constify struct fscrypt_operations fscrypt: properly declare on-stack completion fscrypt: split supp and notsupp declarations into their own headers fscrypt: remove redundant assignment of res fscrypt: make fscrypt_operations.key_prefix a string fscrypt: remove unused 'mode' member of fscrypt_ctx ext4: don't allow encrypted operations without keys fscrypt: make test_dummy_encryption require a keyring key fscrypt: factor out bio specific functions fscrypt: pass up error codes from ->get_context() fscrypt: remove user-triggerable warning messages fscrypt: use EEXIST when file already uses different policy fscrypt: use ENOTDIR when setting encryption policy on nondirectory fscrypt: use ENOKEY when file cannot be created w/o key
This commit is contained in:
commit
6c24337f22
|
@ -5281,7 +5281,7 @@ M: Jaegeuk Kim <jaegeuk@kernel.org>
|
|||
L: linux-fsdevel@vger.kernel.org
|
||||
S: Supported
|
||||
F: fs/crypto/
|
||||
F: include/linux/fscrypto.h
|
||||
F: include/linux/fscrypt*.h
|
||||
|
||||
F2FS FILE SYSTEM
|
||||
M: Jaegeuk Kim <jaegeuk@kernel.org>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
config FS_ENCRYPTION
|
||||
tristate "FS Encryption (Per-file encryption)"
|
||||
depends on BLOCK
|
||||
select CRYPTO
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CBC
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
obj-$(CONFIG_FS_ENCRYPTION) += fscrypto.o
|
||||
|
||||
fscrypto-y := crypto.o fname.o policy.o keyinfo.o
|
||||
fscrypto-$(CONFIG_BLOCK) += bio.o
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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->bi_bdev = 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_error)
|
||||
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);
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/namei.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
@ -44,7 +43,7 @@ static mempool_t *fscrypt_bounce_page_pool = NULL;
|
|||
static LIST_HEAD(fscrypt_free_ctxs);
|
||||
static DEFINE_SPINLOCK(fscrypt_ctx_lock);
|
||||
|
||||
static struct workqueue_struct *fscrypt_read_workqueue;
|
||||
struct workqueue_struct *fscrypt_read_workqueue;
|
||||
static DEFINE_MUTEX(fscrypt_init_mutex);
|
||||
|
||||
static struct kmem_cache *fscrypt_ctx_cachep;
|
||||
|
@ -141,16 +140,10 @@ static void page_crypt_complete(struct crypto_async_request *req, int res)
|
|||
complete(&ecr->completion);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FS_DECRYPT = 0,
|
||||
FS_ENCRYPT,
|
||||
} fscrypt_direction_t;
|
||||
|
||||
static int do_page_crypto(const struct inode *inode,
|
||||
fscrypt_direction_t rw, u64 lblk_num,
|
||||
struct page *src_page, struct page *dest_page,
|
||||
unsigned int len, unsigned int offs,
|
||||
gfp_t gfp_flags)
|
||||
int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
||||
u64 lblk_num, struct page *src_page,
|
||||
struct page *dest_page, unsigned int len,
|
||||
unsigned int offs, gfp_t gfp_flags)
|
||||
{
|
||||
struct {
|
||||
__le64 index;
|
||||
|
@ -205,7 +198,8 @@ static int do_page_crypto(const struct inode *inode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct page *alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags)
|
||||
struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
ctx->w.bounce_page = mempool_alloc(fscrypt_bounce_page_pool, gfp_flags);
|
||||
if (ctx->w.bounce_page == NULL)
|
||||
|
@ -260,9 +254,9 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
|
|||
|
||||
if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
|
||||
/* with inplace-encryption we just encrypt the page */
|
||||
err = do_page_crypto(inode, FS_ENCRYPT, lblk_num,
|
||||
page, ciphertext_page,
|
||||
len, offs, gfp_flags);
|
||||
err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page,
|
||||
ciphertext_page, len, offs,
|
||||
gfp_flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
|
@ -276,14 +270,14 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
|
|||
return (struct page *)ctx;
|
||||
|
||||
/* The encryption operation will require a bounce page. */
|
||||
ciphertext_page = alloc_bounce_page(ctx, gfp_flags);
|
||||
ciphertext_page = fscrypt_alloc_bounce_page(ctx, gfp_flags);
|
||||
if (IS_ERR(ciphertext_page))
|
||||
goto errout;
|
||||
|
||||
ctx->w.control_page = page;
|
||||
err = do_page_crypto(inode, FS_ENCRYPT, lblk_num,
|
||||
page, ciphertext_page,
|
||||
len, offs, gfp_flags);
|
||||
err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num,
|
||||
page, ciphertext_page, len, offs,
|
||||
gfp_flags);
|
||||
if (err) {
|
||||
ciphertext_page = ERR_PTR(err);
|
||||
goto errout;
|
||||
|
@ -320,72 +314,11 @@ int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
|
|||
if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
|
||||
BUG_ON(!PageLocked(page));
|
||||
|
||||
return do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page, len,
|
||||
offs, GFP_NOFS);
|
||||
return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
|
||||
len, offs, GFP_NOFS);
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_decrypt_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 = alloc_bounce_page(ctx, GFP_NOWAIT);
|
||||
if (IS_ERR(ciphertext_page)) {
|
||||
err = PTR_ERR(ciphertext_page);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
err = 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->bi_bdev = 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_error)
|
||||
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);
|
||||
|
||||
/*
|
||||
* Validate dentries for encrypted directories to make sure we aren't
|
||||
* potentially caching stale data after a key has been added or
|
||||
|
@ -442,64 +375,6 @@ const struct dentry_operations fscrypt_d_ops = {
|
|||
};
|
||||
EXPORT_SYMBOL(fscrypt_d_ops);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
void fscrypt_restore_control_page(struct page *page)
|
||||
{
|
||||
struct fscrypt_ctx *ctx;
|
||||
|
|
|
@ -332,7 +332,7 @@ int fscrypt_fname_usr_to_disk(struct inode *inode,
|
|||
* in a directory. Consequently, a user space name cannot be mapped to
|
||||
* a disk-space name
|
||||
*/
|
||||
return -EACCES;
|
||||
return -ENOKEY;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
|
||||
|
||||
|
@ -367,7 +367,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
|||
return 0;
|
||||
}
|
||||
if (!lookup)
|
||||
return -EACCES;
|
||||
return -ENOKEY;
|
||||
|
||||
/*
|
||||
* We don't have the key and we are doing a lookup; decode the
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#ifndef _FSCRYPT_PRIVATE_H
|
||||
#define _FSCRYPT_PRIVATE_H
|
||||
|
||||
#include <linux/fscrypto.h>
|
||||
#include <linux/fscrypt_supp.h>
|
||||
|
||||
#define FS_FNAME_CRYPTO_DIGEST_SIZE 32
|
||||
|
||||
|
@ -71,6 +71,11 @@ struct fscrypt_info {
|
|||
u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
FS_DECRYPT = 0,
|
||||
FS_ENCRYPT,
|
||||
} fscrypt_direction_t;
|
||||
|
||||
#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
|
||||
#define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002
|
||||
|
||||
|
@ -81,11 +86,20 @@ struct fscrypt_completion_result {
|
|||
|
||||
#define DECLARE_FS_COMPLETION_RESULT(ecr) \
|
||||
struct fscrypt_completion_result ecr = { \
|
||||
COMPLETION_INITIALIZER((ecr).completion), 0 }
|
||||
COMPLETION_INITIALIZER_ONSTACK((ecr).completion), 0 }
|
||||
|
||||
|
||||
/* crypto.c */
|
||||
int fscrypt_initialize(unsigned int cop_flags);
|
||||
extern int fscrypt_initialize(unsigned int cop_flags);
|
||||
extern struct workqueue_struct *fscrypt_read_workqueue;
|
||||
extern int fscrypt_do_page_crypto(const struct inode *inode,
|
||||
fscrypt_direction_t rw, u64 lblk_num,
|
||||
struct page *src_page,
|
||||
struct page *dest_page,
|
||||
unsigned int len, unsigned int offs,
|
||||
gfp_t gfp_flags);
|
||||
extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
|
||||
gfp_t gfp_flags);
|
||||
|
||||
/* keyinfo.c */
|
||||
extern int fscrypt_get_crypt_info(struct inode *);
|
||||
|
|
|
@ -77,26 +77,22 @@ out:
|
|||
|
||||
static int validate_user_key(struct fscrypt_info *crypt_info,
|
||||
struct fscrypt_context *ctx, u8 *raw_key,
|
||||
u8 *prefix, int prefix_size)
|
||||
const char *prefix)
|
||||
{
|
||||
u8 *full_key_descriptor;
|
||||
char *description;
|
||||
struct key *keyring_key;
|
||||
struct fscrypt_key *master_key;
|
||||
const struct user_key_payload *ukp;
|
||||
int full_key_len = prefix_size + (FS_KEY_DESCRIPTOR_SIZE * 2) + 1;
|
||||
int res;
|
||||
|
||||
full_key_descriptor = kmalloc(full_key_len, GFP_NOFS);
|
||||
if (!full_key_descriptor)
|
||||
description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
|
||||
FS_KEY_DESCRIPTOR_SIZE,
|
||||
ctx->master_key_descriptor);
|
||||
if (!description)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(full_key_descriptor, prefix, prefix_size);
|
||||
sprintf(full_key_descriptor + prefix_size,
|
||||
"%*phN", FS_KEY_DESCRIPTOR_SIZE,
|
||||
ctx->master_key_descriptor);
|
||||
full_key_descriptor[full_key_len - 1] = '\0';
|
||||
keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
|
||||
kfree(full_key_descriptor);
|
||||
keyring_key = request_key(&key_type_logon, description, NULL);
|
||||
kfree(description);
|
||||
if (IS_ERR(keyring_key))
|
||||
return PTR_ERR(keyring_key);
|
||||
|
||||
|
@ -206,12 +202,15 @@ retry:
|
|||
|
||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (res < 0) {
|
||||
if (!fscrypt_dummy_context_enabled(inode))
|
||||
if (!fscrypt_dummy_context_enabled(inode) ||
|
||||
inode->i_sb->s_cop->is_encrypted(inode))
|
||||
return res;
|
||||
/* Fake up a context for an unencrypted directory */
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
|
||||
ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
|
||||
ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
|
||||
ctx.flags = 0;
|
||||
memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
|
||||
} else if (res != sizeof(ctx)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -247,21 +246,10 @@ retry:
|
|||
if (!raw_key)
|
||||
goto out;
|
||||
|
||||
if (fscrypt_dummy_context_enabled(inode)) {
|
||||
memset(raw_key, 0x42, keysize/2);
|
||||
memset(raw_key+keysize/2, 0x24, keysize - (keysize/2));
|
||||
goto got_key;
|
||||
}
|
||||
|
||||
res = validate_user_key(crypt_info, &ctx, raw_key,
|
||||
FS_KEY_DESC_PREFIX, FS_KEY_DESC_PREFIX_SIZE);
|
||||
res = validate_user_key(crypt_info, &ctx, raw_key, FS_KEY_DESC_PREFIX);
|
||||
if (res && inode->i_sb->s_cop->key_prefix) {
|
||||
u8 *prefix = NULL;
|
||||
int prefix_size, res2;
|
||||
|
||||
prefix_size = inode->i_sb->s_cop->key_prefix(inode, &prefix);
|
||||
res2 = validate_user_key(crypt_info, &ctx, raw_key,
|
||||
prefix, prefix_size);
|
||||
int res2 = validate_user_key(crypt_info, &ctx, raw_key,
|
||||
inode->i_sb->s_cop->key_prefix);
|
||||
if (res2) {
|
||||
if (res2 == -ENOKEY)
|
||||
res = -ENOKEY;
|
||||
|
@ -270,7 +258,6 @@ retry:
|
|||
} else if (res) {
|
||||
goto out;
|
||||
}
|
||||
got_key:
|
||||
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
|
||||
if (!ctfm || IS_ERR(ctfm)) {
|
||||
res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
|
||||
|
|
|
@ -13,37 +13,20 @@
|
|||
#include <linux/mount.h>
|
||||
#include "fscrypt_private.h"
|
||||
|
||||
static int inode_has_encryption_context(struct inode *inode)
|
||||
{
|
||||
if (!inode->i_sb->s_cop->get_context)
|
||||
return 0;
|
||||
return (inode->i_sb->s_cop->get_context(inode, NULL, 0L) > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* check whether the policy is consistent with the encryption context
|
||||
* for the inode
|
||||
* check whether an encryption policy is consistent with an encryption context
|
||||
*/
|
||||
static int is_encryption_context_consistent_with_policy(struct inode *inode,
|
||||
static bool is_encryption_context_consistent_with_policy(
|
||||
const struct fscrypt_context *ctx,
|
||||
const struct fscrypt_policy *policy)
|
||||
{
|
||||
struct fscrypt_context ctx;
|
||||
int res;
|
||||
|
||||
if (!inode->i_sb->s_cop->get_context)
|
||||
return 0;
|
||||
|
||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (res != sizeof(ctx))
|
||||
return 0;
|
||||
|
||||
return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
|
||||
return memcmp(ctx->master_key_descriptor, policy->master_key_descriptor,
|
||||
FS_KEY_DESCRIPTOR_SIZE) == 0 &&
|
||||
(ctx.flags == policy->flags) &&
|
||||
(ctx.contents_encryption_mode ==
|
||||
(ctx->flags == policy->flags) &&
|
||||
(ctx->contents_encryption_mode ==
|
||||
policy->contents_encryption_mode) &&
|
||||
(ctx.filenames_encryption_mode ==
|
||||
policy->filenames_encryption_mode));
|
||||
(ctx->filenames_encryption_mode ==
|
||||
policy->filenames_encryption_mode);
|
||||
}
|
||||
|
||||
static int create_encryption_context_from_policy(struct inode *inode,
|
||||
|
@ -66,20 +49,12 @@ static int create_encryption_context_from_policy(struct inode *inode,
|
|||
FS_KEY_DESCRIPTOR_SIZE);
|
||||
|
||||
if (!fscrypt_valid_contents_enc_mode(
|
||||
policy->contents_encryption_mode)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Invalid contents encryption mode %d\n", __func__,
|
||||
policy->contents_encryption_mode);
|
||||
policy->contents_encryption_mode))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!fscrypt_valid_filenames_enc_mode(
|
||||
policy->filenames_encryption_mode)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Invalid filenames encryption mode %d\n", __func__,
|
||||
policy->filenames_encryption_mode);
|
||||
policy->filenames_encryption_mode))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (policy->flags & ~FS_POLICY_FLAGS_VALID)
|
||||
return -EINVAL;
|
||||
|
@ -98,6 +73,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
|
|||
struct fscrypt_policy policy;
|
||||
struct inode *inode = file_inode(filp);
|
||||
int ret;
|
||||
struct fscrypt_context ctx;
|
||||
|
||||
if (copy_from_user(&policy, arg, sizeof(policy)))
|
||||
return -EFAULT;
|
||||
|
@ -114,9 +90,10 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
|
|||
|
||||
inode_lock(inode);
|
||||
|
||||
if (!inode_has_encryption_context(inode)) {
|
||||
ret = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (ret == -ENODATA) {
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
ret = -EINVAL;
|
||||
ret = -ENOTDIR;
|
||||
else if (!inode->i_sb->s_cop->empty_dir)
|
||||
ret = -EOPNOTSUPP;
|
||||
else if (!inode->i_sb->s_cop->empty_dir(inode))
|
||||
|
@ -124,12 +101,14 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
|
|||
else
|
||||
ret = create_encryption_context_from_policy(inode,
|
||||
&policy);
|
||||
} else if (!is_encryption_context_consistent_with_policy(inode,
|
||||
} else if (ret == sizeof(ctx) &&
|
||||
is_encryption_context_consistent_with_policy(&ctx,
|
||||
&policy)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Policy inconsistent with encryption context\n",
|
||||
__func__);
|
||||
ret = -EINVAL;
|
||||
/* The file already uses the same encryption policy. */
|
||||
ret = 0;
|
||||
} else if (ret >= 0 || ret == -ERANGE) {
|
||||
/* The file already uses a different encryption policy. */
|
||||
ret = -EEXIST;
|
||||
}
|
||||
|
||||
inode_unlock(inode);
|
||||
|
@ -151,8 +130,10 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
|
|||
return -ENODATA;
|
||||
|
||||
res = inode->i_sb->s_cop->get_context(inode, &ctx, sizeof(ctx));
|
||||
if (res < 0 && res != -ERANGE)
|
||||
return res;
|
||||
if (res != sizeof(ctx))
|
||||
return -ENODATA;
|
||||
return -EINVAL;
|
||||
if (ctx.format != FS_ENCRYPTION_CONTEXT_FORMAT_V1)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -217,9 +198,9 @@ EXPORT_SYMBOL(fscrypt_has_permitted_context);
|
|||
* @parent: Parent inode from which the context is inherited.
|
||||
* @child: Child inode that inherits the context from @parent.
|
||||
* @fs_data: private data given by FS.
|
||||
* @preload: preload child i_crypt_info
|
||||
* @preload: preload child i_crypt_info if true
|
||||
*
|
||||
* Return: Zero on success, non-zero otherwise
|
||||
* Return: 0 on success, -errno on failure
|
||||
*/
|
||||
int fscrypt_inherit_context(struct inode *parent, struct inode *child,
|
||||
void *fs_data, bool preload)
|
||||
|
@ -240,19 +221,11 @@ int fscrypt_inherit_context(struct inode *parent, struct inode *child,
|
|||
return -ENOKEY;
|
||||
|
||||
ctx.format = FS_ENCRYPTION_CONTEXT_FORMAT_V1;
|
||||
if (fscrypt_dummy_context_enabled(parent)) {
|
||||
ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
|
||||
ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
|
||||
ctx.flags = 0;
|
||||
memset(ctx.master_key_descriptor, 0x42, FS_KEY_DESCRIPTOR_SIZE);
|
||||
res = 0;
|
||||
} else {
|
||||
ctx.contents_encryption_mode = ci->ci_data_mode;
|
||||
ctx.filenames_encryption_mode = ci->ci_filename_mode;
|
||||
ctx.flags = ci->ci_flags;
|
||||
memcpy(ctx.master_key_descriptor, ci->ci_master_key,
|
||||
FS_KEY_DESCRIPTOR_SIZE);
|
||||
}
|
||||
get_random_bytes(ctx.nonce, FS_KEY_DERIVATION_NONCE_SIZE);
|
||||
res = parent->i_sb->s_cop->set_context(child, &ctx,
|
||||
sizeof(ctx), fs_data);
|
||||
|
|
|
@ -32,7 +32,11 @@
|
|||
#include <linux/percpu_counter.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/fscrypto.h>
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
#include <linux/fscrypt_supp.h>
|
||||
#else
|
||||
#include <linux/fscrypt_notsupp.h>
|
||||
#endif
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/percpu-rwsem.h>
|
||||
#ifdef __KERNEL__
|
||||
|
@ -1343,11 +1347,6 @@ struct ext4_super_block {
|
|||
/* Number of quota types we support */
|
||||
#define EXT4_MAXQUOTAS 3
|
||||
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
#define EXT4_KEY_DESC_PREFIX "ext4:"
|
||||
#define EXT4_KEY_DESC_PREFIX_SIZE 5
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fourth extended-fs super-block data in memory
|
||||
*/
|
||||
|
@ -1517,12 +1516,6 @@ struct ext4_sb_info {
|
|||
|
||||
/* Barrier between changing inodes' journal flags and writepages ops. */
|
||||
struct percpu_rw_semaphore s_journal_flag_rwsem;
|
||||
|
||||
/* Encryption support */
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
u8 key_prefix[EXT4_KEY_DESC_PREFIX_SIZE];
|
||||
u8 key_prefix_size;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
|
||||
|
@ -2320,28 +2313,6 @@ static inline int ext4_fname_setup_filename(struct inode *dir,
|
|||
}
|
||||
static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
|
||||
|
||||
#define fscrypt_set_d_op(i)
|
||||
#define fscrypt_get_ctx fscrypt_notsupp_get_ctx
|
||||
#define fscrypt_release_ctx fscrypt_notsupp_release_ctx
|
||||
#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page
|
||||
#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page
|
||||
#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages
|
||||
#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page
|
||||
#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page
|
||||
#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range
|
||||
#define fscrypt_ioctl_set_policy fscrypt_notsupp_ioctl_set_policy
|
||||
#define fscrypt_ioctl_get_policy fscrypt_notsupp_ioctl_get_policy
|
||||
#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context
|
||||
#define fscrypt_inherit_context fscrypt_notsupp_inherit_context
|
||||
#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info
|
||||
#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info
|
||||
#define fscrypt_setup_filename fscrypt_notsupp_setup_filename
|
||||
#define fscrypt_free_filename fscrypt_notsupp_free_filename
|
||||
#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size
|
||||
#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer
|
||||
#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer
|
||||
#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr
|
||||
#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk
|
||||
#endif
|
||||
|
||||
/* dir.c */
|
||||
|
|
|
@ -771,7 +771,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
|
|||
if (err)
|
||||
return ERR_PTR(err);
|
||||
if (!fscrypt_has_encryption_key(dir))
|
||||
return ERR_PTR(-EPERM);
|
||||
return ERR_PTR(-ENOKEY);
|
||||
if (!handle)
|
||||
nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb);
|
||||
encrypt = 1;
|
||||
|
|
|
@ -1378,6 +1378,8 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
|
|||
return NULL;
|
||||
|
||||
retval = ext4_fname_setup_filename(dir, d_name, 1, &fname);
|
||||
if (retval == -ENOENT)
|
||||
return NULL;
|
||||
if (retval)
|
||||
return ERR_PTR(retval);
|
||||
|
||||
|
@ -3088,7 +3090,7 @@ static int ext4_symlink(struct inode *dir,
|
|||
if (err)
|
||||
return err;
|
||||
if (!fscrypt_has_encryption_key(dir))
|
||||
return -EPERM;
|
||||
return -ENOKEY;
|
||||
disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
|
||||
sizeof(struct fscrypt_symlink_data));
|
||||
sd = kzalloc(disk_link.len, GFP_KERNEL);
|
||||
|
@ -3525,6 +3527,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
EXT4_I(old_dentry->d_inode)->i_projid)))
|
||||
return -EXDEV;
|
||||
|
||||
if ((ext4_encrypted_inode(old_dir) &&
|
||||
!fscrypt_has_encryption_key(old_dir)) ||
|
||||
(ext4_encrypted_inode(new_dir) &&
|
||||
!fscrypt_has_encryption_key(new_dir)))
|
||||
return -ENOKEY;
|
||||
|
||||
retval = dquot_initialize(old.dir);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
@ -3725,6 +3733,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
int retval;
|
||||
struct timespec ctime;
|
||||
|
||||
if ((ext4_encrypted_inode(old_dir) &&
|
||||
!fscrypt_has_encryption_key(old_dir)) ||
|
||||
(ext4_encrypted_inode(new_dir) &&
|
||||
!fscrypt_has_encryption_key(new_dir)))
|
||||
return -ENOKEY;
|
||||
|
||||
if ((ext4_encrypted_inode(old_dir) ||
|
||||
ext4_encrypted_inode(new_dir)) &&
|
||||
(old_dir != new_dir) &&
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/fscrypto.h>
|
||||
|
||||
#include "ext4_jbd2.h"
|
||||
#include "xattr.h"
|
||||
|
|
|
@ -1100,12 +1100,6 @@ static int ext4_get_context(struct inode *inode, void *ctx, size_t len)
|
|||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len);
|
||||
}
|
||||
|
||||
static int ext4_key_prefix(struct inode *inode, u8 **key)
|
||||
{
|
||||
*key = EXT4_SB(inode->i_sb)->key_prefix;
|
||||
return EXT4_SB(inode->i_sb)->key_prefix_size;
|
||||
}
|
||||
|
||||
static int ext4_prepare_context(struct inode *inode)
|
||||
{
|
||||
return ext4_convert_inline_data(inode);
|
||||
|
@ -1179,9 +1173,9 @@ static unsigned ext4_max_namelen(struct inode *inode)
|
|||
EXT4_NAME_LEN;
|
||||
}
|
||||
|
||||
static struct fscrypt_operations ext4_cryptops = {
|
||||
static const struct fscrypt_operations ext4_cryptops = {
|
||||
.key_prefix = "ext4:",
|
||||
.get_context = ext4_get_context,
|
||||
.key_prefix = ext4_key_prefix,
|
||||
.prepare_context = ext4_prepare_context,
|
||||
.set_context = ext4_set_context,
|
||||
.dummy_context = ext4_dummy_context,
|
||||
|
@ -1190,7 +1184,7 @@ static struct fscrypt_operations ext4_cryptops = {
|
|||
.max_namelen = ext4_max_namelen,
|
||||
};
|
||||
#else
|
||||
static struct fscrypt_operations ext4_cryptops = {
|
||||
static const struct fscrypt_operations ext4_cryptops = {
|
||||
.is_encrypted = ext4_encrypted_inode,
|
||||
};
|
||||
#endif
|
||||
|
@ -4218,11 +4212,6 @@ no_journal:
|
|||
ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10);
|
||||
|
||||
kfree(orig_data);
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX,
|
||||
EXT4_KEY_DESC_PREFIX_SIZE);
|
||||
sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
cantfind_ext4:
|
||||
|
|
|
@ -268,6 +268,9 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
|
|||
|
||||
err = fscrypt_setup_filename(dir, child, 1, &fname);
|
||||
if (err) {
|
||||
if (err == -ENOENT)
|
||||
*res_page = NULL;
|
||||
else
|
||||
*res_page = ERR_PTR(err);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,11 @@
|
|||
#include <linux/vmalloc.h>
|
||||
#include <linux/bio.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/fscrypto.h>
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
#include <linux/fscrypt_supp.h>
|
||||
#else
|
||||
#include <linux/fscrypt_notsupp.h>
|
||||
#endif
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
|
@ -760,10 +764,6 @@ enum {
|
|||
MAX_TIME,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
#define F2FS_KEY_DESC_PREFIX "f2fs:"
|
||||
#define F2FS_KEY_DESC_PREFIX_SIZE 5
|
||||
#endif
|
||||
struct f2fs_sb_info {
|
||||
struct super_block *sb; /* pointer to VFS super block */
|
||||
struct proc_dir_entry *s_proc; /* proc entry */
|
||||
|
@ -771,11 +771,6 @@ struct f2fs_sb_info {
|
|||
int valid_super_block; /* valid super block no */
|
||||
unsigned long s_flag; /* flags for sbi */
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
u8 key_prefix[F2FS_KEY_DESC_PREFIX_SIZE];
|
||||
u8 key_prefix_size;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
unsigned int blocks_per_blkz; /* F2FS blocks per zone */
|
||||
unsigned int log_blocks_per_blkz; /* log2 F2FS blocks per zone */
|
||||
|
@ -2510,28 +2505,4 @@ static inline bool f2fs_may_encrypt(struct inode *inode)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_F2FS_FS_ENCRYPTION
|
||||
#define fscrypt_set_d_op(i)
|
||||
#define fscrypt_get_ctx fscrypt_notsupp_get_ctx
|
||||
#define fscrypt_release_ctx fscrypt_notsupp_release_ctx
|
||||
#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page
|
||||
#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page
|
||||
#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages
|
||||
#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page
|
||||
#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page
|
||||
#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range
|
||||
#define fscrypt_ioctl_set_policy fscrypt_notsupp_ioctl_set_policy
|
||||
#define fscrypt_ioctl_get_policy fscrypt_notsupp_ioctl_get_policy
|
||||
#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context
|
||||
#define fscrypt_inherit_context fscrypt_notsupp_inherit_context
|
||||
#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info
|
||||
#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info
|
||||
#define fscrypt_setup_filename fscrypt_notsupp_setup_filename
|
||||
#define fscrypt_free_filename fscrypt_notsupp_free_filename
|
||||
#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size
|
||||
#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer
|
||||
#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer
|
||||
#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr
|
||||
#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -403,7 +403,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
return err;
|
||||
|
||||
if (!fscrypt_has_encryption_key(dir))
|
||||
return -EPERM;
|
||||
return -ENOKEY;
|
||||
|
||||
disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
|
||||
sizeof(struct fscrypt_symlink_data));
|
||||
|
@ -447,7 +447,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
|||
goto err_out;
|
||||
|
||||
if (!fscrypt_has_encryption_key(inode)) {
|
||||
err = -EPERM;
|
||||
err = -ENOKEY;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
|
|
|
@ -1156,12 +1156,6 @@ static int f2fs_get_context(struct inode *inode, void *ctx, size_t len)
|
|||
ctx, len, NULL);
|
||||
}
|
||||
|
||||
static int f2fs_key_prefix(struct inode *inode, u8 **key)
|
||||
{
|
||||
*key = F2FS_I_SB(inode)->key_prefix;
|
||||
return F2FS_I_SB(inode)->key_prefix_size;
|
||||
}
|
||||
|
||||
static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
|
||||
void *fs_data)
|
||||
{
|
||||
|
@ -1176,16 +1170,16 @@ static unsigned f2fs_max_namelen(struct inode *inode)
|
|||
inode->i_sb->s_blocksize : F2FS_NAME_LEN;
|
||||
}
|
||||
|
||||
static struct fscrypt_operations f2fs_cryptops = {
|
||||
static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.key_prefix = "f2fs:",
|
||||
.get_context = f2fs_get_context,
|
||||
.key_prefix = f2fs_key_prefix,
|
||||
.set_context = f2fs_set_context,
|
||||
.is_encrypted = f2fs_encrypted_inode,
|
||||
.empty_dir = f2fs_empty_dir,
|
||||
.max_namelen = f2fs_max_namelen,
|
||||
};
|
||||
#else
|
||||
static struct fscrypt_operations f2fs_cryptops = {
|
||||
static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.is_encrypted = f2fs_encrypted_inode,
|
||||
};
|
||||
#endif
|
||||
|
@ -1518,12 +1512,6 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
|||
mutex_init(&sbi->wio_mutex[NODE]);
|
||||
mutex_init(&sbi->wio_mutex[DATA]);
|
||||
spin_lock_init(&sbi->cp_lock);
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_ENCRYPTION
|
||||
memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
|
||||
F2FS_KEY_DESC_PREFIX_SIZE);
|
||||
sbi->key_prefix_size = F2FS_KEY_DESC_PREFIX_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int init_percpu_info(struct f2fs_sb_info *sbi)
|
||||
|
|
|
@ -26,15 +26,6 @@ static unsigned int ubifs_crypt_max_namelen(struct inode *inode)
|
|||
return UBIFS_MAX_NLEN;
|
||||
}
|
||||
|
||||
static int ubifs_key_prefix(struct inode *inode, u8 **key)
|
||||
{
|
||||
static char prefix[] = "ubifs:";
|
||||
|
||||
*key = prefix;
|
||||
|
||||
return sizeof(prefix) - 1;
|
||||
}
|
||||
|
||||
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
unsigned int in_len, unsigned int *out_len, int block)
|
||||
{
|
||||
|
@ -86,12 +77,12 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct fscrypt_operations ubifs_crypt_operations = {
|
||||
const struct fscrypt_operations ubifs_crypt_operations = {
|
||||
.flags = FS_CFLG_OWN_PAGES,
|
||||
.key_prefix = "ubifs:",
|
||||
.get_context = ubifs_crypt_get_context,
|
||||
.set_context = ubifs_crypt_set_context,
|
||||
.is_encrypted = __ubifs_crypt_is_encrypted,
|
||||
.empty_dir = ubifs_crypt_empty_dir,
|
||||
.max_namelen = ubifs_crypt_max_namelen,
|
||||
.key_prefix = ubifs_key_prefix,
|
||||
};
|
||||
|
|
|
@ -2000,7 +2000,7 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
|
|||
}
|
||||
|
||||
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
struct fscrypt_operations ubifs_crypt_operations = {
|
||||
const struct fscrypt_operations ubifs_crypt_operations = {
|
||||
.is_encrypted = __ubifs_crypt_is_encrypted,
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,11 @@
|
|||
#include <linux/backing-dev.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/fscrypto.h>
|
||||
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
#include <linux/fscrypt_supp.h>
|
||||
#else
|
||||
#include <linux/fscrypt_notsupp.h>
|
||||
#endif
|
||||
#include <linux/random.h>
|
||||
#include "ubifs-media.h"
|
||||
|
||||
|
@ -1797,28 +1801,6 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
|
|||
#include "key.h"
|
||||
|
||||
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
#define fscrypt_set_d_op(i)
|
||||
#define fscrypt_get_ctx fscrypt_notsupp_get_ctx
|
||||
#define fscrypt_release_ctx fscrypt_notsupp_release_ctx
|
||||
#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page
|
||||
#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page
|
||||
#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages
|
||||
#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page
|
||||
#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page
|
||||
#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range
|
||||
#define fscrypt_ioctl_set_policy fscrypt_notsupp_ioctl_set_policy
|
||||
#define fscrypt_ioctl_get_policy fscrypt_notsupp_ioctl_get_policy
|
||||
#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context
|
||||
#define fscrypt_inherit_context fscrypt_notsupp_inherit_context
|
||||
#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info
|
||||
#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info
|
||||
#define fscrypt_setup_filename fscrypt_notsupp_setup_filename
|
||||
#define fscrypt_free_filename fscrypt_notsupp_free_filename
|
||||
#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size
|
||||
#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer
|
||||
#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer
|
||||
#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr
|
||||
#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk
|
||||
static inline int ubifs_encrypt(const struct inode *inode,
|
||||
struct ubifs_data_node *dn,
|
||||
unsigned int in_len, unsigned int *out_len,
|
||||
|
@ -1842,7 +1824,7 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
|||
unsigned int *out_len, int block);
|
||||
#endif
|
||||
|
||||
extern struct fscrypt_operations ubifs_crypt_operations;
|
||||
extern const struct fscrypt_operations ubifs_crypt_operations;
|
||||
|
||||
static inline bool __ubifs_crypt_is_encrypted(struct inode *inode)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* fscrypt_common.h: common declarations for per-file encryption
|
||||
*
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
*
|
||||
* Written by Michael Halcrow, 2015.
|
||||
* Modified by Jaegeuk Kim, 2015.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FSCRYPT_COMMON_H
|
||||
#define _LINUX_FSCRYPT_COMMON_H
|
||||
|
||||
#include <linux/key.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>
|
||||
|
||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||
|
||||
struct fscrypt_info;
|
||||
|
||||
struct fscrypt_ctx {
|
||||
union {
|
||||
struct {
|
||||
struct page *bounce_page; /* Ciphertext page */
|
||||
struct page *control_page; /* Original page */
|
||||
} w;
|
||||
struct {
|
||||
struct bio *bio;
|
||||
struct work_struct work;
|
||||
} r;
|
||||
struct list_head free_list; /* Free list */
|
||||
};
|
||||
u8 flags; /* Flags */
|
||||
};
|
||||
|
||||
/**
|
||||
* For encrypted symlinks, the ciphertext length is stored at the beginning
|
||||
* of the string in little-endian format.
|
||||
*/
|
||||
struct fscrypt_symlink_data {
|
||||
__le16 len;
|
||||
char encrypted_path[1];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* This function is used to calculate the disk space required to
|
||||
* store a filename of length l in encrypted symlink format.
|
||||
*/
|
||||
static inline u32 fscrypt_symlink_data_len(u32 l)
|
||||
{
|
||||
if (l < FS_CRYPTO_BLOCK_SIZE)
|
||||
l = FS_CRYPTO_BLOCK_SIZE;
|
||||
return (l + sizeof(struct fscrypt_symlink_data) - 1);
|
||||
}
|
||||
|
||||
struct fscrypt_str {
|
||||
unsigned char *name;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct fscrypt_name {
|
||||
const struct qstr *usr_fname;
|
||||
struct fscrypt_str disk_name;
|
||||
u32 hash;
|
||||
u32 minor_hash;
|
||||
struct fscrypt_str crypto_buf;
|
||||
};
|
||||
|
||||
#define FSTR_INIT(n, l) { .name = n, .len = l }
|
||||
#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
|
||||
#define fname_name(p) ((p)->disk_name.name)
|
||||
#define fname_len(p) ((p)->disk_name.len)
|
||||
|
||||
/*
|
||||
* fscrypt superblock flags
|
||||
*/
|
||||
#define FS_CFLG_OWN_PAGES (1U << 1)
|
||||
|
||||
/*
|
||||
* crypto opertions for filesystems
|
||||
*/
|
||||
struct fscrypt_operations {
|
||||
unsigned int flags;
|
||||
const char *key_prefix;
|
||||
int (*get_context)(struct inode *, void *, size_t);
|
||||
int (*prepare_context)(struct inode *);
|
||||
int (*set_context)(struct inode *, const void *, size_t, void *);
|
||||
int (*dummy_context)(struct inode *);
|
||||
bool (*is_encrypted)(struct inode *);
|
||||
bool (*empty_dir)(struct inode *);
|
||||
unsigned (*max_namelen)(struct inode *);
|
||||
};
|
||||
|
||||
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
|
||||
{
|
||||
if (inode->i_sb->s_cop->dummy_context &&
|
||||
inode->i_sb->s_cop->dummy_context(inode))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
|
||||
{
|
||||
return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
|
||||
}
|
||||
|
||||
static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
|
||||
{
|
||||
return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
||||
{
|
||||
if (str->len == 1 && str->name[0] == '.')
|
||||
return true;
|
||||
|
||||
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct page *fscrypt_control_page(struct page *page)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
|
||||
#else
|
||||
WARN_ON_ONCE(1);
|
||||
return ERR_PTR(-EINVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int fscrypt_has_encryption_key(const struct inode *inode)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
return (inode->i_crypt_info != NULL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_COMMON_H */
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* fscrypt_notsupp.h
|
||||
*
|
||||
* This stubs out the fscrypt functions for filesystems configured without
|
||||
* encryption support.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FSCRYPT_NOTSUPP_H
|
||||
#define _LINUX_FSCRYPT_NOTSUPP_H
|
||||
|
||||
#include <linux/fscrypt_common.h>
|
||||
|
||||
/* crypto.c */
|
||||
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void fscrypt_release_ctx(struct fscrypt_ctx *ctx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline struct page *fscrypt_encrypt_page(const struct inode *inode,
|
||||
struct page *page,
|
||||
unsigned int len,
|
||||
unsigned int offs,
|
||||
u64 lblk_num, gfp_t gfp_flags)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int fscrypt_decrypt_page(const struct inode *inode,
|
||||
struct page *page,
|
||||
unsigned int len, unsigned int offs,
|
||||
u64 lblk_num)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
static inline void fscrypt_restore_control_page(struct page *page)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_d_op(struct dentry *dentry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* policy.c */
|
||||
static inline int fscrypt_ioctl_set_policy(struct file *filp,
|
||||
const void __user *arg)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_has_permitted_context(struct inode *parent,
|
||||
struct inode *child)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_inherit_context(struct inode *parent,
|
||||
struct inode *child,
|
||||
void *fs_data, bool preload)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* keyinfo.c */
|
||||
static inline int fscrypt_get_encryption_info(struct inode *inode)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void fscrypt_put_encryption_info(struct inode *inode,
|
||||
struct fscrypt_info *ci)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* fname.c */
|
||||
static inline int fscrypt_setup_filename(struct inode *dir,
|
||||
const struct qstr *iname,
|
||||
int lookup, struct fscrypt_name *fname)
|
||||
{
|
||||
if (dir->i_sb->s_cop->is_encrypted(dir))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(fname, 0, sizeof(struct fscrypt_name));
|
||||
fname->usr_fname = iname;
|
||||
fname->disk_name.name = (unsigned char *)iname->name;
|
||||
fname->disk_name.len = iname->len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void fscrypt_free_filename(struct fscrypt_name *fname)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode,
|
||||
u32 ilen)
|
||||
{
|
||||
/* never happens */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
|
||||
u32 ilen,
|
||||
struct fscrypt_str *crypto_str)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int fscrypt_fname_disk_to_usr(struct inode *inode,
|
||||
u32 hash, u32 minor_hash,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
|
||||
const struct qstr *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* bio.c */
|
||||
static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
|
||||
struct bio *bio)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_pullback_bio_page(struct page **page, bool restore)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
|
||||
sector_t pblk, unsigned int len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* fscrypt_supp.h
|
||||
*
|
||||
* This is included by filesystems configured with encryption support.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FSCRYPT_SUPP_H
|
||||
#define _LINUX_FSCRYPT_SUPP_H
|
||||
|
||||
#include <linux/fscrypt_common.h>
|
||||
|
||||
/* crypto.c */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
|
||||
extern void fscrypt_release_ctx(struct fscrypt_ctx *);
|
||||
extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
|
||||
unsigned int, unsigned int,
|
||||
u64, gfp_t);
|
||||
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
|
||||
unsigned int, u64);
|
||||
extern void fscrypt_restore_control_page(struct page *);
|
||||
|
||||
extern const struct dentry_operations fscrypt_d_ops;
|
||||
|
||||
static inline void fscrypt_set_d_op(struct dentry *dentry)
|
||||
{
|
||||
d_set_d_op(dentry, &fscrypt_d_ops);
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
|
||||
{
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
|
||||
/* policy.c */
|
||||
extern int fscrypt_ioctl_set_policy(struct file *, const void __user *);
|
||||
extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
|
||||
extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
|
||||
extern int fscrypt_inherit_context(struct inode *, struct inode *,
|
||||
void *, bool);
|
||||
/* keyinfo.c */
|
||||
extern int fscrypt_get_encryption_info(struct inode *);
|
||||
extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
|
||||
|
||||
/* fname.c */
|
||||
extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
|
||||
int lookup, struct fscrypt_name *);
|
||||
extern void fscrypt_free_filename(struct fscrypt_name *);
|
||||
extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
|
||||
extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
|
||||
struct fscrypt_str *);
|
||||
extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
|
||||
extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
|
||||
const struct fscrypt_str *, struct fscrypt_str *);
|
||||
extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
|
||||
struct fscrypt_str *);
|
||||
|
||||
/* bio.c */
|
||||
extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
|
||||
extern void fscrypt_pullback_bio_page(struct page **, bool);
|
||||
extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
|
||||
unsigned int);
|
||||
|
||||
#endif /* _LINUX_FSCRYPT_SUPP_H */
|
|
@ -1,345 +0,0 @@
|
|||
/*
|
||||
* General per-file encryption definition
|
||||
*
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
*
|
||||
* Written by Michael Halcrow, 2015.
|
||||
* Modified by Jaegeuk Kim, 2015.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FSCRYPTO_H
|
||||
#define _LINUX_FSCRYPTO_H
|
||||
|
||||
#include <linux/key.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>
|
||||
|
||||
#define FS_CRYPTO_BLOCK_SIZE 16
|
||||
|
||||
struct fscrypt_info;
|
||||
|
||||
struct fscrypt_ctx {
|
||||
union {
|
||||
struct {
|
||||
struct page *bounce_page; /* Ciphertext page */
|
||||
struct page *control_page; /* Original page */
|
||||
} w;
|
||||
struct {
|
||||
struct bio *bio;
|
||||
struct work_struct work;
|
||||
} r;
|
||||
struct list_head free_list; /* Free list */
|
||||
};
|
||||
u8 flags; /* Flags */
|
||||
u8 mode; /* Encryption mode for tfm */
|
||||
};
|
||||
|
||||
/**
|
||||
* For encrypted symlinks, the ciphertext length is stored at the beginning
|
||||
* of the string in little-endian format.
|
||||
*/
|
||||
struct fscrypt_symlink_data {
|
||||
__le16 len;
|
||||
char encrypted_path[1];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* This function is used to calculate the disk space required to
|
||||
* store a filename of length l in encrypted symlink format.
|
||||
*/
|
||||
static inline u32 fscrypt_symlink_data_len(u32 l)
|
||||
{
|
||||
if (l < FS_CRYPTO_BLOCK_SIZE)
|
||||
l = FS_CRYPTO_BLOCK_SIZE;
|
||||
return (l + sizeof(struct fscrypt_symlink_data) - 1);
|
||||
}
|
||||
|
||||
struct fscrypt_str {
|
||||
unsigned char *name;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct fscrypt_name {
|
||||
const struct qstr *usr_fname;
|
||||
struct fscrypt_str disk_name;
|
||||
u32 hash;
|
||||
u32 minor_hash;
|
||||
struct fscrypt_str crypto_buf;
|
||||
};
|
||||
|
||||
#define FSTR_INIT(n, l) { .name = n, .len = l }
|
||||
#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len)
|
||||
#define fname_name(p) ((p)->disk_name.name)
|
||||
#define fname_len(p) ((p)->disk_name.len)
|
||||
|
||||
/*
|
||||
* fscrypt superblock flags
|
||||
*/
|
||||
#define FS_CFLG_OWN_PAGES (1U << 1)
|
||||
|
||||
/*
|
||||
* crypto opertions for filesystems
|
||||
*/
|
||||
struct fscrypt_operations {
|
||||
unsigned int flags;
|
||||
int (*get_context)(struct inode *, void *, size_t);
|
||||
int (*key_prefix)(struct inode *, u8 **);
|
||||
int (*prepare_context)(struct inode *);
|
||||
int (*set_context)(struct inode *, const void *, size_t, void *);
|
||||
int (*dummy_context)(struct inode *);
|
||||
bool (*is_encrypted)(struct inode *);
|
||||
bool (*empty_dir)(struct inode *);
|
||||
unsigned (*max_namelen)(struct inode *);
|
||||
};
|
||||
|
||||
static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
|
||||
{
|
||||
if (inode->i_sb->s_cop->dummy_context &&
|
||||
inode->i_sb->s_cop->dummy_context(inode))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_valid_contents_enc_mode(u32 mode)
|
||||
{
|
||||
return (mode == FS_ENCRYPTION_MODE_AES_256_XTS);
|
||||
}
|
||||
|
||||
static inline bool fscrypt_valid_filenames_enc_mode(u32 mode)
|
||||
{
|
||||
return (mode == FS_ENCRYPTION_MODE_AES_256_CTS);
|
||||
}
|
||||
|
||||
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
|
||||
{
|
||||
if (str->len == 1 && str->name[0] == '.')
|
||||
return true;
|
||||
|
||||
if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline struct page *fscrypt_control_page(struct page *page)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
|
||||
#else
|
||||
WARN_ON_ONCE(1);
|
||||
return ERR_PTR(-EINVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int fscrypt_has_encryption_key(const struct inode *inode)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
return (inode->i_crypt_info != NULL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
extern const struct dentry_operations fscrypt_d_ops;
|
||||
#endif
|
||||
|
||||
static inline void fscrypt_set_d_op(struct dentry *dentry)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
d_set_d_op(dentry, &fscrypt_d_ops);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
|
||||
/* crypto.c */
|
||||
extern struct kmem_cache *fscrypt_info_cachep;
|
||||
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
|
||||
extern void fscrypt_release_ctx(struct fscrypt_ctx *);
|
||||
extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
|
||||
unsigned int, unsigned int,
|
||||
u64, gfp_t);
|
||||
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
|
||||
unsigned int, u64);
|
||||
extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
|
||||
extern void fscrypt_pullback_bio_page(struct page **, bool);
|
||||
extern void fscrypt_restore_control_page(struct page *);
|
||||
extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
|
||||
unsigned int);
|
||||
/* policy.c */
|
||||
extern int fscrypt_ioctl_set_policy(struct file *, const void __user *);
|
||||
extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
|
||||
extern int fscrypt_has_permitted_context(struct inode *, struct inode *);
|
||||
extern int fscrypt_inherit_context(struct inode *, struct inode *,
|
||||
void *, bool);
|
||||
/* keyinfo.c */
|
||||
extern int fscrypt_get_encryption_info(struct inode *);
|
||||
extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
|
||||
|
||||
/* fname.c */
|
||||
extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
|
||||
int lookup, struct fscrypt_name *);
|
||||
extern void fscrypt_free_filename(struct fscrypt_name *);
|
||||
extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
|
||||
extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
|
||||
struct fscrypt_str *);
|
||||
extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
|
||||
extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
|
||||
const struct fscrypt_str *, struct fscrypt_str *);
|
||||
extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
|
||||
struct fscrypt_str *);
|
||||
#endif
|
||||
|
||||
/* crypto.c */
|
||||
static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(const struct inode *i,
|
||||
gfp_t f)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline struct page *fscrypt_notsupp_encrypt_page(const struct inode *i,
|
||||
struct page *p,
|
||||
unsigned int len,
|
||||
unsigned int offs,
|
||||
u64 lblk_num, gfp_t f)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_decrypt_page(const struct inode *i, struct page *p,
|
||||
unsigned int len, unsigned int offs,
|
||||
u64 lblk_num)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_decrypt_bio_pages(struct fscrypt_ctx *c,
|
||||
struct bio *b)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_pullback_bio_page(struct page **p, bool b)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_restore_control_page(struct page *p)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_zeroout_range(const struct inode *i, pgoff_t p,
|
||||
sector_t s, unsigned int f)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* policy.c */
|
||||
static inline int fscrypt_notsupp_ioctl_set_policy(struct file *f,
|
||||
const void __user *arg)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_ioctl_get_policy(struct file *f,
|
||||
void __user *arg)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_has_permitted_context(struct inode *p,
|
||||
struct inode *i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_inherit_context(struct inode *p,
|
||||
struct inode *i, void *v, bool b)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* keyinfo.c */
|
||||
static inline int fscrypt_notsupp_get_encryption_info(struct inode *i)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_put_encryption_info(struct inode *i,
|
||||
struct fscrypt_info *f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* fname.c */
|
||||
static inline int fscrypt_notsupp_setup_filename(struct inode *dir,
|
||||
const struct qstr *iname,
|
||||
int lookup, struct fscrypt_name *fname)
|
||||
{
|
||||
if (dir->i_sb->s_cop->is_encrypted(dir))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memset(fname, 0, sizeof(struct fscrypt_name));
|
||||
fname->usr_fname = iname;
|
||||
fname->disk_name.name = (unsigned char *)iname->name;
|
||||
fname->disk_name.len = iname->len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_free_filename(struct fscrypt_name *fname)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline u32 fscrypt_notsupp_fname_encrypted_size(struct inode *i, u32 s)
|
||||
{
|
||||
/* never happens */
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_fname_alloc_buffer(struct inode *inode,
|
||||
u32 ilen, struct fscrypt_str *crypto_str)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode,
|
||||
u32 hash, u32 minor_hash,
|
||||
const struct fscrypt_str *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int fscrypt_notsupp_fname_usr_to_disk(struct inode *inode,
|
||||
const struct qstr *iname,
|
||||
struct fscrypt_str *oname)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif /* _LINUX_FSCRYPTO_H */
|
Loading…
Reference in New Issue