Commit d475a507 authored by Richard Weinberger's avatar Richard Weinberger

ubifs: Add skeleton for fscrypto

This is the first building block to provide file level
encryption on UBIFS.
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 6a5e98ab
...@@ -50,3 +50,14 @@ config UBIFS_ATIME_SUPPORT ...@@ -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.
...@@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o ...@@ -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
#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,
};
...@@ -85,11 +85,26 @@ static int inherit_flags(const struct inode *dir, umode_t mode) ...@@ -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, ...@@ -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;
} }
......
...@@ -181,6 +181,41 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -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;
......
...@@ -380,6 +380,9 @@ static void ubifs_evict_inode(struct inode *inode) ...@@ -380,6 +380,9 @@ static void ubifs_evict_inode(struct inode *inode)
} }
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) ...@@ -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) ...@@ -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);
......
...@@ -316,6 +316,7 @@ enum { ...@@ -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 { ...@@ -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 */
......
...@@ -38,6 +38,7 @@ ...@@ -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); ...@@ -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, ...@@ -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, ...);
......
...@@ -158,6 +158,15 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -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 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -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_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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment