|
@@ -196,13 +196,13 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
|
|
|
|
|
static int dbg_check_name(const struct ubifs_info *c,
|
|
|
const struct ubifs_dent_node *dent,
|
|
|
- const struct qstr *nm)
|
|
|
+ const struct fscrypt_name *nm)
|
|
|
{
|
|
|
if (!dbg_is_chk_gen(c))
|
|
|
return 0;
|
|
|
- if (le16_to_cpu(dent->nlen) != nm->len)
|
|
|
+ if (le16_to_cpu(dent->nlen) != fname_len(nm))
|
|
|
return -EINVAL;
|
|
|
- if (memcmp(dent->name, nm->name, nm->len))
|
|
|
+ if (memcmp(dent->name, fname_name(nm), fname_len(nm)))
|
|
|
return -EINVAL;
|
|
|
return 0;
|
|
|
}
|
|
@@ -215,6 +215,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
struct inode *inode = NULL;
|
|
|
struct ubifs_dent_node *dent;
|
|
|
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);
|
|
|
|
|
@@ -233,27 +234,42 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
|
- if (dentry->d_name.len > UBIFS_MAX_NLEN)
|
|
|
- return ERR_PTR(-ENAMETOOLONG);
|
|
|
+ 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);
|
|
|
- if (!dent)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
+ if (!dent) {
|
|
|
+ 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(c, &key, dent);
|
|
|
+ } 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 == -ENOENT) {
|
|
|
dbg_gen("not found");
|
|
|
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;
|
|
|
- goto out;
|
|
|
+ goto out_dent;
|
|
|
}
|
|
|
|
|
|
inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
|
|
@@ -266,11 +282,12 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
|
|
ubifs_err(c, "dead directory entry '%pd', error %d",
|
|
|
dentry, err);
|
|
|
ubifs_ro_mode(c, err);
|
|
|
- goto out;
|
|
|
+ goto out_dent;
|
|
|
}
|
|
|
|
|
|
done:
|
|
|
kfree(dent);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
/*
|
|
|
* Note, d_splice_alias() would be required instead if we supported
|
|
|
* NFS.
|
|
@@ -278,8 +295,10 @@ done:
|
|
|
d_add(dentry, inode);
|
|
|
return NULL;
|
|
|
|
|
|
-out:
|
|
|
+out_dent:
|
|
|
kfree(dent);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
@@ -288,10 +307,11 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
|
{
|
|
|
struct inode *inode;
|
|
|
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,
|
|
|
.dirtied_ino = 1 };
|
|
|
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
|
|
@@ -305,10 +325,16 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
|
if (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);
|
|
|
if (IS_ERR(inode)) {
|
|
|
err = PTR_ERR(inode);
|
|
|
- goto out_budg;
|
|
|
+ goto out_fname;
|
|
|
}
|
|
|
|
|
|
err = ubifs_init_security(dir, inode, &dentry->d_name);
|
|
@@ -319,12 +345,13 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|
|
dir->i_size += sz_change;
|
|
|
dir_ui->ui_size = dir->i_size;
|
|
|
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)
|
|
|
goto out_cancel;
|
|
|
mutex_unlock(&dir_ui->ui_mutex);
|
|
|
|
|
|
ubifs_release_budget(c, &req);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
insert_inode_hash(inode);
|
|
|
d_instantiate(dentry, inode);
|
|
|
return 0;
|
|
@@ -336,6 +363,8 @@ out_cancel:
|
|
|
out_inode:
|
|
|
make_bad_inode(inode);
|
|
|
iput(inode);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
out_budg:
|
|
|
ubifs_release_budget(c, &req);
|
|
|
ubifs_err(c, "cannot create regular file, error %d", err);
|
|
@@ -351,6 +380,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
|
|
struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
|
|
|
struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
|
|
|
int err, instantiated = 0;
|
|
|
+ struct fscrypt_name nm;
|
|
|
|
|
|
/*
|
|
|
* Budget request settings: new dirty inode, new direntry,
|
|
@@ -360,13 +390,30 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
|
|
dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
|
|
|
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)
|
|
|
return err;
|
|
|
|
|
|
+ err = ubifs_budget_space(c, &req);
|
|
|
+ if (err) {
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
err = ubifs_budget_space(c, &ino_req);
|
|
|
if (err) {
|
|
|
ubifs_release_budget(c, &req);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -402,7 +449,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
|
|
mutex_unlock(&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)
|
|
|
goto out_cancel;
|
|
|
mutex_unlock(&dir_ui->ui_mutex);
|
|
@@ -421,6 +468,7 @@ out_budg:
|
|
|
ubifs_release_budget(c, &req);
|
|
|
if (!instantiated)
|
|
|
ubifs_release_budget(c, &ino_req);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
ubifs_err(c, "cannot create temporary file, error %d", err);
|
|
|
return err;
|
|
|
}
|
|
@@ -480,12 +528,14 @@ static unsigned int vfs_dent_type(uint8_t type)
|
|
|
*/
|
|
|
static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
|
|
{
|
|
|
- int err = 0;
|
|
|
- struct qstr nm;
|
|
|
+ int fstr_real_len, err = 0;
|
|
|
+ struct fscrypt_name nm;
|
|
|
+ struct fscrypt_str fstr = {0};
|
|
|
union ubifs_key key;
|
|
|
struct ubifs_dent_node *dent;
|
|
|
struct inode *dir = file_inode(file);
|
|
|
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);
|
|
|
|
|
@@ -496,6 +546,18 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
|
|
*/
|
|
|
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) {
|
|
|
/*
|
|
|
* The file was seek'ed, which means that @file->private_data
|
|
@@ -517,12 +579,15 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
|
|
/* File positions 0 and 1 correspond to "." and ".." */
|
|
|
if (ctx->pos < 2) {
|
|
|
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;
|
|
|
+ }
|
|
|
|
|
|
/* Find the first entry in TNC and save it */
|
|
|
lowest_dent_key(c, &key, dir->i_ino);
|
|
|
- nm.name = NULL;
|
|
|
+ fname_len(&nm) = 0;
|
|
|
dent = ubifs_tnc_next_ent(c, &key, &nm);
|
|
|
if (IS_ERR(dent)) {
|
|
|
err = PTR_ERR(dent);
|
|
@@ -540,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.
|
|
|
*/
|
|
|
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);
|
|
|
if (IS_ERR(dent)) {
|
|
|
err = PTR_ERR(dent);
|
|
@@ -557,15 +622,30 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
|
|
ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
|
|
|
ubifs_inode(dir)->creat_sqnum);
|
|
|
|
|
|
- nm.len = le16_to_cpu(dent->nlen);
|
|
|
- if (!dir_emit(ctx, dent->name, nm.len,
|
|
|
+ fname_len(&nm) = le16_to_cpu(dent->nlen);
|
|
|
+ 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), 0, &nm.disk_name, &fstr);
|
|
|
+ if (err < 0)
|
|
|
+ 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),
|
|
|
- vfs_dent_type(dent->type)))
|
|
|
+ vfs_dent_type(dent->type))) {
|
|
|
+ if (encrypted)
|
|
|
+ fscrypt_fname_free_buffer(&fstr);
|
|
|
return 0;
|
|
|
+ }
|
|
|
|
|
|
/* Switch to the next entry */
|
|
|
key_read(c, &dent->key, &key);
|
|
|
- nm.name = dent->name;
|
|
|
dent = ubifs_tnc_next_ent(c, &key, &nm);
|
|
|
if (IS_ERR(dent)) {
|
|
|
err = PTR_ERR(dent);
|
|
@@ -582,6 +662,9 @@ out:
|
|
|
kfree(file->private_data);
|
|
|
file->private_data = NULL;
|
|
|
|
|
|
+ if (encrypted)
|
|
|
+ fscrypt_fname_free_buffer(&fstr);
|
|
|
+
|
|
|
if (err != -ENOENT)
|
|
|
ubifs_err(c, "cannot find next direntry, error %d", err);
|
|
|
else
|
|
@@ -642,6 +725,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
|
|
|
struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2,
|
|
|
.dirtied_ino_d = ALIGN(ui->data_len, 8) };
|
|
|
+ struct fscrypt_name nm;
|
|
|
|
|
|
/*
|
|
|
* Budget request settings: new direntry, changing the target inode,
|
|
@@ -654,17 +738,29 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
ubifs_assert(inode_is_locked(dir));
|
|
|
ubifs_assert(inode_is_locked(inode));
|
|
|
|
|
|
- if (ubifs_crypt_is_encrypted(dir) &&
|
|
|
- !fscrypt_has_permitted_context(dir, inode))
|
|
|
- return -EPERM;
|
|
|
+ if (ubifs_crypt_is_encrypted(dir)) {
|
|
|
+ if (!fscrypt_has_permitted_context(dir, inode))
|
|
|
+ return -EPERM;
|
|
|
|
|
|
- err = dbg_check_synced_i_size(c, inode);
|
|
|
+ err = fscrypt_get_encryption_info(inode);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ if (!fscrypt_has_encryption_key(inode))
|
|
|
+ return -EPERM;
|
|
|
+ }
|
|
|
+
|
|
|
+ err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
|
+ err = dbg_check_synced_i_size(c, inode);
|
|
|
+ if (err)
|
|
|
+ goto out_fname;
|
|
|
+
|
|
|
err = ubifs_budget_space(c, &req);
|
|
|
if (err)
|
|
|
- return err;
|
|
|
+ goto out_fname;
|
|
|
|
|
|
lock_2_inodes(dir, inode);
|
|
|
inc_nlink(inode);
|
|
@@ -673,13 +769,14 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
dir->i_size += sz_change;
|
|
|
dir_ui->ui_size = dir->i_size;
|
|
|
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)
|
|
|
goto out_cancel;
|
|
|
unlock_2_inodes(dir, inode);
|
|
|
|
|
|
ubifs_release_budget(c, &req);
|
|
|
d_instantiate(dentry, inode);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return 0;
|
|
|
|
|
|
out_cancel:
|
|
@@ -689,6 +786,8 @@ out_cancel:
|
|
|
unlock_2_inodes(dir, inode);
|
|
|
ubifs_release_budget(c, &req);
|
|
|
iput(inode);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -697,10 +796,10 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
|
|
struct inode *inode = d_inode(dentry);
|
|
|
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
|
|
- int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
|
|
|
- int err, budgeted = 1;
|
|
|
+ int err, sz_change, budgeted = 1;
|
|
|
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
|
|
|
unsigned int saved_nlink = inode->i_nlink;
|
|
|
+ struct fscrypt_name nm;
|
|
|
|
|
|
/*
|
|
|
* Budget request settings: deletion direntry, deletion inode (+1 for
|
|
@@ -712,16 +811,29 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu",
|
|
|
dentry, inode->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(inode));
|
|
|
err = dbg_check_synced_i_size(c, inode);
|
|
|
if (err)
|
|
|
- return err;
|
|
|
+ goto out_fname;
|
|
|
|
|
|
err = ubifs_budget_space(c, &req);
|
|
|
if (err) {
|
|
|
if (err != -ENOSPC)
|
|
|
- return err;
|
|
|
+ goto out_fname;
|
|
|
budgeted = 0;
|
|
|
}
|
|
|
|
|
@@ -731,7 +843,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
dir->i_size -= sz_change;
|
|
|
dir_ui->ui_size = dir->i_size;
|
|
|
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)
|
|
|
goto out_cancel;
|
|
|
unlock_2_inodes(dir, inode);
|
|
@@ -743,6 +855,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
|
|
c->bi.nospace = c->bi.nospace_rp = 0;
|
|
|
smp_wmb();
|
|
|
}
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return 0;
|
|
|
|
|
|
out_cancel:
|
|
@@ -752,6 +865,8 @@ out_cancel:
|
|
|
unlock_2_inodes(dir, inode);
|
|
|
if (budgeted)
|
|
|
ubifs_release_budget(c, &req);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -766,7 +881,7 @@ out_cancel:
|
|
|
int ubifs_check_dir_empty(struct inode *dir)
|
|
|
{
|
|
|
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
|
|
- struct qstr nm = { .name = NULL };
|
|
|
+ struct fscrypt_name nm = { 0 };
|
|
|
struct ubifs_dent_node *dent;
|
|
|
union ubifs_key key;
|
|
|
int err;
|
|
@@ -788,10 +903,10 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
{
|
|
|
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
|
|
struct inode *inode = d_inode(dentry);
|
|
|
- int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
|
|
|
- int err, budgeted = 1;
|
|
|
+ int err, sz_change, budgeted = 1;
|
|
|
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
|
|
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
|
|
|
+ struct fscrypt_name nm;
|
|
|
|
|
|
/*
|
|
|
* Budget request settings: deletion direntry, deletion inode and
|
|
@@ -807,10 +922,22 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
if (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);
|
|
|
if (err) {
|
|
|
if (err != -ENOSPC)
|
|
|
- return err;
|
|
|
+ goto out_fname;
|
|
|
budgeted = 0;
|
|
|
}
|
|
|
|
|
@@ -821,7 +948,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
dir->i_size -= sz_change;
|
|
|
dir_ui->ui_size = dir->i_size;
|
|
|
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)
|
|
|
goto out_cancel;
|
|
|
unlock_2_inodes(dir, inode);
|
|
@@ -833,6 +960,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
|
|
c->bi.nospace = c->bi.nospace_rp = 0;
|
|
|
smp_wmb();
|
|
|
}
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return 0;
|
|
|
|
|
|
out_cancel:
|
|
@@ -843,6 +971,8 @@ out_cancel:
|
|
|
unlock_2_inodes(dir, inode);
|
|
|
if (budgeted)
|
|
|
ubifs_release_budget(c, &req);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -851,8 +981,9 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
struct inode *inode;
|
|
|
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
|
|
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 fscrypt_name nm;
|
|
|
|
|
|
/*
|
|
|
* Budget request settings: new inode, new direntry and changing parent
|
|
@@ -866,10 +997,27 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
if (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);
|
|
|
if (IS_ERR(inode)) {
|
|
|
err = PTR_ERR(inode);
|
|
|
- goto out_budg;
|
|
|
+ goto out_fname;
|
|
|
}
|
|
|
|
|
|
err = ubifs_init_security(dir, inode, &dentry->d_name);
|
|
@@ -883,7 +1031,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
dir->i_size += sz_change;
|
|
|
dir_ui->ui_size = dir->i_size;
|
|
|
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) {
|
|
|
ubifs_err(c, "cannot create directory, error %d", err);
|
|
|
goto out_cancel;
|
|
@@ -892,6 +1040,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|
|
|
|
|
ubifs_release_budget(c, &req);
|
|
|
d_instantiate(dentry, inode);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return 0;
|
|
|
|
|
|
out_cancel:
|
|
@@ -902,6 +1051,8 @@ out_cancel:
|
|
|
out_inode:
|
|
|
make_bad_inode(inode);
|
|
|
iput(inode);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
out_budg:
|
|
|
ubifs_release_budget(c, &req);
|
|
|
return err;
|
|
@@ -915,11 +1066,12 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
|
|
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
|
|
union ubifs_dev_desc *dev = NULL;
|
|
|
- int sz_change = CALC_DENT_SIZE(dentry->d_name.len);
|
|
|
+ int sz_change;
|
|
|
int err, devlen = 0;
|
|
|
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
|
|
|
.new_ino_d = ALIGN(devlen, 8),
|
|
|
.dirtied_ino = 1 };
|
|
|
+ struct fscrypt_name nm;
|
|
|
|
|
|
/*
|
|
|
* Budget request settings: new inode, new direntry and changing parent
|
|
@@ -941,11 +1093,28 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
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);
|
|
|
if (IS_ERR(inode)) {
|
|
|
kfree(dev);
|
|
|
err = PTR_ERR(inode);
|
|
|
- goto out_budg;
|
|
|
+ goto out_fname;
|
|
|
}
|
|
|
|
|
|
init_special_inode(inode, inode->i_mode, rdev);
|
|
@@ -962,7 +1131,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
dir->i_size += sz_change;
|
|
|
dir_ui->ui_size = dir->i_size;
|
|
|
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)
|
|
|
goto out_cancel;
|
|
|
mutex_unlock(&dir_ui->ui_mutex);
|
|
@@ -970,6 +1139,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
|
|
ubifs_release_budget(c, &req);
|
|
|
insert_inode_hash(inode);
|
|
|
d_instantiate(dentry, inode);
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
return 0;
|
|
|
|
|
|
out_cancel:
|
|
@@ -979,6 +1149,8 @@ out_cancel:
|
|
|
out_inode:
|
|
|
make_bad_inode(inode);
|
|
|
iput(inode);
|
|
|
+out_fname:
|
|
|
+ fscrypt_free_filename(&nm);
|
|
|
out_budg:
|
|
|
ubifs_release_budget(c, &req);
|
|
|
return err;
|
|
@@ -1123,15 +1295,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
struct ubifs_inode *whiteout_ui = NULL;
|
|
|
int err, release, sync = 0, move = (new_dir != old_dir);
|
|
|
int is_dir = S_ISDIR(old_inode->i_mode);
|
|
|
- int unlink = !!new_inode;
|
|
|
- int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len);
|
|
|
- int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len);
|
|
|
+ int unlink = !!new_inode, new_sz, old_sz;
|
|
|
struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
|
|
|
.dirtied_ino = 3 };
|
|
|
struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
|
|
|
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
|
|
|
struct timespec time;
|
|
|
unsigned int uninitialized_var(saved_nlink);
|
|
|
+ struct fscrypt_name old_nm, new_nm;
|
|
|
|
|
|
if (flags & ~RENAME_NOREPLACE)
|
|
|
return -EINVAL;
|
|
@@ -1164,11 +1335,29 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
- err = ubifs_budget_space(c, &req);
|
|
|
+ err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm);
|
|
|
if (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);
|
|
|
if (err) {
|
|
|
+ fscrypt_free_filename(&old_nm);
|
|
|
+ fscrypt_free_filename(&new_nm);
|
|
|
ubifs_release_budget(c, &req);
|
|
|
return err;
|
|
|
}
|
|
@@ -1290,8 +1479,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
iput(whiteout);
|
|
|
}
|
|
|
|
|
|
- err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, whiteout,
|
|
|
- sync);
|
|
|
+ err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir,
|
|
|
+ new_inode, &new_nm, whiteout, sync);
|
|
|
if (err)
|
|
|
goto out_cancel;
|
|
|
|
|
@@ -1307,6 +1496,9 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
ubifs_release_budget(c, &ino_req);
|
|
|
if (IS_SYNC(old_inode))
|
|
|
err = old_inode->i_sb->s_op->write_inode(old_inode, NULL);
|
|
|
+
|
|
|
+ fscrypt_free_filename(&old_nm);
|
|
|
+ fscrypt_free_filename(&new_nm);
|
|
|
return err;
|
|
|
|
|
|
out_cancel:
|
|
@@ -1335,6 +1527,8 @@ out_cancel:
|
|
|
unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
|
|
|
ubifs_release_budget(c, &ino_req);
|
|
|
ubifs_release_budget(c, &req);
|
|
|
+ fscrypt_free_filename(&old_nm);
|
|
|
+ fscrypt_free_filename(&new_nm);
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -1349,6 +1543,7 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
struct inode *snd_inode = d_inode(new_dentry);
|
|
|
struct timespec time;
|
|
|
int err;
|
|
|
+ struct fscrypt_name fst_nm, snd_nm;
|
|
|
|
|
|
ubifs_assert(fst_inode && snd_inode);
|
|
|
|
|
@@ -1359,6 +1554,16 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
!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);
|
|
|
|
|
|
time = ubifs_current_time(old_dir);
|
|
@@ -1378,12 +1583,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,
|
|
|
- sync);
|
|
|
+ err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir,
|
|
|
+ snd_inode, &snd_nm, sync);
|
|
|
|
|
|
unlock_4_inodes(old_dir, new_dir, NULL, NULL);
|
|
|
ubifs_release_budget(c, &req);
|
|
|
|
|
|
+ fscrypt_free_filename(&fst_nm);
|
|
|
+ fscrypt_free_filename(&snd_nm);
|
|
|
return err;
|
|
|
}
|
|
|
|