]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/ubifs/file.c
Merge branch 'parisc-4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[linux.git] / fs / ubifs / file.c
index b4fbeefba246adf8eec82f45cf0692ec9f22e660..b0d783774c963c97f32df7649feeb8fb7e4e3e4f 100644 (file)
@@ -78,6 +78,13 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
                goto dump;
 
        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;
        err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
                               le16_to_cpu(dn->compr_type));
@@ -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;
                        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,
                                               le16_to_cpu(dn->compr_type));
                        if (err || len != out_len)
@@ -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)
 {
        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);
        if (err)
@@ -1605,6 +1628,88 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
        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 = {
        .readpage       = ubifs_readpage,
        .writepage      = ubifs_writepage,
@@ -1628,8 +1733,7 @@ const struct inode_operations ubifs_file_inode_operations = {
 };
 
 const struct inode_operations ubifs_symlink_inode_operations = {
-       .readlink    = generic_readlink,
-       .get_link    = simple_get_link,
+       .get_link    = ubifs_get_link,
        .setattr     = ubifs_setattr,
        .getattr     = ubifs_getattr,
        .listxattr   = ubifs_listxattr,
@@ -1647,6 +1751,7 @@ const struct file_operations ubifs_file_operations = {
        .unlocked_ioctl = ubifs_ioctl,
        .splice_read    = generic_file_splice_read,
        .splice_write   = iter_file_splice_write,
+       .open           = ubifs_file_open,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = ubifs_compat_ioctl,
 #endif