ubifs: Add skeleton for fscrypto

This is the first building block to provide file level
encryption on UBIFS.

Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
Richard Weinberger 2016-10-20 16:47:56 +02:00
parent 6a5e98ab7d
commit d475a50745
9 changed files with 178 additions and 2 deletions

View File

@ -50,3 +50,14 @@ config UBIFS_ATIME_SUPPORT
strictatime is the "heavy", relatime is "lighter", etc. strictatime is the "heavy", relatime is "lighter", etc.
If unsure, say 'N' If unsure, say 'N'
config UBIFS_FS_ENCRYPTION
bool "UBIFS Encryption"
depends on UBIFS_FS
select FS_ENCRYPTION
default n
help
Enable encryption of UBIFS files and directories. This
feature is similar to ecryptfs, but it is more memory
efficient since it avoids caching the encrypted and
decrypted pages in the page cache.

View File

@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
ubifs-y += misc.o ubifs-y += misc.o
ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o

46
fs/ubifs/crypto.c Normal file
View File

@ -0,0 +1,46 @@
#include "ubifs.h"
static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len)
{
return ubifs_xattr_get(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
ctx, len);
}
static int ubifs_crypt_set_context(struct inode *inode, const void *ctx,
size_t len, void *fs_data)
{
return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
ctx, len, 0);
}
static bool ubifs_crypt_empty_dir(struct inode *inode)
{
return ubifs_check_dir_empty(inode) == 0;
}
static unsigned int ubifs_crypt_max_namelen(struct inode *inode)
{
if (S_ISLNK(inode->i_mode))
return UBIFS_MAX_INO_DATA;
else
return UBIFS_MAX_NLEN;
}
static int ubifs_key_prefix(struct inode *inode, u8 **key)
{
static char prefix[] = "ubifs:";
*key = prefix;
return sizeof(prefix) - 1;
}
struct fscrypt_operations ubifs_crypt_operations = {
.flags = FS_CFLG_INPLACE_ENCRYPTION,
.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,
};

View File

@ -85,11 +85,26 @@ static int inherit_flags(const struct inode *dir, umode_t mode)
* initializes it. Returns new inode in case of success and an error code in * initializes it. Returns new inode in case of success and an error code in
* case of failure. * case of failure.
*/ */
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
umode_t mode) umode_t mode)
{ {
int err;
struct inode *inode; struct inode *inode;
struct ubifs_inode *ui; struct ubifs_inode *ui;
bool encrypted = false;
if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err) {
ubifs_err(c, "fscrypt_get_encryption_info failed: %i", err);
return ERR_PTR(err);
}
if (!fscrypt_has_encryption_key(dir))
return ERR_PTR(-EPERM);
encrypted = true;
}
inode = new_inode(c->vfs_sb); inode = new_inode(c->vfs_sb);
ui = ubifs_inode(inode); ui = ubifs_inode(inode);
@ -165,6 +180,17 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
*/ */
ui->creat_sqnum = ++c->max_sqnum; ui->creat_sqnum = ++c->max_sqnum;
spin_unlock(&c->cnt_lock); spin_unlock(&c->cnt_lock);
if (encrypted) {
err = fscrypt_inherit_context(dir, inode, &encrypted, true);
if (err) {
ubifs_err(c, "fscrypt_inherit_context failed: %i", err);
make_bad_inode(inode);
iput(inode);
return ERR_PTR(err);
}
}
return inode; return inode;
} }

View File

@ -181,6 +181,41 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mnt_drop_write_file(file); mnt_drop_write_file(file);
return err; return err;
} }
case FS_IOC_SET_ENCRYPTION_POLICY: {
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
struct fscrypt_policy policy;
if (copy_from_user(&policy,
(struct fscrypt_policy __user *)arg,
sizeof(policy)))
return -EFAULT;
err = fscrypt_process_policy(file, &policy);
return err;
#else
return -EOPNOTSUPP;
#endif
}
case FS_IOC_GET_ENCRYPTION_POLICY: {
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
struct fscrypt_policy policy;
if (!ubifs_crypt_is_encrypted(inode))
return -ENOENT;
err = fscrypt_get_policy(inode, &policy);
if (err)
return err;
if (copy_to_user((void __user *)arg, &policy, sizeof(policy)))
return -EFAULT;
return 0;
#else
return -EOPNOTSUPP;
#endif
}
default: default:
return -ENOTTY; return -ENOTTY;

View File

@ -380,6 +380,9 @@ out:
} }
done: done:
clear_inode(inode); clear_inode(inode);
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
fscrypt_put_encryption_info(inode, NULL);
#endif
} }
static void ubifs_dirty_inode(struct inode *inode, int flags) static void ubifs_dirty_inode(struct inode *inode, int flags)
@ -1995,6 +1998,12 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
return c; return c;
} }
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
struct fscrypt_operations ubifs_crypt_operations = {
.is_encrypted = ubifs_crypt_is_encrypted,
};
#endif
static int ubifs_fill_super(struct super_block *sb, void *data, int silent) static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct ubifs_info *c = sb->s_fs_info; struct ubifs_info *c = sb->s_fs_info;
@ -2041,6 +2050,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations; sb->s_op = &ubifs_super_operations;
sb->s_xattr = ubifs_xattr_handlers; sb->s_xattr = ubifs_xattr_handlers;
sb->s_cop = &ubifs_crypt_operations;
mutex_lock(&c->umount_mutex); mutex_lock(&c->umount_mutex);
err = mount_ubifs(c); err = mount_ubifs(c);

View File

@ -316,6 +316,7 @@ enum {
* UBIFS_APPEND_FL: writes to the inode may only append data * UBIFS_APPEND_FL: writes to the inode may only append data
* UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
* UBIFS_XATTR_FL: this inode is the inode for an extended attribute value * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
* UBIFS_CRYPT_FL: use encryption for this inode
* *
* Note, these are on-flash flags which correspond to ioctl flags * Note, these are on-flash flags which correspond to ioctl flags
* (@FS_COMPR_FL, etc). They have the same values now, but generally, do not * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
@ -328,6 +329,7 @@ enum {
UBIFS_APPEND_FL = 0x08, UBIFS_APPEND_FL = 0x08,
UBIFS_DIRSYNC_FL = 0x10, UBIFS_DIRSYNC_FL = 0x10,
UBIFS_XATTR_FL = 0x20, UBIFS_XATTR_FL = 0x20,
UBIFS_CRYPT_FL = 0x40,
}; };
/* Inode flag bits used by UBIFS */ /* Inode flag bits used by UBIFS */

View File

@ -38,6 +38,7 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/xattr.h> #include <linux/xattr.h>
#include <linux/fscrypto.h>
#include "ubifs-media.h" #include "ubifs-media.h"
/* Version of this UBIFS implementation */ /* Version of this UBIFS implementation */
@ -1724,7 +1725,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
#endif #endif
/* dir.c */ /* dir.c */
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
umode_t mode); umode_t mode);
int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat); struct kstat *stat);
@ -1773,10 +1774,44 @@ void ubifs_compress(const struct ubifs_info *c, const void *in_buf, int in_len,
int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
void *out, int *out_len, int compr_type); void *out, int *out_len, int compr_type);
extern struct fscrypt_operations ubifs_crypt_operations;
#include "debug.h" #include "debug.h"
#include "misc.h" #include "misc.h"
#include "key.h" #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_process_policy fscrypt_notsupp_process_policy
#define fscrypt_get_policy fscrypt_notsupp_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
static inline bool ubifs_crypt_is_encrypted(struct inode *inode)
{
struct ubifs_inode *ui = ubifs_inode(inode);
return ui->flags & UBIFS_CRYPT_FL;
}
/* Normal UBIFS messages */ /* Normal UBIFS messages */
__printf(2, 3) __printf(2, 3)
void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...); void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);

View File

@ -158,6 +158,15 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
host_ui->xattr_size += CALC_XATTR_BYTES(size); host_ui->xattr_size += CALC_XATTR_BYTES(size);
host_ui->xattr_names += nm->len; host_ui->xattr_names += nm->len;
/*
* We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we
* have to set the UBIFS_CRYPT_FL flag on the host inode.
* To avoid multiple updates of the same inode in the same operation,
* let's do it here.
*/
if (strcmp(nm->name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
host_ui->flags |= UBIFS_CRYPT_FL;
err = ubifs_jnl_update(c, host, nm, inode, 0, 1); err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
if (err) if (err)
goto out_cancel; goto out_cancel;
@ -173,6 +182,7 @@ out_cancel:
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
host_ui->xattr_size -= CALC_XATTR_BYTES(size); host_ui->xattr_size -= CALC_XATTR_BYTES(size);
host_ui->xattr_names -= nm->len; host_ui->xattr_names -= nm->len;
host_ui->flags &= ~UBIFS_CRYPT_FL;
mutex_unlock(&host_ui->ui_mutex); mutex_unlock(&host_ui->ui_mutex);
out_free: out_free:
make_bad_inode(inode); make_bad_inode(inode);