Skip to content

Commit

Permalink
ubifs: Add skeleton for fscrypto
Browse files Browse the repository at this point in the history
This is the first building block to provide file level
encryption on UBIFS.

Signed-off-by: Richard Weinberger <richard@nod.at>
  • Loading branch information
Richard Weinberger committed Dec 12, 2016
1 parent 6a5e98a commit d475a50
Show file tree
Hide file tree
Showing 9 changed files with 178 additions and 2 deletions.
11 changes: 11 additions & 0 deletions fs/ubifs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,14 @@ config UBIFS_ATIME_SUPPORT
strictatime is the "heavy", relatime is "lighter", etc.

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.
1 change: 1 addition & 0 deletions fs/ubifs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
ubifs-y += misc.o
ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o
46 changes: 46 additions & 0 deletions fs/ubifs/crypto.c
Original file line number Diff line number Diff line change
@@ -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,
};
28 changes: 27 additions & 1 deletion fs/ubifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
* 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)
{
int err;
struct inode *inode;
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);
ui = ubifs_inode(inode);
Expand Down Expand Up @@ -165,6 +180,17 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
*/
ui->creat_sqnum = ++c->max_sqnum;
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;
}

Expand Down
35 changes: 35 additions & 0 deletions fs/ubifs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,41 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
mnt_drop_write_file(file);
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:
return -ENOTTY;
Expand Down
10 changes: 10 additions & 0 deletions fs/ubifs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,9 @@ static void ubifs_evict_inode(struct inode *inode)
}
done:
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)
Expand Down Expand Up @@ -1995,6 +1998,12 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
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)
{
struct ubifs_info *c = sb->s_fs_info;
Expand Down Expand Up @@ -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_op = &ubifs_super_operations;
sb->s_xattr = ubifs_xattr_handlers;
sb->s_cop = &ubifs_crypt_operations;

mutex_lock(&c->umount_mutex);
err = mount_ubifs(c);
Expand Down
2 changes: 2 additions & 0 deletions fs/ubifs/ubifs-media.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ enum {
* 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_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
* (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
Expand All @@ -328,6 +329,7 @@ enum {
UBIFS_APPEND_FL = 0x08,
UBIFS_DIRSYNC_FL = 0x10,
UBIFS_XATTR_FL = 0x20,
UBIFS_CRYPT_FL = 0x40,
};

/* Inode flag bits used by UBIFS */
Expand Down
37 changes: 36 additions & 1 deletion fs/ubifs/ubifs.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <linux/backing-dev.h>
#include <linux/security.h>
#include <linux/xattr.h>
#include <linux/fscrypto.h>
#include "ubifs-media.h"

/* Version of this UBIFS implementation */
Expand Down Expand Up @@ -1724,7 +1725,7 @@ int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
#endif

/* 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);
int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
Expand Down Expand Up @@ -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,
void *out, int *out_len, int compr_type);

extern struct fscrypt_operations ubifs_crypt_operations;

#include "debug.h"
#include "misc.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 */
__printf(2, 3)
void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
Expand Down
10 changes: 10 additions & 0 deletions fs/ubifs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_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);
if (err)
goto out_cancel;
Expand All @@ -173,6 +182,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
host_ui->xattr_size -= CALC_XATTR_BYTES(size);
host_ui->xattr_names -= nm->len;
host_ui->flags &= ~UBIFS_CRYPT_FL;
mutex_unlock(&host_ui->ui_mutex);
out_free:
make_bad_inode(inode);
Expand Down

0 comments on commit d475a50

Please sign in to comment.