Commit 39d2c3b9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-4.10-rc1' of git://git.infradead.org/linux-ubifs

Pull ubifs updates from Richard Weinberger:

 - file encryption for UBIFS using the fscrypt framework

 - a fix to honor the dirty_writeback_interval sysctl

 - removal of dead code

* tag 'upstream-4.10-rc1' of git://git.infradead.org/linux-ubifs: (30 commits)
  ubifs: Initialize fstr_real_len
  ubifs: Use fscrypt ioctl() helpers
  ubifs: Use FS_CFLG_OWN_PAGES
  ubifs: Raise write version to 5
  ubifs: Implement UBIFS_FLG_ENCRYPTION
  ubifs: Implement UBIFS_FLG_DOUBLE_HASH
  ubifs: Use a random number for cookies
  ubifs: Add full hash lookup support
  ubifs: Rename tnc_read_node_nm
  ubifs: Add support for encrypted symlinks
  ubifs: Implement encrypted filenames
  ubifs: Make r5 hash binary string aware
  ubifs: Relax checks in ubifs_validate_entry()
  ubifs: Implement encrypt/decrypt for all IO
  ubifs: Constify struct inode pointer in ubifs_crypt_is_encrypted()
  ubifs: Introduce new data node field, compr_size
  ubifs: Enforce crypto policy in mmap
  ubifs: Massage assert in ubifs_xattr_set() wrt. fscrypto
  ubifs: Preload crypto context in ->lookup()
  ubifs: Enforce crypto policy in ->link and ->rename
  ...
parents e18bf801 ba75d570
...@@ -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;
}
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
unsigned int in_len, unsigned int *out_len, int block)
{
struct ubifs_info *c = inode->i_sb->s_fs_info;
void *p = &dn->data;
struct page *ret;
unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE);
ubifs_assert(pad_len <= *out_len);
dn->compr_size = cpu_to_le16(in_len);
/* pad to full block cipher length */
if (pad_len != in_len)
memset(p + in_len, 0, pad_len - in_len);
ret = fscrypt_encrypt_page(inode, virt_to_page(&dn->data), pad_len,
offset_in_page(&dn->data), block, GFP_NOFS);
if (IS_ERR(ret)) {
ubifs_err(c, "fscrypt_encrypt_page failed: %ld", PTR_ERR(ret));
return PTR_ERR(ret);
}
*out_len = pad_len;
return 0;
}
int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
unsigned int *out_len, int block)
{
struct ubifs_info *c = inode->i_sb->s_fs_info;
int err;
unsigned int clen = le16_to_cpu(dn->compr_size);
unsigned int dlen = *out_len;
if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen) {
ubifs_err(c, "bad compr_size: %i", clen);
return -EINVAL;
}
ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
err = fscrypt_decrypt_page(inode, virt_to_page(&dn->data), dlen,
offset_in_page(&dn->data), block);
if (err) {
ubifs_err(c, "fscrypt_decrypt_page failed: %i", err);
return err;
}
*out_len = clen;
return 0;
}
struct fscrypt_operations ubifs_crypt_operations = {
.flags = FS_CFLG_OWN_PAGES,
.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,
};
...@@ -233,7 +233,7 @@ static void dump_ch(const struct ubifs_ch *ch) ...@@ -233,7 +233,7 @@ static void dump_ch(const struct ubifs_ch *ch)
void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode) void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
{ {
const struct ubifs_inode *ui = ubifs_inode(inode); const struct ubifs_inode *ui = ubifs_inode(inode);
struct qstr nm = { .name = NULL }; struct fscrypt_name nm = {0};
union ubifs_key key; union ubifs_key key;
struct ubifs_dent_node *dent, *pdent = NULL; struct ubifs_dent_node *dent, *pdent = NULL;
int count = 2; int count = 2;
...@@ -289,8 +289,8 @@ void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -289,8 +289,8 @@ void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
pr_err("\t%d: %s (%s)\n", pr_err("\t%d: %s (%s)\n",
count++, dent->name, get_dent_type(dent->type)); count++, dent->name, get_dent_type(dent->type));
nm.name = dent->name; fname_name(&nm) = dent->name;
nm.len = le16_to_cpu(dent->nlen); fname_len(&nm) = le16_to_cpu(dent->nlen);
kfree(pdent); kfree(pdent);
pdent = dent; pdent = dent;
key_read(c, &dent->key, &key); key_read(c, &dent->key, &key);
...@@ -1107,7 +1107,7 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) ...@@ -1107,7 +1107,7 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
unsigned int nlink = 2; unsigned int nlink = 2;
union ubifs_key key; union ubifs_key key;
struct ubifs_dent_node *dent, *pdent = NULL; struct ubifs_dent_node *dent, *pdent = NULL;
struct qstr nm = { .name = NULL }; struct fscrypt_name nm = {0};
loff_t size = UBIFS_INO_NODE_SZ; loff_t size = UBIFS_INO_NODE_SZ;
if (!dbg_is_chk_gen(c)) if (!dbg_is_chk_gen(c))
...@@ -1128,9 +1128,9 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir) ...@@ -1128,9 +1128,9 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
return err; return err;
} }
nm.name = dent->name; fname_name(&nm) = dent->name;
nm.len = le16_to_cpu(dent->nlen); fname_len(&nm) = le16_to_cpu(dent->nlen);
size += CALC_DENT_SIZE(nm.len); size += CALC_DENT_SIZE(fname_len(&nm));
if (dent->type == UBIFS_ITYPE_DIR) if (dent->type == UBIFS_ITYPE_DIR)
nlink += 1; nlink += 1;
kfree(pdent); kfree(pdent);
......
...@@ -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,18 +180,29 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, ...@@ -165,18 +180,29 @@ 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;
} }
static int dbg_check_name(const struct ubifs_info *c, static int dbg_check_name(const struct ubifs_info *c,
const struct ubifs_dent_node *dent, const struct ubifs_dent_node *dent,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
if (!dbg_is_chk_gen(c)) if (!dbg_is_chk_gen(c))
return 0; return 0;
if (le16_to_cpu(dent->nlen) != nm->len) if (le16_to_cpu(dent->nlen) != fname_len(nm))
return -EINVAL; return -EINVAL;
if (memcmp(dent->name, nm->name, nm->len)) if (memcmp(dent->name, fname_name(nm), fname_len(nm)))
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
...@@ -189,30 +215,61 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -189,30 +215,61 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
struct inode *inode = NULL; struct inode *inode = NULL;
struct ubifs_dent_node *dent; struct ubifs_dent_node *dent;
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
struct fscrypt_name nm;
dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
if (dentry->d_name.len > UBIFS_MAX_NLEN) if (ubifs_crypt_is_encrypted(dir)) {
return ERR_PTR(-ENAMETOOLONG); err = fscrypt_get_encryption_info(dir);
/*
* DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
* created while the directory was encrypted and we
* have access to the key.
*/
if (fscrypt_has_encryption_key(dir))
fscrypt_set_encrypted_dentry(dentry);
fscrypt_set_d_op(dentry);
if (err && err != -ENOKEY)
return ERR_PTR(err);
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
if (err)
return ERR_PTR(err);
if (fname_len(&nm) > UBIFS_MAX_NLEN) {
err = -ENAMETOOLONG;
goto out_fname;
}
dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
if (!dent) if (!dent) {
return ERR_PTR(-ENOMEM); err = -ENOMEM;
goto out_fname;
}
dent_key_init(c, &key, dir->i_ino, &dentry->d_name); if (nm.hash) {
ubifs_assert(fname_len(&nm) == 0);
ubifs_assert(fname_name(&nm) == NULL);
dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
} else {
dent_key_init(c, &key, dir->i_ino, &nm);
err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
}
err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
if (err) { if (err) {
if (err == -ENOENT) { if (err == -ENOENT) {
dbg_gen("not found"); dbg_gen("not found");
goto done; goto done;
} }
goto out; goto out_dent;
} }
if (dbg_check_name(c, dent, &dentry->d_name)) { if (dbg_check_name(c, dent, &nm)) {
err = -EINVAL; err = -EINVAL;
goto out; goto out_dent;
} }
inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
...@@ -225,11 +282,12 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -225,11 +282,12 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
ubifs_err(c, "dead directory entry '%pd', error %d", ubifs_err(c, "dead directory entry '%pd', error %d",
dentry, err); dentry, err);
ubifs_ro_mode(c, err); ubifs_ro_mode(c, err);
goto out; goto out_dent;
} }
done: done:
kfree(dent); kfree(dent);
fscrypt_free_filename(&nm);
/* /*
* Note, d_splice_alias() would be required instead if we supported * Note, d_splice_alias() would be required instead if we supported
* NFS. * NFS.
...@@ -237,8 +295,10 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -237,8 +295,10 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
d_add(dentry, inode); d_add(dentry, inode);
return NULL; return NULL;
out: out_dent:
kfree(dent); kfree(dent);
out_fname:
fscrypt_free_filename(&nm);
return ERR_PTR(err); return ERR_PTR(err);
} }
...@@ -247,10 +307,11 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -247,10 +307,11 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.dirtied_ino = 1 }; .dirtied_ino = 1 };
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct fscrypt_name nm;
int err, sz_change;
/* /*
* Budget request settings: new inode, new direntry, changing the * Budget request settings: new inode, new direntry, changing the
...@@ -264,10 +325,16 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -264,10 +325,16 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
if (err) if (err)
return err; return err;
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
goto out_budg;
sz_change = CALC_DENT_SIZE(fname_len(&nm));
inode = ubifs_new_inode(c, dir, mode); inode = ubifs_new_inode(c, dir, mode);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto out_budg; goto out_fname;
} }
err = ubifs_init_security(dir, inode, &dentry->d_name); err = ubifs_init_security(dir, inode, &dentry->d_name);
...@@ -278,12 +345,13 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -278,12 +345,13 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
mutex_unlock(&dir_ui->ui_mutex); mutex_unlock(&dir_ui->ui_mutex);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
fscrypt_free_filename(&nm);
insert_inode_hash(inode); insert_inode_hash(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
...@@ -295,6 +363,8 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ...@@ -295,6 +363,8 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
out_inode: out_inode:
make_bad_inode(inode); make_bad_inode(inode);
iput(inode); iput(inode);
out_fname:
fscrypt_free_filename(&nm);
out_budg: out_budg:
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
ubifs_err(c, "cannot create regular file, error %d", err); ubifs_err(c, "cannot create regular file, error %d", err);
...@@ -310,6 +380,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -310,6 +380,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
struct ubifs_budget_req ino_req = { .dirtied_ino = 1 }; struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir); struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
int err, instantiated = 0; int err, instantiated = 0;
struct fscrypt_name nm;
/* /*
* Budget request settings: new dirty inode, new direntry, * Budget request settings: new dirty inode, new direntry,
...@@ -319,13 +390,30 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -319,13 +390,30 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
dentry, mode, dir->i_ino); dentry, mode, dir->i_ino);
err = ubifs_budget_space(c, &req); if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err)
return err;
if (!fscrypt_has_encryption_key(dir)) {
return -EPERM;
}
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err) if (err)
return err; return err;
err = ubifs_budget_space(c, &req);
if (err) {
fscrypt_free_filename(&nm);
return err;
}
err = ubifs_budget_space(c, &ino_req); err = ubifs_budget_space(c, &ino_req);
if (err) { if (err) {
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
fscrypt_free_filename(&nm);
return err; return err;
} }
...@@ -361,7 +449,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -361,7 +449,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
mutex_unlock(&ui->ui_mutex); mutex_unlock(&ui->ui_mutex);
mutex_lock(&dir_ui->ui_mutex); mutex_lock(&dir_ui->ui_mutex);
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
mutex_unlock(&dir_ui->ui_mutex); mutex_unlock(&dir_ui->ui_mutex);
...@@ -380,6 +468,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry, ...@@ -380,6 +468,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
if (!instantiated) if (!instantiated)
ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &ino_req);
fscrypt_free_filename(&nm);
ubifs_err(c, "cannot create temporary file, error %d", err); ubifs_err(c, "cannot create temporary file, error %d", err);
return err; return err;
} }
...@@ -439,12 +528,14 @@ static unsigned int vfs_dent_type(uint8_t type) ...@@ -439,12 +528,14 @@ static unsigned int vfs_dent_type(uint8_t type)
*/ */
static int ubifs_readdir(struct file *file, struct dir_context *ctx) static int ubifs_readdir(struct file *file, struct dir_context *ctx)
{ {
int err = 0; int fstr_real_len = 0, err = 0;
struct qstr nm; struct fscrypt_name nm;
struct fscrypt_str fstr = {0};
union ubifs_key key; union ubifs_key key;
struct ubifs_dent_node *dent; struct ubifs_dent_node *dent;
struct inode *dir = file_inode(file); struct inode *dir = file_inode(file);
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
bool encrypted = ubifs_crypt_is_encrypted(dir);
dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos); dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
...@@ -455,6 +546,18 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -455,6 +546,18 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
*/ */
return 0; return 0;
if (encrypted) {
err = fscrypt_get_encryption_info(dir);
if (err && err != -ENOKEY)
return err;
err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr);
if (err)
return err;
fstr_real_len = fstr.len;
}
if (file->f_version == 0) { if (file->f_version == 0) {
/* /*
* The file was seek'ed, which means that @file->private_data * The file was seek'ed, which means that @file->private_data
...@@ -476,12 +579,15 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -476,12 +579,15 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
/* File positions 0 and 1 correspond to "." and ".." */ /* File positions 0 and 1 correspond to "." and ".." */
if (ctx->pos < 2) { if (ctx->pos < 2) {
ubifs_assert(!file->private_data); ubifs_assert(!file->private_data);
if (!dir_emit_dots(file, ctx)) if (!dir_emit_dots(file, ctx)) {
if (encrypted)
fscrypt_fname_free_buffer(&fstr);
return 0; return 0;
}
/* Find the first entry in TNC and save it */ /* Find the first entry in TNC and save it */
lowest_dent_key(c, &key, dir->i_ino); lowest_dent_key(c, &key, dir->i_ino);
nm.name = NULL; fname_len(&nm) = 0;
dent = ubifs_tnc_next_ent(c, &key, &nm); dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) { if (IS_ERR(dent)) {
err = PTR_ERR(dent); err = PTR_ERR(dent);
...@@ -499,7 +605,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -499,7 +605,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
* Find the entry corresponding to @ctx->pos or the closest one. * Find the entry corresponding to @ctx->pos or the closest one.
*/ */
dent_key_init_hash(c, &key, dir->i_ino, ctx->pos); dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
nm.name = NULL; fname_len(&nm) = 0;
dent = ubifs_tnc_next_ent(c, &key, &nm); dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) { if (IS_ERR(dent)) {
err = PTR_ERR(dent); err = PTR_ERR(dent);
...@@ -516,15 +622,33 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -516,15 +622,33 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
ubifs_inode(dir)->creat_sqnum); ubifs_inode(dir)->creat_sqnum);
nm.len = le16_to_cpu(dent->nlen); fname_len(&nm) = le16_to_cpu(dent->nlen);
if (!dir_emit(ctx, dent->name, nm.len, fname_name(&nm) = dent->name;
if (encrypted) {
fstr.len = fstr_real_len;
err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
&dent->key),
le32_to_cpu(dent->cookie),
&nm.disk_name, &fstr);
if (err)
goto out;
} else {
fstr.len = fname_len(&nm);
fstr.name = fname_name(&nm);
}
if (!dir_emit(ctx, fstr.name, fstr.len,
le64_to_cpu(dent->inum), le64_to_cpu(dent->inum),
vfs_dent_type(dent->type))) vfs_dent_type(dent->type))) {
if (encrypted)
fscrypt_fname_free_buffer(&fstr);
return 0; return 0;
}
/* Switch to the next entry */ /* Switch to the next entry */
key_read(c, &dent->key, &key); key_read(c, &dent->key, &key);
nm.name = dent->name;
dent = ubifs_tnc_next_ent(c, &key, &nm); dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) { if (IS_ERR(dent)) {
err = PTR_ERR(dent); err = PTR_ERR(dent);
...@@ -541,6 +665,9 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -541,6 +665,9 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
kfree(file->private_data); kfree(file->private_data);
file->private_data = NULL; file->private_data = NULL;
if (encrypted)
fscrypt_fname_free_buffer(&fstr);
if (err != -ENOENT) if (err != -ENOENT)
ubifs_err(c, "cannot find next direntry, error %d", err); ubifs_err(c, "cannot find next direntry, error %d", err);
else else
...@@ -601,6 +728,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -601,6 +728,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2,
.dirtied_ino_d = ALIGN(ui->data_len, 8) }; .dirtied_ino_d = ALIGN(ui->data_len, 8) };
struct fscrypt_name nm;
/* /*
* Budget request settings: new direntry, changing the target inode, * Budget request settings: new direntry, changing the target inode,
...@@ -613,14 +741,30 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -613,14 +741,30 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(dir));
ubifs_assert(inode_is_locked(inode)); ubifs_assert(inode_is_locked(inode));
err = dbg_check_synced_i_size(c, inode); if (ubifs_crypt_is_encrypted(dir)) {
if (!fscrypt_has_permitted_context(dir, inode))
return -EPERM;
err = fscrypt_get_encryption_info(inode);
if (err) if (err)
return err; return err;
err = ubifs_budget_space(c, &req); if (!fscrypt_has_encryption_key(inode))
return -EPERM;
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err) if (err)
return err; return err;
err = dbg_check_synced_i_size(c, inode);
if (err)
goto out_fname;
err = ubifs_budget_space(c, &req);
if (err)
goto out_fname;
lock_2_inodes(dir, inode); lock_2_inodes(dir, inode);
inc_nlink(inode); inc_nlink(inode);
ihold(inode); ihold(inode);
...@@ -628,13 +772,14 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -628,13 +772,14 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fscrypt_free_filename(&nm);
return 0; return 0;
out_cancel: out_cancel:
...@@ -644,6 +789,8 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ...@@ -644,6 +789,8 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
iput(inode); iput(inode);
out_fname:
fscrypt_free_filename(&nm);
return err; return err;
} }
...@@ -652,10 +799,10 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -652,10 +799,10 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, sz_change, budgeted = 1;
int err, budgeted = 1;
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
unsigned int saved_nlink = inode->i_nlink; unsigned int saved_nlink = inode->i_nlink;
struct fscrypt_name nm;
/* /*
* Budget request settings: deletion direntry, deletion inode (+1 for * Budget request settings: deletion direntry, deletion inode (+1 for
...@@ -667,16 +814,29 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -667,16 +814,29 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu", dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu",
dentry, inode->i_ino, dentry, inode->i_ino,
inode->i_nlink, dir->i_ino); inode->i_nlink, dir->i_ino);
if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err && err != -ENOKEY)
return err;
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
if (err)
return err;
sz_change = CALC_DENT_SIZE(fname_len(&nm));
ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(dir));
ubifs_assert(inode_is_locked(inode)); ubifs_assert(inode_is_locked(inode));
err = dbg_check_synced_i_size(c, inode); err = dbg_check_synced_i_size(c, inode);
if (err) if (err)
return err; goto out_fname;
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) { if (err) {
if (err != -ENOSPC) if (err != -ENOSPC)
return err; goto out_fname;
budgeted = 0; budgeted = 0;
} }
...@@ -686,7 +846,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -686,7 +846,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
dir->i_size -= sz_change; dir->i_size -= sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);
...@@ -698,6 +858,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -698,6 +858,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
c->bi.nospace = c->bi.nospace_rp = 0; c->bi.nospace = c->bi.nospace_rp = 0;
smp_wmb(); smp_wmb();
} }
fscrypt_free_filename(&nm);
return 0; return 0;
out_cancel: out_cancel:
...@@ -707,21 +868,23 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -707,21 +868,23 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);
if (budgeted) if (budgeted)
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
out_fname:
fscrypt_free_filename(&nm);
return err; return err;
} }
/** /**
* check_dir_empty - check if a directory is empty or not. * check_dir_empty - check if a directory is empty or not.
* @c: UBIFS file-system description object
* @dir: VFS inode object of the directory to check * @dir: VFS inode object of the directory to check
* *
* This function checks if directory @dir is empty. Returns zero if the * This function checks if directory @dir is empty. Returns zero if the
* directory is empty, %-ENOTEMPTY if it is not, and other negative error codes * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes
* in case of of errors. * in case of of errors.
*/ */
static int check_dir_empty(struct ubifs_info *c, struct inode *dir) int ubifs_check_dir_empty(struct inode *dir)
{ {
struct qstr nm = { .name = NULL }; struct ubifs_info *c = dir->i_sb->s_fs_info;
struct fscrypt_name nm = { 0 };
struct ubifs_dent_node *dent; struct ubifs_dent_node *dent;
union ubifs_key key; union ubifs_key key;
int err; int err;
...@@ -743,10 +906,10 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -743,10 +906,10 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, sz_change, budgeted = 1;
int err, budgeted = 1;
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
struct fscrypt_name nm;
/* /*
* Budget request settings: deletion direntry, deletion inode and * Budget request settings: deletion direntry, deletion inode and
...@@ -758,14 +921,26 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -758,14 +921,26 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
inode->i_ino, dir->i_ino); inode->i_ino, dir->i_ino);
ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(dir));
ubifs_assert(inode_is_locked(inode)); ubifs_assert(inode_is_locked(inode));
err = check_dir_empty(c, d_inode(dentry)); err = ubifs_check_dir_empty(d_inode(dentry));
if (err) if (err)
return err; return err;
if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err && err != -ENOKEY)
return err;
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
if (err)
return err;
sz_change = CALC_DENT_SIZE(fname_len(&nm));
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) { if (err) {
if (err != -ENOSPC) if (err != -ENOSPC)
return err; goto out_fname;
budgeted = 0; budgeted = 0;
} }
...@@ -776,7 +951,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -776,7 +951,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
dir->i_size -= sz_change; dir->i_size -= sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);
...@@ -788,6 +963,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -788,6 +963,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
c->bi.nospace = c->bi.nospace_rp = 0; c->bi.nospace = c->bi.nospace_rp = 0;
smp_wmb(); smp_wmb();
} }
fscrypt_free_filename(&nm);
return 0; return 0;
out_cancel: out_cancel:
...@@ -798,6 +974,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -798,6 +974,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);
if (budgeted) if (budgeted)
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
out_fname:
fscrypt_free_filename(&nm);
return err; return err;
} }
...@@ -806,8 +984,9 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -806,8 +984,9 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *inode; struct inode *inode;
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, sz_change;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 };
struct fscrypt_name nm;
/* /*
* Budget request settings: new inode, new direntry and changing parent * Budget request settings: new inode, new direntry and changing parent
...@@ -821,10 +1000,27 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -821,10 +1000,27 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
if (err) if (err)
return err; return err;
if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err)
goto out_budg;
if (!fscrypt_has_encryption_key(dir)) {
err = -EPERM;
goto out_budg;
}
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
goto out_budg;
sz_change = CALC_DENT_SIZE(fname_len(&nm));
inode = ubifs_new_inode(c, dir, S_IFDIR | mode); inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto out_budg; goto out_fname;
} }
err = ubifs_init_security(dir, inode, &dentry->d_name); err = ubifs_init_security(dir, inode, &dentry->d_name);
...@@ -838,7 +1034,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -838,7 +1034,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
if (err) { if (err) {
ubifs_err(c, "cannot create directory, error %d", err); ubifs_err(c, "cannot create directory, error %d", err);
goto out_cancel; goto out_cancel;
...@@ -847,6 +1043,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -847,6 +1043,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fscrypt_free_filename(&nm);
return 0; return 0;
out_cancel: out_cancel:
...@@ -857,6 +1054,8 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -857,6 +1054,8 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
out_inode: out_inode:
make_bad_inode(inode); make_bad_inode(inode);
iput(inode); iput(inode);
out_fname:
fscrypt_free_filename(&nm);
out_budg: out_budg:
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return err; return err;
...@@ -870,11 +1069,12 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -870,11 +1069,12 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
union ubifs_dev_desc *dev = NULL; union ubifs_dev_desc *dev = NULL;
int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int sz_change;
int err, devlen = 0; int err, devlen = 0;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(devlen, 8), .new_ino_d = ALIGN(devlen, 8),
.dirtied_ino = 1 }; .dirtied_ino = 1 };
struct fscrypt_name nm;
/* /*
* Budget request settings: new inode, new direntry and changing parent * Budget request settings: new inode, new direntry and changing parent
...@@ -896,11 +1096,28 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -896,11 +1096,28 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
return err; return err;
} }
if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err)
goto out_budg;
if (!fscrypt_has_encryption_key(dir)) {
err = -EPERM;
goto out_budg;
}
}
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
goto out_budg;
sz_change = CALC_DENT_SIZE(fname_len(&nm));
inode = ubifs_new_inode(c, dir, mode); inode = ubifs_new_inode(c, dir, mode);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
kfree(dev); kfree(dev);
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto out_budg; goto out_fname;
} }
init_special_inode(inode, inode->i_mode, rdev); init_special_inode(inode, inode->i_mode, rdev);
...@@ -917,7 +1134,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -917,7 +1134,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
mutex_unlock(&dir_ui->ui_mutex); mutex_unlock(&dir_ui->ui_mutex);
...@@ -925,6 +1142,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -925,6 +1142,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
insert_inode_hash(inode); insert_inode_hash(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fscrypt_free_filename(&nm);
return 0; return 0;
out_cancel: out_cancel:
...@@ -934,6 +1152,8 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -934,6 +1152,8 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
out_inode: out_inode:
make_bad_inode(inode); make_bad_inode(inode);
iput(inode); iput(inode);
out_fname:
fscrypt_free_filename(&nm);
out_budg: out_budg:
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return err; return err;
...@@ -947,10 +1167,27 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -947,10 +1167,27 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
int err, len = strlen(symname); int err, len = strlen(symname);
int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int sz_change = CALC_DENT_SIZE(len);
struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
struct fscrypt_symlink_data *sd = NULL;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
.new_ino_d = ALIGN(len, 8), .new_ino_d = ALIGN(len, 8),
.dirtied_ino = 1 }; .dirtied_ino = 1 };
struct fscrypt_name nm;
if (ubifs_crypt_is_encrypted(dir)) {
err = fscrypt_get_encryption_info(dir);
if (err)
goto out_budg;
if (!fscrypt_has_encryption_key(dir)) {
err = -EPERM;
goto out_budg;
}
disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
sizeof(struct fscrypt_symlink_data));
}
/* /*
* Budget request settings: new inode, new direntry and changing parent * Budget request settings: new inode, new direntry and changing parent
...@@ -960,36 +1197,77 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -960,36 +1197,77 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
symname, dir->i_ino); symname, dir->i_ino);
if (len > UBIFS_MAX_INO_DATA) if (disk_link.len > UBIFS_MAX_INO_DATA)
return -ENAMETOOLONG; return -ENAMETOOLONG;
err = ubifs_budget_space(c, &req); err = ubifs_budget_space(c, &req);
if (err) if (err)
return err; return err;
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
goto out_budg;
inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
err = PTR_ERR(inode); err = PTR_ERR(inode);
goto out_budg; goto out_fname;
} }
ui = ubifs_inode(inode); ui = ubifs_inode(inode);
ui->data = kmalloc(len + 1, GFP_NOFS); ui->data = kmalloc(disk_link.len, GFP_NOFS);
if (!ui->data) { if (!ui->data) {
err = -ENOMEM; err = -ENOMEM;
goto out_inode; goto out_inode;
} }
memcpy(ui->data, symname, len); if (ubifs_crypt_is_encrypted(dir)) {
((char *)ui->data)[len] = '\0'; struct qstr istr = QSTR_INIT(symname, len);
struct fscrypt_str ostr;
sd = kzalloc(disk_link.len, GFP_NOFS);
if (!sd) {
err = -ENOMEM;
goto out_inode;
}
err = fscrypt_get_encryption_info(inode);
if (err) {
kfree(sd);
goto out_inode;
}
if (!fscrypt_has_encryption_key(inode)) {
kfree(sd);
err = -EPERM;
goto out_inode;
}
ostr.name = sd->encrypted_path;
ostr.len = disk_link.len;
err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
if (err) {
kfree(sd);
goto out_inode;
}
sd->len = cpu_to_le16(ostr.len);
disk_link.name = (char *)sd;
} else {
inode->i_link = ui->data; inode->i_link = ui->data;
}
memcpy(ui->data, disk_link.name, disk_link.len);
((char *)ui->data)[disk_link.len - 1] = '\0';
/* /*
* The terminating zero byte is not written to the flash media and it * The terminating zero byte is not written to the flash media and it
* is put just to make later in-memory string processing simpler. Thus, * is put just to make later in-memory string processing simpler. Thus,
* data length is @len, not @len + %1. * data length is @len, not @len + %1.
*/ */
ui->data_len = len; ui->data_len = disk_link.len - 1;
inode->i_size = ubifs_inode(inode)->ui_size = len; inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1;
err = ubifs_init_security(dir, inode, &dentry->d_name); err = ubifs_init_security(dir, inode, &dentry->d_name);
if (err) if (err)
...@@ -999,7 +1277,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -999,7 +1277,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
dir->i_size += sz_change; dir->i_size += sz_change;
dir_ui->ui_size = dir->i_size; dir_ui->ui_size = dir->i_size;
dir->i_mtime = dir->i_ctime = inode->i_ctime; dir->i_mtime = dir->i_ctime = inode->i_ctime;
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
if (err) if (err)
goto out_cancel; goto out_cancel;
mutex_unlock(&dir_ui->ui_mutex); mutex_unlock(&dir_ui->ui_mutex);
...@@ -1007,6 +1285,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1007,6 +1285,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
insert_inode_hash(inode); insert_inode_hash(inode);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fscrypt_free_filename(&nm);
return 0; return 0;
out_cancel: out_cancel:
...@@ -1016,6 +1295,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1016,6 +1295,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
out_inode: out_inode:
make_bad_inode(inode); make_bad_inode(inode);
iput(inode); iput(inode);
out_fname:
fscrypt_free_filename(&nm);
out_budg: out_budg:
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return err; return err;
...@@ -1078,15 +1359,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1078,15 +1359,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
struct ubifs_inode *whiteout_ui = NULL; struct ubifs_inode *whiteout_ui = NULL;
int err, release, sync = 0, move = (new_dir != old_dir); int err, release, sync = 0, move = (new_dir != old_dir);
int is_dir = S_ISDIR(old_inode->i_mode); int is_dir = S_ISDIR(old_inode->i_mode);
int unlink = !!new_inode; int unlink = !!new_inode, new_sz, old_sz;
int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len);
int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len);
struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
.dirtied_ino = 3 }; .dirtied_ino = 3 };
struct ubifs_budget_req ino_req = { .dirtied_ino = 1, struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
struct timespec time; struct timespec time;
unsigned int uninitialized_var(saved_nlink); unsigned int uninitialized_var(saved_nlink);
struct fscrypt_name old_nm, new_nm;
if (flags & ~RENAME_NOREPLACE) if (flags & ~RENAME_NOREPLACE)
return -EINVAL; return -EINVAL;
...@@ -1107,17 +1387,41 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1107,17 +1387,41 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
if (unlink) if (unlink)
ubifs_assert(inode_is_locked(new_inode)); ubifs_assert(inode_is_locked(new_inode));
if (old_dir != new_dir) {
if (ubifs_crypt_is_encrypted(new_dir) &&
!fscrypt_has_permitted_context(new_dir, old_inode))
return -EPERM;
}
if (unlink && is_dir) { if (unlink && is_dir) {
err = check_dir_empty(c, new_inode); err = ubifs_check_dir_empty(new_inode);
if (err) if (err)
return err; return err;
} }
err = ubifs_budget_space(c, &req); err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm);
if (err) if (err)
return err; return err;
err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm);
if (err) {
fscrypt_free_filename(&old_nm);
return err;
}
new_sz = CALC_DENT_SIZE(fname_len(&new_nm));
old_sz = CALC_DENT_SIZE(fname_len(&old_nm));
err = ubifs_budget_space(c, &req);
if (err) {
fscrypt_free_filename(&old_nm);
fscrypt_free_filename(&new_nm);
return err;
}
err = ubifs_budget_space(c, &ino_req); err = ubifs_budget_space(c, &ino_req);
if (err) { if (err) {
fscrypt_free_filename(&old_nm);
fscrypt_free_filename(&new_nm);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return err; return err;
} }
...@@ -1239,8 +1543,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1239,8 +1543,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
iput(whiteout); iput(whiteout);
} }
err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, whiteout, err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir,
sync); new_inode, &new_nm, whiteout, sync);
if (err) if (err)
goto out_cancel; goto out_cancel;
...@@ -1256,6 +1560,9 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1256,6 +1560,9 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &ino_req);
if (IS_SYNC(old_inode)) if (IS_SYNC(old_inode))
err = old_inode->i_sb->s_op->write_inode(old_inode, NULL); err = old_inode->i_sb->s_op->write_inode(old_inode, NULL);
fscrypt_free_filename(&old_nm);
fscrypt_free_filename(&new_nm);
return err; return err;
out_cancel: out_cancel:
...@@ -1284,6 +1591,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1284,6 +1591,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &ino_req);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
fscrypt_free_filename(&old_nm);
fscrypt_free_filename(&new_nm);
return err; return err;
} }
...@@ -1298,9 +1607,27 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1298,9 +1607,27 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *snd_inode = d_inode(new_dentry); struct inode *snd_inode = d_inode(new_dentry);
struct timespec time; struct timespec time;
int err; int err;
struct fscrypt_name fst_nm, snd_nm;
ubifs_assert(fst_inode && snd_inode); ubifs_assert(fst_inode && snd_inode);
if ((ubifs_crypt_is_encrypted(old_dir) ||
ubifs_crypt_is_encrypted(new_dir)) &&
(old_dir != new_dir) &&
(!fscrypt_has_permitted_context(new_dir, fst_inode) ||
!fscrypt_has_permitted_context(old_dir, snd_inode)))
return -EPERM;
err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm);
if (err)
return err;
err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &snd_nm);
if (err) {
fscrypt_free_filename(&fst_nm);
return err;
}
lock_4_inodes(old_dir, new_dir, NULL, NULL); lock_4_inodes(old_dir, new_dir, NULL, NULL);
time = ubifs_current_time(old_dir); time = ubifs_current_time(old_dir);
...@@ -1320,12 +1647,14 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -1320,12 +1647,14 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
} }
} }
err = ubifs_jnl_xrename(c, old_dir, old_dentry, new_dir, new_dentry, err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir,
sync); snd_inode, &snd_nm, sync);
unlock_4_inodes(old_dir, new_dir, NULL, NULL); unlock_4_inodes(old_dir, new_dir, NULL, NULL);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
fscrypt_free_filename(&fst_nm);
fscrypt_free_filename(&snd_nm);
return err; return err;
} }
...@@ -1384,6 +1713,14 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1384,6 +1713,14 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
return 0; return 0;
} }
static int ubifs_dir_open(struct inode *dir, struct file *file)
{
if (ubifs_crypt_is_encrypted(dir))
return fscrypt_get_encryption_info(dir) ? -EACCES : 0;
return 0;
}
const struct inode_operations ubifs_dir_inode_operations = { const struct inode_operations ubifs_dir_inode_operations = {
.lookup = ubifs_lookup, .lookup = ubifs_lookup,
.create = ubifs_create, .create = ubifs_create,
...@@ -1410,6 +1747,7 @@ const struct file_operations ubifs_dir_operations = { ...@@ -1410,6 +1747,7 @@ const struct file_operations ubifs_dir_operations = {
.iterate_shared = ubifs_readdir, .iterate_shared = ubifs_readdir,
.fsync = ubifs_fsync, .fsync = ubifs_fsync,
.unlocked_ioctl = ubifs_ioctl, .unlocked_ioctl = ubifs_ioctl,
.open = ubifs_dir_open,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = ubifs_compat_ioctl, .compat_ioctl = ubifs_compat_ioctl,
#endif #endif
......
...@@ -78,6 +78,13 @@ static int read_block(struct inode *inode, void *addr, unsigned int block, ...@@ -78,6 +78,13 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
goto dump; goto dump;
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
if (ubifs_crypt_is_encrypted(inode)) {
err = ubifs_decrypt(inode, dn, &dlen, block);
if (err)
goto dump;
}
out_len = UBIFS_BLOCK_SIZE; out_len = UBIFS_BLOCK_SIZE;
err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len, err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
le16_to_cpu(dn->compr_type)); le16_to_cpu(dn->compr_type));
...@@ -650,6 +657,13 @@ static int populate_page(struct ubifs_info *c, struct page *page, ...@@ -650,6 +657,13 @@ static int populate_page(struct ubifs_info *c, struct page *page,
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
out_len = UBIFS_BLOCK_SIZE; out_len = UBIFS_BLOCK_SIZE;
if (ubifs_crypt_is_encrypted(inode)) {
err = ubifs_decrypt(inode, dn, &dlen, page_block);
if (err)
goto out_err;
}
err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len, err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
le16_to_cpu(dn->compr_type)); le16_to_cpu(dn->compr_type));
if (err || len != out_len) if (err || len != out_len)
...@@ -1594,6 +1608,15 @@ static const struct vm_operations_struct ubifs_file_vm_ops = { ...@@ -1594,6 +1608,15 @@ static const struct vm_operations_struct ubifs_file_vm_ops = {
static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
{ {
int err; int err;
struct inode *inode = file->f_mapping->host;
if (ubifs_crypt_is_encrypted(inode)) {
err = fscrypt_get_encryption_info(inode);
if (err)
return -EACCES;
if (!fscrypt_has_encryption_key(inode))
return -ENOKEY;
}
err = generic_file_mmap(file, vma); err = generic_file_mmap(file, vma);
if (err) if (err)
...@@ -1605,6 +1628,88 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1605,6 +1628,88 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
return 0; return 0;
} }
static int ubifs_file_open(struct inode *inode, struct file *filp)
{
int ret;
struct dentry *dir;
struct ubifs_info *c = inode->i_sb->s_fs_info;
if (ubifs_crypt_is_encrypted(inode)) {
ret = fscrypt_get_encryption_info(inode);
if (ret)
return -EACCES;
if (!fscrypt_has_encryption_key(inode))
return -ENOKEY;
}
dir = dget_parent(file_dentry(filp));
if (ubifs_crypt_is_encrypted(d_inode(dir)) &&
!fscrypt_has_permitted_context(d_inode(dir), inode)) {
ubifs_err(c, "Inconsistent encryption contexts: %lu/%lu",
(unsigned long) d_inode(dir)->i_ino,
(unsigned long) inode->i_ino);
dput(dir);
ubifs_ro_mode(c, -EPERM);
return -EPERM;
}
dput(dir);
return 0;
}
static const char *ubifs_get_link(struct dentry *dentry,
struct inode *inode,
struct delayed_call *done)
{
int err;
struct fscrypt_symlink_data *sd;
struct ubifs_inode *ui = ubifs_inode(inode);
struct fscrypt_str cstr;
struct fscrypt_str pstr;
if (!ubifs_crypt_is_encrypted(inode))
return ui->data;
if (!dentry)
return ERR_PTR(-ECHILD);
err = fscrypt_get_encryption_info(inode);
if (err)
return ERR_PTR(err);
sd = (struct fscrypt_symlink_data *)ui->data;
cstr.name = sd->encrypted_path;
cstr.len = le16_to_cpu(sd->len);
if (cstr.len == 0)
return ERR_PTR(-ENOENT);
if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > ui->data_len)
return ERR_PTR(-EIO);
err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
if (err)
return ERR_PTR(err);
err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
if (err) {
fscrypt_fname_free_buffer(&pstr);
return ERR_PTR(err);
}
pstr.name[pstr.len] = '\0';
// XXX this probably won't happen anymore...
if (pstr.name[0] == '\0') {
fscrypt_fname_free_buffer(&pstr);
return ERR_PTR(-ENOENT);
}
set_delayed_call(done, kfree_link, pstr.name);
return pstr.name;
}
const struct address_space_operations ubifs_file_address_operations = { const struct address_space_operations ubifs_file_address_operations = {
.readpage = ubifs_readpage, .readpage = ubifs_readpage,
.writepage = ubifs_writepage, .writepage = ubifs_writepage,
...@@ -1629,7 +1734,7 @@ const struct inode_operations ubifs_file_inode_operations = { ...@@ -1629,7 +1734,7 @@ const struct inode_operations ubifs_file_inode_operations = {
const struct inode_operations ubifs_symlink_inode_operations = { const struct inode_operations ubifs_symlink_inode_operations = {
.readlink = generic_readlink, .readlink = generic_readlink,
.get_link = simple_get_link, .get_link = ubifs_get_link,
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
...@@ -1647,6 +1752,7 @@ const struct file_operations ubifs_file_operations = { ...@@ -1647,6 +1752,7 @@ const struct file_operations ubifs_file_operations = {
.unlocked_ioctl = ubifs_ioctl, .unlocked_ioctl = ubifs_ioctl,
.splice_read = generic_file_splice_read, .splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write, .splice_write = iter_file_splice_write,
.open = ubifs_file_open,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = ubifs_compat_ioctl, .compat_ioctl = ubifs_compat_ioctl,
#endif #endif
......
...@@ -846,10 +846,6 @@ int ubifs_gc_start_commit(struct ubifs_info *c) ...@@ -846,10 +846,6 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
*/ */
while (1) { while (1) {
lp = ubifs_fast_find_freeable(c); lp = ubifs_fast_find_freeable(c);
if (IS_ERR(lp)) {
err = PTR_ERR(lp);
goto out;
}
if (!lp) if (!lp)
break; break;
ubifs_assert(!(lp->flags & LPROPS_TAKEN)); ubifs_assert(!(lp->flags & LPROPS_TAKEN));
......
...@@ -452,16 +452,22 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer) ...@@ -452,16 +452,22 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
*/ */
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
{ {
ktime_t softlimit = ms_to_ktime(dirty_writeback_interval * 10);
unsigned long long delta = dirty_writeback_interval;
/* centi to milli, milli to nano, then 10% */
delta *= 10ULL * NSEC_PER_MSEC / 10ULL;
ubifs_assert(!hrtimer_active(&wbuf->timer)); ubifs_assert(!hrtimer_active(&wbuf->timer));
ubifs_assert(delta <= ULONG_MAX);
if (wbuf->no_timer) if (wbuf->no_timer)
return; return;
dbg_io("set timer for jhead %s, %llu-%llu millisecs", dbg_io("set timer for jhead %s, %llu-%llu millisecs",
dbg_jhead(wbuf->jhead), dbg_jhead(wbuf->jhead),
div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC), div_u64(ktime_to_ns(softlimit), USEC_PER_SEC),
div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta, div_u64(ktime_to_ns(softlimit) + delta, USEC_PER_SEC));
USEC_PER_SEC)); hrtimer_start_range_ns(&wbuf->timer, softlimit, delta,
hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
HRTIMER_MODE_REL); HRTIMER_MODE_REL);
} }
...@@ -1059,10 +1065,6 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) ...@@ -1059,10 +1065,6 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
wbuf->timer.function = wbuf_timer_callback_nolock; wbuf->timer.function = wbuf_timer_callback_nolock;
wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
wbuf->delta *= 1000000000ULL;
ubifs_assert(wbuf->delta <= ULONG_MAX);
return 0; return 0;
} }
......
...@@ -181,6 +181,26 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -181,6 +181,26 @@ 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 ubifs_info *c = inode->i_sb->s_fs_info;
err = ubifs_enable_encryption(c);
if (err)
return err;
return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
#else
return -EOPNOTSUPP;
#endif
}
case FS_IOC_GET_ENCRYPTION_POLICY: {
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
return fscrypt_ioctl_get_policy(file, (void __user *)arg);
#else
return -EOPNOTSUPP;
#endif
}
default: default:
return -ENOTTY; return -ENOTTY;
......
...@@ -78,16 +78,6 @@ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino) ...@@ -78,16 +78,6 @@ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino)
static inline void zero_dent_node_unused(struct ubifs_dent_node *dent) static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
{ {
dent->padding1 = 0; dent->padding1 = 0;
memset(dent->padding2, 0, 4);
}
/**
* zero_data_node_unused - zero out unused fields of an on-flash data node.
* @data: the data node to zero out
*/
static inline void zero_data_node_unused(struct ubifs_data_node *data)
{
memset(data->padding, 0, 2);
} }
/** /**
...@@ -511,6 +501,14 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui) ...@@ -511,6 +501,14 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
ui->dirty = 0; ui->dirty = 0;
} }
static void set_dent_cookie(struct ubifs_info *c, struct ubifs_dent_node *dent)
{
if (c->double_hash)
dent->cookie = prandom_u32();
else
dent->cookie = 0;
}
/** /**
* ubifs_jnl_update - update inode. * ubifs_jnl_update - update inode.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -539,7 +537,7 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui) ...@@ -539,7 +537,7 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
* success. In case of failure, a negative error code is returned. * success. In case of failure, a negative error code is returned.
*/ */
int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
const struct qstr *nm, const struct inode *inode, const struct fscrypt_name *nm, const struct inode *inode,
int deletion, int xent) int deletion, int xent)
{ {
int err, dlen, ilen, len, lnum, ino_offs, dent_offs; int err, dlen, ilen, len, lnum, ino_offs, dent_offs;
...@@ -551,11 +549,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -551,11 +549,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
struct ubifs_ino_node *ino; struct ubifs_ino_node *ino;
union ubifs_key dent_key, ino_key; union ubifs_key dent_key, ino_key;
dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu", //dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino); // inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
ubifs_assert(mutex_is_locked(&host_ui->ui_mutex)); ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
dlen = UBIFS_DENT_NODE_SZ + nm->len + 1; dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
ilen = UBIFS_INO_NODE_SZ; ilen = UBIFS_INO_NODE_SZ;
/* /*
...@@ -596,9 +594,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, ...@@ -596,9 +594,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
key_write(c, &dent_key, dent->key); key_write(c, &dent_key, dent->key);
dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino); dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino);
dent->type = get_dent_type(inode->i_mode); dent->type = get_dent_type(inode->i_mode);
dent->nlen = cpu_to_le16(nm->len); dent->nlen = cpu_to_le16(fname_len(nm));
memcpy(dent->name, nm->name, nm->len); memcpy(dent->name, fname_name(nm), fname_len(nm));
dent->name[nm->len] = '\0'; dent->name[fname_len(nm)] = '\0';
set_dent_cookie(c, dent);
zero_dent_node_unused(dent); zero_dent_node_unused(dent);
ubifs_prep_grp_node(c, dent, dlen, 0); ubifs_prep_grp_node(c, dent, dlen, 0);
...@@ -697,14 +697,18 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ...@@ -697,14 +697,18 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
const union ubifs_key *key, const void *buf, int len) const union ubifs_key *key, const void *buf, int len)
{ {
struct ubifs_data_node *data; struct ubifs_data_node *data;
int err, lnum, offs, compr_type, out_len; int err, lnum, offs, compr_type, out_len, compr_len;
int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1; int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
bool encrypted = ubifs_crypt_is_encrypted(inode);
dbg_jnlk(key, "ino %lu, blk %u, len %d, key ", dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
(unsigned long)key_inum(c, key), key_block(c, key), len); (unsigned long)key_inum(c, key), key_block(c, key), len);
ubifs_assert(len <= UBIFS_BLOCK_SIZE); ubifs_assert(len <= UBIFS_BLOCK_SIZE);
if (encrypted)
dlen += UBIFS_CIPHER_BLOCK_SIZE;
data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN); data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
if (!data) { if (!data) {
/* /*
...@@ -722,7 +726,6 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ...@@ -722,7 +726,6 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
data->ch.node_type = UBIFS_DATA_NODE; data->ch.node_type = UBIFS_DATA_NODE;
key_write(c, key, &data->key); key_write(c, key, &data->key);
data->size = cpu_to_le32(len); data->size = cpu_to_le32(len);
zero_data_node_unused(data);
if (!(ui->flags & UBIFS_COMPR_FL)) if (!(ui->flags & UBIFS_COMPR_FL))
/* Compression is disabled for this inode */ /* Compression is disabled for this inode */
...@@ -730,9 +733,18 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, ...@@ -730,9 +733,18 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
else else
compr_type = ui->compr_type; compr_type = ui->compr_type;
out_len = dlen - UBIFS_DATA_NODE_SZ; out_len = compr_len = dlen - UBIFS_DATA_NODE_SZ;
ubifs_compress(c, buf, len, &data->data, &out_len, &compr_type); ubifs_compress(c, buf, len, &data->data, &compr_len, &compr_type);
ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); ubifs_assert(compr_len <= UBIFS_BLOCK_SIZE);
if (encrypted) {
err = ubifs_encrypt(inode, data, compr_len, &out_len, key_block(c, key));
if (err)
goto out_free;
} else {
data->compr_size = 0;
}
dlen = UBIFS_DATA_NODE_SZ + out_len; dlen = UBIFS_DATA_NODE_SZ + out_len;
data->compr_type = cpu_to_le16(compr_type); data->compr_type = cpu_to_le16(compr_type);
...@@ -911,9 +923,11 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -911,9 +923,11 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
* ubifs_jnl_xrename - cross rename two directory entries. * ubifs_jnl_xrename - cross rename two directory entries.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @fst_dir: parent inode of 1st directory entry to exchange * @fst_dir: parent inode of 1st directory entry to exchange
* @fst_dentry: 1st directory entry to exchange * @fst_inode: 1st inode to exchange
* @fst_nm: name of 1st inode to exchange
* @snd_dir: parent inode of 2nd directory entry to exchange * @snd_dir: parent inode of 2nd directory entry to exchange
* @snd_dentry: 2nd directory entry to exchange * @snd_inode: 2nd inode to exchange
* @snd_nm: name of 2nd inode to exchange
* @sync: non-zero if the write-buffer has to be synchronized * @sync: non-zero if the write-buffer has to be synchronized
* *
* This function implements the cross rename operation which may involve * This function implements the cross rename operation which may involve
...@@ -922,29 +936,29 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode) ...@@ -922,29 +936,29 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
* returned. * returned.
*/ */
int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
const struct dentry *fst_dentry, const struct inode *fst_inode,
const struct fscrypt_name *fst_nm,
const struct inode *snd_dir, const struct inode *snd_dir,
const struct dentry *snd_dentry, int sync) const struct inode *snd_inode,
const struct fscrypt_name *snd_nm, int sync)
{ {
union ubifs_key key; union ubifs_key key;
struct ubifs_dent_node *dent1, *dent2; struct ubifs_dent_node *dent1, *dent2;
int err, dlen1, dlen2, lnum, offs, len, plen = UBIFS_INO_NODE_SZ; int err, dlen1, dlen2, lnum, offs, len, plen = UBIFS_INO_NODE_SZ;
int aligned_dlen1, aligned_dlen2; int aligned_dlen1, aligned_dlen2;
int twoparents = (fst_dir != snd_dir); int twoparents = (fst_dir != snd_dir);
const struct inode *fst_inode = d_inode(fst_dentry);
const struct inode *snd_inode = d_inode(snd_dentry);
void *p; void *p;
dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu", //dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino); // fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
ubifs_assert(ubifs_inode(fst_dir)->data_len == 0); ubifs_assert(ubifs_inode(fst_dir)->data_len == 0);
ubifs_assert(ubifs_inode(snd_dir)->data_len == 0); ubifs_assert(ubifs_inode(snd_dir)->data_len == 0);
ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex)); ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex));
ubifs_assert(mutex_is_locked(&ubifs_inode(snd_dir)->ui_mutex)); ubifs_assert(mutex_is_locked(&ubifs_inode(snd_dir)->ui_mutex));
dlen1 = UBIFS_DENT_NODE_SZ + snd_dentry->d_name.len + 1; dlen1 = UBIFS_DENT_NODE_SZ + fname_len(snd_nm) + 1;
dlen2 = UBIFS_DENT_NODE_SZ + fst_dentry->d_name.len + 1; dlen2 = UBIFS_DENT_NODE_SZ + fname_len(fst_nm) + 1;
aligned_dlen1 = ALIGN(dlen1, 8); aligned_dlen1 = ALIGN(dlen1, 8);
aligned_dlen2 = ALIGN(dlen2, 8); aligned_dlen2 = ALIGN(dlen2, 8);
...@@ -963,24 +977,24 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -963,24 +977,24 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
/* Make new dent for 1st entry */ /* Make new dent for 1st entry */
dent1->ch.node_type = UBIFS_DENT_NODE; dent1->ch.node_type = UBIFS_DENT_NODE;
dent_key_init_flash(c, &dent1->key, snd_dir->i_ino, &snd_dentry->d_name); dent_key_init_flash(c, &dent1->key, snd_dir->i_ino, snd_nm);
dent1->inum = cpu_to_le64(fst_inode->i_ino); dent1->inum = cpu_to_le64(fst_inode->i_ino);
dent1->type = get_dent_type(fst_inode->i_mode); dent1->type = get_dent_type(fst_inode->i_mode);
dent1->nlen = cpu_to_le16(snd_dentry->d_name.len); dent1->nlen = cpu_to_le16(fname_len(snd_nm));
memcpy(dent1->name, snd_dentry->d_name.name, snd_dentry->d_name.len); memcpy(dent1->name, fname_name(snd_nm), fname_len(snd_nm));
dent1->name[snd_dentry->d_name.len] = '\0'; dent1->name[fname_len(snd_nm)] = '\0';
zero_dent_node_unused(dent1); zero_dent_node_unused(dent1);
ubifs_prep_grp_node(c, dent1, dlen1, 0); ubifs_prep_grp_node(c, dent1, dlen1, 0);
/* Make new dent for 2nd entry */ /* Make new dent for 2nd entry */
dent2 = (void *)dent1 + aligned_dlen1; dent2 = (void *)dent1 + aligned_dlen1;
dent2->ch.node_type = UBIFS_DENT_NODE; dent2->ch.node_type = UBIFS_DENT_NODE;
dent_key_init_flash(c, &dent2->key, fst_dir->i_ino, &fst_dentry->d_name); dent_key_init_flash(c, &dent2->key, fst_dir->i_ino, fst_nm);
dent2->inum = cpu_to_le64(snd_inode->i_ino); dent2->inum = cpu_to_le64(snd_inode->i_ino);
dent2->type = get_dent_type(snd_inode->i_mode); dent2->type = get_dent_type(snd_inode->i_mode);
dent2->nlen = cpu_to_le16(fst_dentry->d_name.len); dent2->nlen = cpu_to_le16(fname_len(fst_nm));
memcpy(dent2->name, fst_dentry->d_name.name, fst_dentry->d_name.len); memcpy(dent2->name, fname_name(fst_nm), fname_len(fst_nm));
dent2->name[fst_dentry->d_name.len] = '\0'; dent2->name[fname_len(fst_nm)] = '\0';
zero_dent_node_unused(dent2); zero_dent_node_unused(dent2);
ubifs_prep_grp_node(c, dent2, dlen2, 0); ubifs_prep_grp_node(c, dent2, dlen2, 0);
...@@ -1004,14 +1018,14 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -1004,14 +1018,14 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
} }
release_head(c, BASEHD); release_head(c, BASEHD);
dent_key_init(c, &key, snd_dir->i_ino, &snd_dentry->d_name); dent_key_init(c, &key, snd_dir->i_ino, snd_nm);
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &snd_dentry->d_name); err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, snd_nm);
if (err) if (err)
goto out_ro; goto out_ro;
offs += aligned_dlen1; offs += aligned_dlen1;
dent_key_init(c, &key, fst_dir->i_ino, &fst_dentry->d_name); dent_key_init(c, &key, fst_dir->i_ino, fst_nm);
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &fst_dentry->d_name); err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, fst_nm);
if (err) if (err)
goto out_ro; goto out_ro;
...@@ -1063,31 +1077,31 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, ...@@ -1063,31 +1077,31 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
* returned. * returned.
*/ */
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
const struct dentry *old_dentry, const struct inode *old_inode,
const struct fscrypt_name *old_nm,
const struct inode *new_dir, const struct inode *new_dir,
const struct dentry *new_dentry, const struct inode *new_inode,
const struct fscrypt_name *new_nm,
const struct inode *whiteout, int sync) const struct inode *whiteout, int sync)
{ {
void *p; void *p;
union ubifs_key key; union ubifs_key key;
struct ubifs_dent_node *dent, *dent2; struct ubifs_dent_node *dent, *dent2;
int err, dlen1, dlen2, ilen, lnum, offs, len; int err, dlen1, dlen2, ilen, lnum, offs, len;
const struct inode *old_inode = d_inode(old_dentry);
const struct inode *new_inode = d_inode(new_dentry);
int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ; int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ;
int last_reference = !!(new_inode && new_inode->i_nlink == 0); int last_reference = !!(new_inode && new_inode->i_nlink == 0);
int move = (old_dir != new_dir); int move = (old_dir != new_dir);
struct ubifs_inode *uninitialized_var(new_ui); struct ubifs_inode *uninitialized_var(new_ui);
dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu", //dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino); // old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
ubifs_assert(ubifs_inode(old_dir)->data_len == 0); ubifs_assert(ubifs_inode(old_dir)->data_len == 0);
ubifs_assert(ubifs_inode(new_dir)->data_len == 0); ubifs_assert(ubifs_inode(new_dir)->data_len == 0);
ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex)); ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex));
ubifs_assert(mutex_is_locked(&ubifs_inode(new_dir)->ui_mutex)); ubifs_assert(mutex_is_locked(&ubifs_inode(new_dir)->ui_mutex));
dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1; dlen1 = UBIFS_DENT_NODE_SZ + fname_len(new_nm) + 1;
dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1; dlen2 = UBIFS_DENT_NODE_SZ + fname_len(old_nm) + 1;
if (new_inode) { if (new_inode) {
new_ui = ubifs_inode(new_inode); new_ui = ubifs_inode(new_inode);
ubifs_assert(mutex_is_locked(&new_ui->ui_mutex)); ubifs_assert(mutex_is_locked(&new_ui->ui_mutex));
...@@ -1113,19 +1127,19 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1113,19 +1127,19 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
/* Make new dent */ /* Make new dent */
dent->ch.node_type = UBIFS_DENT_NODE; dent->ch.node_type = UBIFS_DENT_NODE;
dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name); dent_key_init_flash(c, &dent->key, new_dir->i_ino, new_nm);
dent->inum = cpu_to_le64(old_inode->i_ino); dent->inum = cpu_to_le64(old_inode->i_ino);
dent->type = get_dent_type(old_inode->i_mode); dent->type = get_dent_type(old_inode->i_mode);
dent->nlen = cpu_to_le16(new_dentry->d_name.len); dent->nlen = cpu_to_le16(fname_len(new_nm));
memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len); memcpy(dent->name, fname_name(new_nm), fname_len(new_nm));
dent->name[new_dentry->d_name.len] = '\0'; dent->name[fname_len(new_nm)] = '\0';
set_dent_cookie(c, dent);
zero_dent_node_unused(dent); zero_dent_node_unused(dent);
ubifs_prep_grp_node(c, dent, dlen1, 0); ubifs_prep_grp_node(c, dent, dlen1, 0);
dent2 = (void *)dent + aligned_dlen1; dent2 = (void *)dent + aligned_dlen1;
dent2->ch.node_type = UBIFS_DENT_NODE; dent2->ch.node_type = UBIFS_DENT_NODE;
dent_key_init_flash(c, &dent2->key, old_dir->i_ino, dent_key_init_flash(c, &dent2->key, old_dir->i_ino, old_nm);
&old_dentry->d_name);
if (whiteout) { if (whiteout) {
dent2->inum = cpu_to_le64(whiteout->i_ino); dent2->inum = cpu_to_le64(whiteout->i_ino);
...@@ -1135,9 +1149,10 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1135,9 +1149,10 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
dent2->inum = 0; dent2->inum = 0;
dent2->type = DT_UNKNOWN; dent2->type = DT_UNKNOWN;
} }
dent2->nlen = cpu_to_le16(old_dentry->d_name.len); dent2->nlen = cpu_to_le16(fname_len(old_nm));
memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len); memcpy(dent2->name, fname_name(old_nm), fname_len(old_nm));
dent2->name[old_dentry->d_name.len] = '\0'; dent2->name[fname_len(old_nm)] = '\0';
set_dent_cookie(c, dent2);
zero_dent_node_unused(dent2); zero_dent_node_unused(dent2);
ubifs_prep_grp_node(c, dent2, dlen2, 0); ubifs_prep_grp_node(c, dent2, dlen2, 0);
...@@ -1178,15 +1193,15 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1178,15 +1193,15 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
} }
release_head(c, BASEHD); release_head(c, BASEHD);
dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name); dent_key_init(c, &key, new_dir->i_ino, new_nm);
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name); err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, new_nm);
if (err) if (err)
goto out_ro; goto out_ro;
offs += aligned_dlen1; offs += aligned_dlen1;
if (whiteout) { if (whiteout) {
dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name); dent_key_init(c, &key, old_dir->i_ino, old_nm);
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &old_dentry->d_name); err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, old_nm);
if (err) if (err)
goto out_ro; goto out_ro;
...@@ -1196,8 +1211,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1196,8 +1211,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
if (err) if (err)
goto out_ro; goto out_ro;
dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name); dent_key_init(c, &key, old_dir->i_ino, old_nm);
err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name); err = ubifs_tnc_remove_nm(c, &key, old_nm);
if (err) if (err)
goto out_ro; goto out_ro;
} }
...@@ -1251,31 +1266,55 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, ...@@ -1251,31 +1266,55 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
} }
/** /**
* recomp_data_node - re-compress a truncated data node. * truncate_data_node - re-compress/encrypt a truncated data node.
* @c: UBIFS file-system description object
* @inode: inode which referes to the data node
* @block: data block number
* @dn: data node to re-compress * @dn: data node to re-compress
* @new_len: new length * @new_len: new length
* *
* This function is used when an inode is truncated and the last data node of * This function is used when an inode is truncated and the last data node of
* the inode has to be re-compressed and re-written. * the inode has to be re-compressed/encrypted and re-written.
*/ */
static int recomp_data_node(const struct ubifs_info *c, static int truncate_data_node(const struct ubifs_info *c, const struct inode *inode,
struct ubifs_data_node *dn, int *new_len) unsigned int block, struct ubifs_data_node *dn,
int *new_len)
{ {
void *buf; void *buf;
int err, len, compr_type, out_len; int err, dlen, compr_type, out_len, old_dlen;
out_len = le32_to_cpu(dn->size); out_len = le32_to_cpu(dn->size);
buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS); buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ; dlen = old_dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
compr_type = le16_to_cpu(dn->compr_type); compr_type = le16_to_cpu(dn->compr_type);
err = ubifs_decompress(c, &dn->data, len, buf, &out_len, compr_type);
if (ubifs_crypt_is_encrypted(inode)) {
err = ubifs_decrypt(inode, dn, &dlen, block);
if (err)
goto out;
}
if (compr_type != UBIFS_COMPR_NONE) {
err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
if (err) if (err)
goto out; goto out;
ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type); ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
}
if (ubifs_crypt_is_encrypted(inode)) {
err = ubifs_encrypt(inode, dn, out_len, &old_dlen, block);
if (err)
goto out;
out_len = old_dlen;
} else {
dn->compr_size = 0;
}
ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
dn->compr_type = cpu_to_le16(compr_type); dn->compr_type = cpu_to_le16(compr_type);
dn->size = cpu_to_le32(*new_len); dn->size = cpu_to_le32(*new_len);
...@@ -1347,17 +1386,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, ...@@ -1347,17 +1386,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
if (le32_to_cpu(dn->size) <= dlen) if (le32_to_cpu(dn->size) <= dlen)
dlen = 0; /* Nothing to do */ dlen = 0; /* Nothing to do */
else { else {
int compr_type = le16_to_cpu(dn->compr_type); err = truncate_data_node(c, inode, blk, dn, &dlen);
if (compr_type != UBIFS_COMPR_NONE) {
err = recomp_data_node(c, dn, &dlen);
if (err) if (err)
goto out_free; goto out_free;
} else {
dn->size = cpu_to_le32(dlen);
dlen += UBIFS_DATA_NODE_SZ;
}
zero_data_node_unused(dn);
} }
} }
} }
...@@ -1442,7 +1473,8 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, ...@@ -1442,7 +1473,8 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
* error code in case of failure. * error code in case of failure.
*/ */
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
const struct inode *inode, const struct qstr *nm) const struct inode *inode,
const struct fscrypt_name *nm)
{ {
int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen; int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen;
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
...@@ -1451,9 +1483,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ...@@ -1451,9 +1483,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
int sync = IS_DIRSYNC(host); int sync = IS_DIRSYNC(host);
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d", //dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
host->i_ino, inode->i_ino, nm->name, // host->i_ino, inode->i_ino, nm->name,
ubifs_inode(inode)->data_len); // ubifs_inode(inode)->data_len);
ubifs_assert(inode->i_nlink == 0); ubifs_assert(inode->i_nlink == 0);
ubifs_assert(mutex_is_locked(&host_ui->ui_mutex)); ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
...@@ -1461,7 +1493,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ...@@ -1461,7 +1493,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
* Since we are deleting the inode, we do not bother to attach any data * Since we are deleting the inode, we do not bother to attach any data
* to it and assume its length is %UBIFS_INO_NODE_SZ. * to it and assume its length is %UBIFS_INO_NODE_SZ.
*/ */
xlen = UBIFS_DENT_NODE_SZ + nm->len + 1; xlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
aligned_xlen = ALIGN(xlen, 8); aligned_xlen = ALIGN(xlen, 8);
hlen = host_ui->data_len + UBIFS_INO_NODE_SZ; hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
...@@ -1482,9 +1514,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, ...@@ -1482,9 +1514,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
key_write(c, &xent_key, xent->key); key_write(c, &xent_key, xent->key);
xent->inum = 0; xent->inum = 0;
xent->type = get_dent_type(inode->i_mode); xent->type = get_dent_type(inode->i_mode);
xent->nlen = cpu_to_le16(nm->len); xent->nlen = cpu_to_le16(fname_len(nm));
memcpy(xent->name, nm->name, nm->len); memcpy(xent->name, fname_name(nm), fname_len(nm));
xent->name[nm->len] = '\0'; xent->name[fname_len(nm)] = '\0';
zero_dent_node_unused(xent); zero_dent_node_unused(xent);
ubifs_prep_grp_node(c, xent, xlen, 0); ubifs_prep_grp_node(c, xent, xlen, 0);
......
...@@ -69,7 +69,7 @@ static inline uint32_t key_r5_hash(const char *s, int len) ...@@ -69,7 +69,7 @@ static inline uint32_t key_r5_hash(const char *s, int len)
uint32_t a = 0; uint32_t a = 0;
const signed char *str = (const signed char *)s; const signed char *str = (const signed char *)s;
while (*str) { while (len--) {
a += *str << 4; a += *str << 4;
a += *str >> 4; a += *str >> 4;
a *= 11; a *= 11;
...@@ -153,13 +153,13 @@ static inline void highest_ino_key(const struct ubifs_info *c, ...@@ -153,13 +153,13 @@ static inline void highest_ino_key(const struct ubifs_info *c,
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @key: key to initialize * @key: key to initialize
* @inum: parent inode number * @inum: parent inode number
* @nm: direntry name and length * @nm: direntry name and length. Not a string when encrypted!
*/ */
static inline void dent_key_init(const struct ubifs_info *c, static inline void dent_key_init(const struct ubifs_info *c,
union ubifs_key *key, ino_t inum, union ubifs_key *key, ino_t inum,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
uint32_t hash = c->key_hash(nm->name, nm->len); uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
key->u32[0] = inum; key->u32[0] = inum;
...@@ -191,10 +191,11 @@ static inline void dent_key_init_hash(const struct ubifs_info *c, ...@@ -191,10 +191,11 @@ static inline void dent_key_init_hash(const struct ubifs_info *c,
* @nm: direntry name and length * @nm: direntry name and length
*/ */
static inline void dent_key_init_flash(const struct ubifs_info *c, void *k, static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
ino_t inum, const struct qstr *nm) ino_t inum,
const struct fscrypt_name *nm)
{ {
union ubifs_key *key = k; union ubifs_key *key = k;
uint32_t hash = c->key_hash(nm->name, nm->len); uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
key->j32[0] = cpu_to_le32(inum); key->j32[0] = cpu_to_le32(inum);
...@@ -225,9 +226,9 @@ static inline void lowest_dent_key(const struct ubifs_info *c, ...@@ -225,9 +226,9 @@ static inline void lowest_dent_key(const struct ubifs_info *c,
*/ */
static inline void xent_key_init(const struct ubifs_info *c, static inline void xent_key_init(const struct ubifs_info *c,
union ubifs_key *key, ino_t inum, union ubifs_key *key, ino_t inum,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
uint32_t hash = c->key_hash(nm->name, nm->len); uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
key->u32[0] = inum; key->u32[0] = inum;
...@@ -242,10 +243,10 @@ static inline void xent_key_init(const struct ubifs_info *c, ...@@ -242,10 +243,10 @@ static inline void xent_key_init(const struct ubifs_info *c,
* @nm: extended attribute entry name and length * @nm: extended attribute entry name and length
*/ */
static inline void xent_key_init_flash(const struct ubifs_info *c, void *k, static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
ino_t inum, const struct qstr *nm) ino_t inum, const struct fscrypt_name *nm)
{ {
union ubifs_key *key = k; union ubifs_key *key = k;
uint32_t hash = c->key_hash(nm->name, nm->len); uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK)); ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
key->j32[0] = cpu_to_le32(inum); key->j32[0] = cpu_to_le32(inum);
......
...@@ -61,7 +61,7 @@ struct replay_entry { ...@@ -61,7 +61,7 @@ struct replay_entry {
struct list_head list; struct list_head list;
union ubifs_key key; union ubifs_key key;
union { union {
struct qstr nm; struct fscrypt_name nm;
struct { struct {
loff_t old_size; loff_t old_size;
loff_t new_size; loff_t new_size;
...@@ -327,7 +327,7 @@ static void destroy_replay_list(struct ubifs_info *c) ...@@ -327,7 +327,7 @@ static void destroy_replay_list(struct ubifs_info *c)
list_for_each_entry_safe(r, tmp, &c->replay_list, list) { list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
if (is_hash_key(c, &r->key)) if (is_hash_key(c, &r->key))
kfree(r->nm.name); kfree(fname_name(&r->nm));
list_del(&r->list); list_del(&r->list);
kfree(r); kfree(r);
} }
...@@ -430,10 +430,10 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, ...@@ -430,10 +430,10 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
r->deletion = !!deletion; r->deletion = !!deletion;
r->sqnum = sqnum; r->sqnum = sqnum;
key_copy(c, key, &r->key); key_copy(c, key, &r->key);
r->nm.len = nlen; fname_len(&r->nm) = nlen;
memcpy(nbuf, name, nlen); memcpy(nbuf, name, nlen);
nbuf[nlen] = '\0'; nbuf[nlen] = '\0';
r->nm.name = nbuf; fname_name(&r->nm) = nbuf;
list_add_tail(&r->list, &c->replay_list); list_add_tail(&r->list, &c->replay_list);
return 0; return 0;
...@@ -456,7 +456,7 @@ int ubifs_validate_entry(struct ubifs_info *c, ...@@ -456,7 +456,7 @@ int ubifs_validate_entry(struct ubifs_info *c,
if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 || if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
dent->type >= UBIFS_ITYPES_CNT || dent->type >= UBIFS_ITYPES_CNT ||
nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 || nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
strnlen(dent->name, nlen) != nlen || (key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) ||
le64_to_cpu(dent->inum) > MAX_INUM) { le64_to_cpu(dent->inum) > MAX_INUM) {
ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ? ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ?
"directory entry" : "extended attribute entry"); "directory entry" : "extended attribute entry");
......
...@@ -163,6 +163,7 @@ static int create_default_filesystem(struct ubifs_info *c) ...@@ -163,6 +163,7 @@ static int create_default_filesystem(struct ubifs_info *c)
tmp64 = (long long)max_buds * c->leb_size; tmp64 = (long long)max_buds * c->leb_size;
if (big_lpt) if (big_lpt)
sup_flags |= UBIFS_FLG_BIGLPT; sup_flags |= UBIFS_FLG_BIGLPT;
sup_flags |= UBIFS_FLG_DOUBLE_HASH;
sup->ch.node_type = UBIFS_SB_NODE; sup->ch.node_type = UBIFS_SB_NODE;
sup->key_hash = UBIFS_KEY_HASH_R5; sup->key_hash = UBIFS_KEY_HASH_R5;
...@@ -465,6 +466,16 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup) ...@@ -465,6 +466,16 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
goto failed; goto failed;
} }
if (!c->double_hash && c->fmt_version >= 5) {
err = 16;
goto failed;
}
if (c->encrypted && c->fmt_version < 5) {
err = 17;
goto failed;
}
return 0; return 0;
failed: failed:
...@@ -620,6 +631,24 @@ int ubifs_read_superblock(struct ubifs_info *c) ...@@ -620,6 +631,24 @@ int ubifs_read_superblock(struct ubifs_info *c)
memcpy(&c->uuid, &sup->uuid, 16); memcpy(&c->uuid, &sup->uuid, 16);
c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT); c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP); c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
ubifs_err(c, "Unknown feature flags found: %#x",
sup_flags & ~UBIFS_FLG_MASK);
err = -EINVAL;
goto out;
}
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
if (c->encrypted) {
ubifs_err(c, "file system contains encrypted files but UBIFS"
" was built without crypto support.");
err = -EINVAL;
goto out;
}
#endif
/* Automatically increase file system size to the maximum size */ /* Automatically increase file system size to the maximum size */
c->old_leb_cnt = c->leb_cnt; c->old_leb_cnt = c->leb_cnt;
...@@ -807,3 +836,33 @@ int ubifs_fixup_free_space(struct ubifs_info *c) ...@@ -807,3 +836,33 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
ubifs_msg(c, "free space fixup complete"); ubifs_msg(c, "free space fixup complete");
return err; return err;
} }
int ubifs_enable_encryption(struct ubifs_info *c)
{
int err;
struct ubifs_sb_node *sup;
if (c->encrypted)
return 0;
if (c->ro_mount || c->ro_media)
return -EROFS;
if (c->fmt_version < 5) {
ubifs_err(c, "on-flash format version 5 is needed for encryption");
return -EINVAL;
}
sup = ubifs_read_sb_node(c);
if (IS_ERR(sup))
return PTR_ERR(sup);
sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION);
err = ubifs_write_sb_node(c, sup);
if (!err)
c->encrypted = 1;
kfree(sup);
return err;
}
...@@ -198,7 +198,6 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ...@@ -198,7 +198,6 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
} }
memcpy(ui->data, ino->data, ui->data_len); memcpy(ui->data, ino->data, ui->data_len);
((char *)ui->data)[ui->data_len] = '\0'; ((char *)ui->data)[ui->data_len] = '\0';
inode->i_link = ui->data;
break; break;
case S_IFBLK: case S_IFBLK:
case S_IFCHR: case S_IFCHR:
...@@ -380,6 +379,9 @@ static void ubifs_evict_inode(struct inode *inode) ...@@ -380,6 +379,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)
...@@ -1207,7 +1209,8 @@ static int mount_ubifs(struct ubifs_info *c) ...@@ -1207,7 +1209,8 @@ static int mount_ubifs(struct ubifs_info *c)
bu_init(c); bu_init(c);
if (!c->ro_mount) { if (!c->ro_mount) {
c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
UBIFS_CIPHER_BLOCK_SIZE,
GFP_KERNEL); GFP_KERNEL);
if (!c->write_reserve_buf) if (!c->write_reserve_buf)
goto out_free; goto out_free;
...@@ -1620,7 +1623,8 @@ static int ubifs_remount_rw(struct ubifs_info *c) ...@@ -1620,7 +1623,8 @@ static int ubifs_remount_rw(struct ubifs_info *c)
goto out; goto out;
} }
c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL); c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
UBIFS_CIPHER_BLOCK_SIZE, GFP_KERNEL);
if (!c->write_reserve_buf) { if (!c->write_reserve_buf) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
...@@ -1995,6 +1999,12 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi) ...@@ -1995,6 +1999,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 +2051,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2041,6 +2051,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);
......
...@@ -378,7 +378,7 @@ static void lnc_free(struct ubifs_zbranch *zbr) ...@@ -378,7 +378,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
} }
/** /**
* tnc_read_node_nm - read a "hashed" leaf node. * tnc_read_hashed_node - read a "hashed" leaf node.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
* @zbr: key and position of the node * @zbr: key and position of the node
* @node: node is returned here * @node: node is returned here
...@@ -388,7 +388,7 @@ static void lnc_free(struct ubifs_zbranch *zbr) ...@@ -388,7 +388,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
* added to LNC. Returns zero in case of success or a negative negative error * added to LNC. Returns zero in case of success or a negative negative error
* code in case of failure. * code in case of failure.
*/ */
static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr, static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
void *node) void *node)
{ {
int err; int err;
...@@ -519,7 +519,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, ...@@ -519,7 +519,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
* of failure, a negative error code is returned. * of failure, a negative error code is returned.
*/ */
static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr, static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
struct ubifs_dent_node *dent; struct ubifs_dent_node *dent;
int nlen, err; int nlen, err;
...@@ -542,11 +542,11 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr, ...@@ -542,11 +542,11 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
dent = zbr->leaf; dent = zbr->leaf;
nlen = le16_to_cpu(dent->nlen); nlen = le16_to_cpu(dent->nlen);
err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len)); err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
if (err == 0) { if (err == 0) {
if (nlen == nm->len) if (nlen == fname_len(nm))
return NAME_MATCHES; return NAME_MATCHES;
else if (nlen < nm->len) else if (nlen < fname_len(nm))
return NAME_LESS; return NAME_LESS;
else else
return NAME_GREATER; return NAME_GREATER;
...@@ -689,7 +689,7 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n) ...@@ -689,7 +689,7 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
*/ */
static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key, static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode **zn, int *n, struct ubifs_znode **zn, int *n,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
int err; int err;
...@@ -807,7 +807,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key, ...@@ -807,7 +807,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
*/ */
static int fallible_matches_name(struct ubifs_info *c, static int fallible_matches_name(struct ubifs_info *c,
struct ubifs_zbranch *zbr, struct ubifs_zbranch *zbr,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
struct ubifs_dent_node *dent; struct ubifs_dent_node *dent;
int nlen, err; int nlen, err;
...@@ -835,11 +835,11 @@ static int fallible_matches_name(struct ubifs_info *c, ...@@ -835,11 +835,11 @@ static int fallible_matches_name(struct ubifs_info *c,
dent = zbr->leaf; dent = zbr->leaf;
nlen = le16_to_cpu(dent->nlen); nlen = le16_to_cpu(dent->nlen);
err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len)); err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
if (err == 0) { if (err == 0) {
if (nlen == nm->len) if (nlen == fname_len(nm))
return NAME_MATCHES; return NAME_MATCHES;
else if (nlen < nm->len) else if (nlen < fname_len(nm))
return NAME_LESS; return NAME_LESS;
else else
return NAME_GREATER; return NAME_GREATER;
...@@ -878,7 +878,8 @@ static int fallible_matches_name(struct ubifs_info *c, ...@@ -878,7 +878,8 @@ static int fallible_matches_name(struct ubifs_info *c,
static int fallible_resolve_collision(struct ubifs_info *c, static int fallible_resolve_collision(struct ubifs_info *c,
const union ubifs_key *key, const union ubifs_key *key,
struct ubifs_znode **zn, int *n, struct ubifs_znode **zn, int *n,
const struct qstr *nm, int adding) const struct fscrypt_name *nm,
int adding)
{ {
struct ubifs_znode *o_znode = NULL, *znode = *zn; struct ubifs_znode *o_znode = NULL, *znode = *zn;
int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n; int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
...@@ -1453,7 +1454,7 @@ int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1453,7 +1454,7 @@ int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
* In this case the leaf node cache gets used, so we pass the * In this case the leaf node cache gets used, so we pass the
* address of the zbranch and keep the mutex locked * address of the zbranch and keep the mutex locked
*/ */
err = tnc_read_node_nm(c, zt, node); err = tnc_read_hashed_node(c, zt, node);
goto out; goto out;
} }
if (safely) { if (safely) {
...@@ -1782,19 +1783,19 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu) ...@@ -1782,19 +1783,19 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
* @node: the node is returned here * @node: the node is returned here
* @nm: node name * @nm: node name
* *
* This function look up and reads a node which contains name hash in the key. * This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same * Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one is * key, so we have to sequentially look to all of them until the needed one is
* found. This function returns zero in case of success, %-ENOENT if the node * found. This function returns zero in case of success, %-ENOENT if the node
* was not found, and a negative error code in case of failure. * was not found, and a negative error code in case of failure.
*/ */
static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
void *node, const struct qstr *nm) void *node, const struct fscrypt_name *nm)
{ {
int found, n, err; int found, n, err;
struct ubifs_znode *znode; struct ubifs_znode *znode;
dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name); //dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
found = ubifs_lookup_level0(c, key, &znode, &n); found = ubifs_lookup_level0(c, key, &znode, &n);
if (!found) { if (!found) {
...@@ -1816,7 +1817,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1816,7 +1817,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
goto out_unlock; goto out_unlock;
} }
err = tnc_read_node_nm(c, &znode->zbranch[n], node); err = tnc_read_hashed_node(c, &znode->zbranch[n], node);
out_unlock: out_unlock:
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
...@@ -1830,14 +1831,14 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1830,14 +1831,14 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
* @node: the node is returned here * @node: the node is returned here
* @nm: node name * @nm: node name
* *
* This function look up and reads a node which contains name hash in the key. * This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same * Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one is * key, so we have to sequentially look to all of them until the needed one is
* found. This function returns zero in case of success, %-ENOENT if the node * found. This function returns zero in case of success, %-ENOENT if the node
* was not found, and a negative error code in case of failure. * was not found, and a negative error code in case of failure.
*/ */
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
void *node, const struct qstr *nm) void *node, const struct fscrypt_name *nm)
{ {
int err, len; int err, len;
const struct ubifs_dent_node *dent = node; const struct ubifs_dent_node *dent = node;
...@@ -1851,16 +1852,105 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -1851,16 +1852,105 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
return err; return err;
len = le16_to_cpu(dent->nlen); len = le16_to_cpu(dent->nlen);
if (nm->len == len && !memcmp(dent->name, nm->name, len)) if (fname_len(nm) == len && !memcmp(dent->name, fname_name(nm), len))
return 0; return 0;
/* /*
* Unluckily, there are hash collisions and we have to iterate over * Unluckily, there are hash collisions and we have to iterate over
* them look at each direntry with colliding name hash sequentially. * them look at each direntry with colliding name hash sequentially.
*/ */
return do_lookup_nm(c, key, node, nm); return do_lookup_nm(c, key, node, nm);
} }
static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_dent_node *dent, uint32_t cookie)
{
int n, err, type = key_type(c, key);
struct ubifs_znode *znode;
struct ubifs_zbranch *zbr;
union ubifs_key *dkey, start_key;
ubifs_assert(is_hash_key(c, key));
lowest_dent_key(c, &start_key, key_inum(c, key));
mutex_lock(&c->tnc_mutex);
err = ubifs_lookup_level0(c, &start_key, &znode, &n);
if (unlikely(err < 0))
goto out_unlock;
for (;;) {
if (!err) {
err = tnc_next(c, &znode, &n);
if (err)
goto out_unlock;
}
zbr = &znode->zbranch[n];
dkey = &zbr->key;
if (key_inum(c, dkey) != key_inum(c, key) ||
key_type(c, dkey) != type) {
err = -ENOENT;
goto out_unlock;
}
err = tnc_read_hashed_node(c, zbr, dent);
if (err)
goto out_unlock;
if (key_hash(c, key) == key_hash(c, dkey) &&
le32_to_cpu(dent->cookie) == cookie)
goto out_unlock;
}
out_unlock:
mutex_unlock(&c->tnc_mutex);
return err;
}
/**
* ubifs_tnc_lookup_dh - look up a "double hashed" node.
* @c: UBIFS file-system description object
* @key: node key to lookup
* @node: the node is returned here
* @cookie: node cookie for collision resolution
*
* This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one
* with the same cookie value is found.
* This function returns zero in case of success, %-ENOENT if the node
* was not found, and a negative error code in case of failure.
*/
int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
void *node, uint32_t cookie)
{
int err;
const struct ubifs_dent_node *dent = node;
if (!c->double_hash)
return -EOPNOTSUPP;
/*
* We assume that in most of the cases there are no name collisions and
* 'ubifs_tnc_lookup()' returns us the right direntry.
*/
err = ubifs_tnc_lookup(c, key, node);
if (err)
return err;
if (le32_to_cpu(dent->cookie) == cookie)
return 0;
/*
* Unluckily, there are hash collisions and we have to iterate over
* them look at each direntry with colliding name hash sequentially.
*/
return do_lookup_dh(c, key, node, cookie);
}
/** /**
* correct_parent_keys - correct parent znodes' keys. * correct_parent_keys - correct parent znodes' keys.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -2279,14 +2369,15 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2279,14 +2369,15 @@ int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
* may have collisions, like directory entry keys. * may have collisions, like directory entry keys.
*/ */
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
int lnum, int offs, int len, const struct qstr *nm) int lnum, int offs, int len,
const struct fscrypt_name *nm)
{ {
int found, n, err = 0; int found, n, err = 0;
struct ubifs_znode *znode; struct ubifs_znode *znode;
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
dbg_tnck(key, "LEB %d:%d, name '%.*s', key ", //dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
lnum, offs, nm->len, nm->name); // lnum, offs, nm->len, nm->name);
found = lookup_level0_dirty(c, key, &znode, &n); found = lookup_level0_dirty(c, key, &znode, &n);
if (found < 0) { if (found < 0) {
err = found; err = found;
...@@ -2344,7 +2435,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, ...@@ -2344,7 +2435,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
* by passing 'ubifs_tnc_remove_nm()' the same key but * by passing 'ubifs_tnc_remove_nm()' the same key but
* an unmatchable name. * an unmatchable name.
*/ */
struct qstr noname = { .name = "" }; struct fscrypt_name noname = { .disk_name = { .name = "", .len = 1 } };
err = dbg_check_tnc(c, 0); err = dbg_check_tnc(c, 0);
mutex_unlock(&c->tnc_mutex); mutex_unlock(&c->tnc_mutex);
...@@ -2514,13 +2605,13 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key) ...@@ -2514,13 +2605,13 @@ int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key)
* Returns %0 on success or negative error code on failure. * Returns %0 on success or negative error code on failure.
*/ */
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
int n, err; int n, err;
struct ubifs_znode *znode; struct ubifs_znode *znode;
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
dbg_tnck(key, "%.*s, key ", nm->len, nm->name); //dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
err = lookup_level0_dirty(c, key, &znode, &n); err = lookup_level0_dirty(c, key, &znode, &n);
if (err < 0) if (err < 0)
goto out_unlock; goto out_unlock;
...@@ -2669,7 +2760,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) ...@@ -2669,7 +2760,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
{ {
union ubifs_key key1, key2; union ubifs_key key1, key2;
struct ubifs_dent_node *xent, *pxent = NULL; struct ubifs_dent_node *xent, *pxent = NULL;
struct qstr nm = { .name = NULL }; struct fscrypt_name nm = {0};
dbg_tnc("ino %lu", (unsigned long)inum); dbg_tnc("ino %lu", (unsigned long)inum);
...@@ -2694,8 +2785,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) ...@@ -2694,8 +2785,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
dbg_tnc("xent '%s', ino %lu", xent->name, dbg_tnc("xent '%s', ino %lu", xent->name,
(unsigned long)xattr_inum); (unsigned long)xattr_inum);
nm.name = xent->name; fname_name(&nm) = xent->name;
nm.len = le16_to_cpu(xent->nlen); fname_len(&nm) = le16_to_cpu(xent->nlen);
err = ubifs_tnc_remove_nm(c, &key1, &nm); err = ubifs_tnc_remove_nm(c, &key1, &nm);
if (err) { if (err) {
kfree(xent); kfree(xent);
...@@ -2747,7 +2838,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) ...@@ -2747,7 +2838,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
*/ */
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
union ubifs_key *key, union ubifs_key *key,
const struct qstr *nm) const struct fscrypt_name *nm)
{ {
int n, err, type = key_type(c, key); int n, err, type = key_type(c, key);
struct ubifs_znode *znode; struct ubifs_znode *znode;
...@@ -2755,7 +2846,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, ...@@ -2755,7 +2846,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
struct ubifs_zbranch *zbr; struct ubifs_zbranch *zbr;
union ubifs_key *dkey; union ubifs_key *dkey;
dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)"); //dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
ubifs_assert(is_hash_key(c, key)); ubifs_assert(is_hash_key(c, key));
mutex_lock(&c->tnc_mutex); mutex_lock(&c->tnc_mutex);
...@@ -2763,7 +2854,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, ...@@ -2763,7 +2854,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
if (unlikely(err < 0)) if (unlikely(err < 0))
goto out_unlock; goto out_unlock;
if (nm->name) { if (fname_len(nm) > 0) {
if (err) { if (err) {
/* Handle collisions */ /* Handle collisions */
err = resolve_collision(c, key, &znode, &n, nm); err = resolve_collision(c, key, &znode, &n, nm);
...@@ -2813,7 +2904,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, ...@@ -2813,7 +2904,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
goto out_free; goto out_free;
} }
err = tnc_read_node_nm(c, zbr, dent); err = tnc_read_hashed_node(c, zbr, dent);
if (unlikely(err)) if (unlikely(err))
goto out_free; goto out_free;
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
* UBIFS went into mainline kernel with format version 4. The older formats * UBIFS went into mainline kernel with format version 4. The older formats
* were development formats. * were development formats.
*/ */
#define UBIFS_FORMAT_VERSION 4 #define UBIFS_FORMAT_VERSION 5
/* /*
* Read-only compatibility version. If the UBIFS format is changed, older UBIFS * Read-only compatibility version. If the UBIFS format is changed, older UBIFS
...@@ -300,6 +300,13 @@ enum { ...@@ -300,6 +300,13 @@ enum {
/* The largest UBIFS node */ /* The largest UBIFS node */
#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ #define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
/*
* xattr name of UBIFS encryption context, we don't use a prefix
* nor a long name to not waste space on the flash.
*/
#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
/* /*
* On-flash inode flags. * On-flash inode flags.
* *
...@@ -309,6 +316,7 @@ enum { ...@@ -309,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
...@@ -321,6 +329,7 @@ enum { ...@@ -321,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 */
...@@ -409,12 +418,19 @@ enum { ...@@ -409,12 +418,19 @@ enum {
* *
* UBIFS_FLG_BIGLPT: if "big" LPT model is used if set * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
* UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
* UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
* support 64bit cookies for lookups by hash
* UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
*/ */
enum { enum {
UBIFS_FLG_BIGLPT = 0x02, UBIFS_FLG_BIGLPT = 0x02,
UBIFS_FLG_SPACE_FIXUP = 0x04, UBIFS_FLG_SPACE_FIXUP = 0x04,
UBIFS_FLG_DOUBLE_HASH = 0x08,
UBIFS_FLG_ENCRYPTION = 0x10,
}; };
#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION)
/** /**
* struct ubifs_ch - common header node. * struct ubifs_ch - common header node.
* @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC) * @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
...@@ -521,7 +537,8 @@ struct ubifs_ino_node { ...@@ -521,7 +537,8 @@ struct ubifs_ino_node {
* @padding1: reserved for future, zeroes * @padding1: reserved for future, zeroes
* @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc) * @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
* @nlen: name length * @nlen: name length
* @padding2: reserved for future, zeroes * @cookie: A 32bits random number, used to construct a 64bits
* identifier.
* @name: zero-terminated name * @name: zero-terminated name
* *
* Note, do not forget to amend 'zero_dent_node_unused()' function when * Note, do not forget to amend 'zero_dent_node_unused()' function when
...@@ -534,7 +551,7 @@ struct ubifs_dent_node { ...@@ -534,7 +551,7 @@ struct ubifs_dent_node {
__u8 padding1; __u8 padding1;
__u8 type; __u8 type;
__le16 nlen; __le16 nlen;
__u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */ __le32 cookie;
__u8 name[]; __u8 name[];
} __packed; } __packed;
...@@ -544,18 +561,16 @@ struct ubifs_dent_node { ...@@ -544,18 +561,16 @@ struct ubifs_dent_node {
* @key: node key * @key: node key
* @size: uncompressed data size in bytes * @size: uncompressed data size in bytes
* @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc) * @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
* @padding: reserved for future, zeroes * @compr_size: compressed data size in bytes, only valid when data is encrypted
* @data: data * @data: data
* *
* Note, do not forget to amend 'zero_data_node_unused()' function when
* changing the padding fields.
*/ */
struct ubifs_data_node { struct ubifs_data_node {
struct ubifs_ch ch; struct ubifs_ch ch;
__u8 key[UBIFS_MAX_KEY_LEN]; __u8 key[UBIFS_MAX_KEY_LEN];
__le32 size; __le32 size;
__le16 compr_type; __le16 compr_type;
__u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */ __le16 compr_size;
__u8 data[]; __u8 data[];
} __packed; } __packed;
......
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
#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 <linux/random.h>
#include "ubifs-media.h" #include "ubifs-media.h"
/* Version of this UBIFS implementation */ /* Version of this UBIFS implementation */
...@@ -83,10 +85,6 @@ ...@@ -83,10 +85,6 @@
*/ */
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d" #define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
/* Write-buffer synchronization timeout interval in seconds */
#define WBUF_TIMEOUT_SOFTLIMIT 3
#define WBUF_TIMEOUT_HARDLIMIT 5
/* Maximum possible inode number (only 32-bit inodes are supported now) */ /* Maximum possible inode number (only 32-bit inodes are supported now) */
#define MAX_INUM 0xFFFFFFFF #define MAX_INUM 0xFFFFFFFF
...@@ -138,6 +136,12 @@ ...@@ -138,6 +136,12 @@
*/ */
#define WORST_COMPR_FACTOR 2 #define WORST_COMPR_FACTOR 2
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
#define UBIFS_CIPHER_BLOCK_SIZE FS_CRYPTO_BLOCK_SIZE
#else
#define UBIFS_CIPHER_BLOCK_SIZE 0
#endif
/* /*
* How much memory is needed for a buffer where we compress a data node. * How much memory is needed for a buffer where we compress a data node.
*/ */
...@@ -645,9 +649,6 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c, ...@@ -645,9 +649,6 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
* @io_mutex: serializes write-buffer I/O * @io_mutex: serializes write-buffer I/O
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
* fields * fields
* @softlimit: soft write-buffer timeout interval
* @delta: hard and soft timeouts delta (the timer expire interval is @softlimit
* and @softlimit + @delta)
* @timer: write-buffer timer * @timer: write-buffer timer
* @no_timer: non-zero if this write-buffer does not have a timer * @no_timer: non-zero if this write-buffer does not have a timer
* @need_sync: non-zero if the timer expired and the wbuf needs sync'ing * @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
...@@ -676,8 +677,6 @@ struct ubifs_wbuf { ...@@ -676,8 +677,6 @@ struct ubifs_wbuf {
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad); int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
struct mutex io_mutex; struct mutex io_mutex;
spinlock_t lock; spinlock_t lock;
ktime_t softlimit;
unsigned long long delta;
struct hrtimer timer; struct hrtimer timer;
unsigned int no_timer:1; unsigned int no_timer:1;
unsigned int need_sync:1; unsigned int need_sync:1;
...@@ -1007,6 +1006,8 @@ struct ubifs_debug_info; ...@@ -1007,6 +1006,8 @@ struct ubifs_debug_info;
* *
* @big_lpt: flag that LPT is too big to write whole during commit * @big_lpt: flag that LPT is too big to write whole during commit
* @space_fixup: flag indicating that free space in LEBs needs to be cleaned up * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
* @double_hash: flag indicating that we can do lookups by hash
* @encrypted: flag indicating that this file system contains encrypted files
* @no_chk_data_crc: do not check CRCs when reading data nodes (except during * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
* recovery) * recovery)
* @bulk_read: enable bulk-reads * @bulk_read: enable bulk-reads
...@@ -1249,6 +1250,8 @@ struct ubifs_info { ...@@ -1249,6 +1250,8 @@ struct ubifs_info {
unsigned int big_lpt:1; unsigned int big_lpt:1;
unsigned int space_fixup:1; unsigned int space_fixup:1;
unsigned int double_hash:1;
unsigned int encrypted:1;
unsigned int no_chk_data_crc:1; unsigned int no_chk_data_crc:1;
unsigned int bulk_read:1; unsigned int bulk_read:1;
unsigned int default_compr:2; unsigned int default_compr:2;
...@@ -1515,25 +1518,29 @@ int ubifs_consolidate_log(struct ubifs_info *c); ...@@ -1515,25 +1518,29 @@ int ubifs_consolidate_log(struct ubifs_info *c);
/* journal.c */ /* journal.c */
int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
const struct qstr *nm, const struct inode *inode, const struct fscrypt_name *nm, const struct inode *inode,
int deletion, int xent); int deletion, int xent);
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
const union ubifs_key *key, const void *buf, int len); const union ubifs_key *key, const void *buf, int len);
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode); int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode); int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
const struct dentry *fst_dentry, const struct inode *fst_inode,
const struct fscrypt_name *fst_nm,
const struct inode *snd_dir, const struct inode *snd_dir,
const struct dentry *snd_dentry, int sync); const struct inode *snd_inode,
const struct fscrypt_name *snd_nm, int sync);
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
const struct dentry *old_dentry, const struct inode *old_inode,
const struct fscrypt_name *old_nm,
const struct inode *new_dir, const struct inode *new_dir,
const struct dentry *new_dentry, const struct inode *new_inode,
const struct fscrypt_name *new_nm,
const struct inode *whiteout, int sync); const struct inode *whiteout, int sync);
int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
loff_t old_size, loff_t new_size); loff_t old_size, loff_t new_size);
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
const struct inode *inode, const struct qstr *nm); const struct inode *inode, const struct fscrypt_name *nm);
int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1, int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
const struct inode *inode2); const struct inode *inode2);
...@@ -1568,7 +1575,9 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c); ...@@ -1568,7 +1575,9 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode **zn, int *n); struct ubifs_znode **zn, int *n);
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
void *node, const struct qstr *nm); void *node, const struct fscrypt_name *nm);
int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
void *node, uint32_t secondary_hash);
int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
void *node, int *lnum, int *offs); void *node, int *lnum, int *offs);
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
...@@ -1576,16 +1585,16 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, ...@@ -1576,16 +1585,16 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
int old_lnum, int old_offs, int lnum, int offs, int len); int old_lnum, int old_offs, int lnum, int offs, int len);
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
int lnum, int offs, int len, const struct qstr *nm); int lnum, int offs, int len, const struct fscrypt_name *nm);
int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key); int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
const struct qstr *nm); const struct fscrypt_name *nm);
int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key, int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
union ubifs_key *to_key); union ubifs_key *to_key);
int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum); int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c, struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
union ubifs_key *key, union ubifs_key *key,
const struct qstr *nm); const struct fscrypt_name *nm);
void ubifs_tnc_close(struct ubifs_info *c); void ubifs_tnc_close(struct ubifs_info *c);
int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level, int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
int lnum, int offs, int is_idx); int lnum, int offs, int is_idx);
...@@ -1642,6 +1651,7 @@ int ubifs_read_superblock(struct ubifs_info *c); ...@@ -1642,6 +1651,7 @@ int ubifs_read_superblock(struct ubifs_info *c);
struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c); struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
int ubifs_fixup_free_space(struct ubifs_info *c); int ubifs_fixup_free_space(struct ubifs_info *c);
int ubifs_enable_encryption(struct ubifs_info *c);
/* replay.c */ /* replay.c */
int ubifs_validate_entry(struct ubifs_info *c, int ubifs_validate_entry(struct ubifs_info *c,
...@@ -1733,16 +1743,21 @@ int ubifs_update_time(struct inode *inode, struct timespec *time, int flags); ...@@ -1733,16 +1743,21 @@ 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);
int ubifs_check_dir_empty(struct inode *dir);
/* xattr.c */ /* xattr.c */
extern const struct xattr_handler *ubifs_xattr_handlers[]; extern const struct xattr_handler *ubifs_xattr_handlers[];
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int ubifs_init_security(struct inode *dentry, struct inode *inode, int ubifs_init_security(struct inode *dentry, struct inode *inode,
const struct qstr *qstr); const struct qstr *qstr);
int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
size_t size, int flags);
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
size_t size);
/* super.c */ /* super.c */
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum); struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
...@@ -1781,6 +1796,66 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, ...@@ -1781,6 +1796,66 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
#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_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,
int block)
{
ubifs_assert(0);
return -EOPNOTSUPP;
}
static inline int ubifs_decrypt(const struct inode *inode,
struct ubifs_data_node *dn,
unsigned int *out_len, int block)
{
ubifs_assert(0);
return -EOPNOTSUPP;
}
#else
/* crypto.c */
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
unsigned int in_len, unsigned int *out_len, int block);
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;
static inline bool __ubifs_crypt_is_encrypted(struct inode *inode)
{
struct ubifs_inode *ui = ubifs_inode(inode);
return ui->flags & UBIFS_CRYPT_FL;
}
static inline bool ubifs_crypt_is_encrypted(const struct inode *inode)
{
return __ubifs_crypt_is_encrypted((struct inode *)inode);
}
/* 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, ...);
......
...@@ -97,7 +97,7 @@ static const struct file_operations empty_fops; ...@@ -97,7 +97,7 @@ static const struct file_operations empty_fops;
* of failure. * of failure.
*/ */
static int create_xattr(struct ubifs_info *c, struct inode *host, static int create_xattr(struct ubifs_info *c, struct inode *host,
const struct qstr *nm, const void *value, int size) const struct fscrypt_name *nm, const void *value, int size)
{ {
int err, names_len; int err, names_len;
struct inode *inode; struct inode *inode;
...@@ -117,7 +117,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -117,7 +117,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
* extended attributes if the name list becomes larger. This limitation * extended attributes if the name list becomes larger. This limitation
* is artificial for UBIFS, though. * is artificial for UBIFS, though.
*/ */
names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1; names_len = host_ui->xattr_names + host_ui->xattr_cnt + fname_len(nm) + 1;
if (names_len > XATTR_LIST_MAX) { if (names_len > XATTR_LIST_MAX) {
ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d", ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
host->i_ino, names_len, XATTR_LIST_MAX); host->i_ino, names_len, XATTR_LIST_MAX);
...@@ -154,9 +154,18 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -154,9 +154,18 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
mutex_lock(&host_ui->ui_mutex); mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host); host->i_ctime = ubifs_current_time(host);
host_ui->xattr_cnt += 1; host_ui->xattr_cnt += 1;
host_ui->xattr_size += CALC_DENT_SIZE(nm->len); host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
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 += fname_len(nm);
/*
* 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(fname_name(nm), 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)
...@@ -170,9 +179,10 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, ...@@ -170,9 +179,10 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
out_cancel: out_cancel:
host_ui->xattr_cnt -= 1; host_ui->xattr_cnt -= 1;
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
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 -= fname_len(nm);
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);
...@@ -269,22 +279,28 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum) ...@@ -269,22 +279,28 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
static int __ubifs_setxattr(struct inode *host, const char *name, int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
const void *value, size_t size, int flags) size_t size, int flags)
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
struct qstr nm = QSTR_INIT(name, strlen(name)); struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
union ubifs_key key; union ubifs_key key;
int err; int err;
/*
* Creating an encryption context is done unlocked since we
* operate on a new inode which is not visible to other users
* at this point.
*/
if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) != 0)
ubifs_assert(inode_is_locked(host)); ubifs_assert(inode_is_locked(host));
if (size > UBIFS_MAX_INO_DATA) if (size > UBIFS_MAX_INO_DATA)
return -ERANGE; return -ERANGE;
if (nm.len > UBIFS_MAX_NLEN) if (fname_len(&nm) > UBIFS_MAX_NLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
...@@ -329,18 +345,18 @@ static int __ubifs_setxattr(struct inode *host, const char *name, ...@@ -329,18 +345,18 @@ static int __ubifs_setxattr(struct inode *host, const char *name,
return err; return err;
} }
static ssize_t __ubifs_getxattr(struct inode *host, const char *name, ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
void *buf, size_t size) size_t size)
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
struct qstr nm = QSTR_INIT(name, strlen(name)); struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
struct ubifs_inode *ui; struct ubifs_inode *ui;
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
union ubifs_key key; union ubifs_key key;
int err; int err;
if (nm.len > UBIFS_MAX_NLEN) if (fname_len(&nm) > UBIFS_MAX_NLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
...@@ -387,6 +403,20 @@ static ssize_t __ubifs_getxattr(struct inode *host, const char *name, ...@@ -387,6 +403,20 @@ static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
return err; return err;
} }
static bool xattr_visible(const char *name)
{
/* File encryption related xattrs are for internal use only */
if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
return false;
/* Show trusted namespace only for "power" users */
if (strncmp(name, XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN))
return false;
return true;
}
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
{ {
union ubifs_key key; union ubifs_key key;
...@@ -395,7 +425,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -395,7 +425,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
struct ubifs_dent_node *xent, *pxent = NULL; struct ubifs_dent_node *xent, *pxent = NULL;
int err, len, written = 0; int err, len, written = 0;
struct qstr nm = { .name = NULL }; struct fscrypt_name nm = {0};
dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino, dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino,
dentry, size); dentry, size);
...@@ -419,15 +449,12 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -419,15 +449,12 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
break; break;
} }
nm.name = xent->name; fname_name(&nm) = xent->name;
nm.len = le16_to_cpu(xent->nlen); fname_len(&nm) = le16_to_cpu(xent->nlen);
/* Show trusted namespace only for "power" users */ if (xattr_visible(xent->name)) {
if (strncmp(xent->name, XATTR_TRUSTED_PREFIX, memcpy(buffer + written, fname_name(&nm), fname_len(&nm) + 1);
XATTR_TRUSTED_PREFIX_LEN) || written += fname_len(&nm) + 1;
capable(CAP_SYS_ADMIN)) {
memcpy(buffer + written, nm.name, nm.len + 1);
written += nm.len + 1;
} }
kfree(pxent); kfree(pxent);
...@@ -446,7 +473,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -446,7 +473,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
} }
static int remove_xattr(struct ubifs_info *c, struct inode *host, static int remove_xattr(struct ubifs_info *c, struct inode *host,
struct inode *inode, const struct qstr *nm) struct inode *inode, const struct fscrypt_name *nm)
{ {
int err; int err;
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
...@@ -463,9 +490,9 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -463,9 +490,9 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
mutex_lock(&host_ui->ui_mutex); mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host); host->i_ctime = ubifs_current_time(host);
host_ui->xattr_cnt -= 1; host_ui->xattr_cnt -= 1;
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
host_ui->xattr_names -= nm->len; host_ui->xattr_names -= fname_len(nm);
err = ubifs_jnl_delete_xattr(c, host, inode, nm); err = ubifs_jnl_delete_xattr(c, host, inode, nm);
if (err) if (err)
...@@ -477,27 +504,27 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -477,27 +504,27 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
out_cancel: out_cancel:
host_ui->xattr_cnt += 1; host_ui->xattr_cnt += 1;
host_ui->xattr_size += CALC_DENT_SIZE(nm->len); host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
host_ui->xattr_names += nm->len; host_ui->xattr_names += fname_len(nm);
mutex_unlock(&host_ui->ui_mutex); mutex_unlock(&host_ui->ui_mutex);
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
make_bad_inode(inode); make_bad_inode(inode);
return err; return err;
} }
static int __ubifs_removexattr(struct inode *host, const char *name) static int ubifs_xattr_remove(struct inode *host, const char *name)
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
struct qstr nm = QSTR_INIT(name, strlen(name)); struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
union ubifs_key key; union ubifs_key key;
int err; int err;
ubifs_assert(inode_is_locked(host)); ubifs_assert(inode_is_locked(host));
if (nm.len > UBIFS_MAX_NLEN) if (fname_len(&nm) > UBIFS_MAX_NLEN)
return -ENAMETOOLONG; return -ENAMETOOLONG;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
...@@ -548,7 +575,8 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array, ...@@ -548,7 +575,8 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
} }
strcpy(name, XATTR_SECURITY_PREFIX); strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name); strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
err = __ubifs_setxattr(inode, name, xattr->value, xattr->value_len, 0); err = ubifs_xattr_set(inode, name, xattr->value,
xattr->value_len, 0);
kfree(name); kfree(name);
if (err < 0) if (err < 0)
break; break;
...@@ -572,7 +600,7 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode, ...@@ -572,7 +600,7 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode,
return err; return err;
} }
static int ubifs_xattr_get(const struct xattr_handler *handler, static int xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode, struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size) const char *name, void *buffer, size_t size)
{ {
...@@ -580,10 +608,10 @@ static int ubifs_xattr_get(const struct xattr_handler *handler, ...@@ -580,10 +608,10 @@ static int ubifs_xattr_get(const struct xattr_handler *handler,
inode->i_ino, dentry, size); inode->i_ino, dentry, size);
name = xattr_full_name(handler, name); name = xattr_full_name(handler, name);
return __ubifs_getxattr(inode, name, buffer, size); return ubifs_xattr_get(inode, name, buffer, size);
} }
static int ubifs_xattr_set(const struct xattr_handler *handler, static int xattr_set(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode, struct dentry *dentry, struct inode *inode,
const char *name, const void *value, const char *name, const void *value,
size_t size, int flags) size_t size, int flags)
...@@ -594,27 +622,27 @@ static int ubifs_xattr_set(const struct xattr_handler *handler, ...@@ -594,27 +622,27 @@ static int ubifs_xattr_set(const struct xattr_handler *handler,
name = xattr_full_name(handler, name); name = xattr_full_name(handler, name);
if (value) if (value)
return __ubifs_setxattr(inode, name, value, size, flags); return ubifs_xattr_set(inode, name, value, size, flags);
else else
return __ubifs_removexattr(inode, name); return ubifs_xattr_remove(inode, name);
} }
static const struct xattr_handler ubifs_user_xattr_handler = { static const struct xattr_handler ubifs_user_xattr_handler = {
.prefix = XATTR_USER_PREFIX, .prefix = XATTR_USER_PREFIX,
.get = ubifs_xattr_get, .get = xattr_get,
.set = ubifs_xattr_set, .set = xattr_set,
}; };
static const struct xattr_handler ubifs_trusted_xattr_handler = { static const struct xattr_handler ubifs_trusted_xattr_handler = {
.prefix = XATTR_TRUSTED_PREFIX, .prefix = XATTR_TRUSTED_PREFIX,
.get = ubifs_xattr_get, .get = xattr_get,
.set = ubifs_xattr_set, .set = xattr_set,
}; };
static const struct xattr_handler ubifs_security_xattr_handler = { static const struct xattr_handler ubifs_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX, .prefix = XATTR_SECURITY_PREFIX,
.get = ubifs_xattr_get, .get = xattr_get,
.set = ubifs_xattr_set, .set = xattr_set,
}; };
const struct xattr_handler *ubifs_xattr_handlers[] = { const struct xattr_handler *ubifs_xattr_handlers[] = {
......
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