// SPDX-License-Identifier: GPL-2.0-or-later/* * eCryptfs: Linux filesystem encryption layer * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * Michael C. Thompsion <mcthomps@us.ibm.com> */ #include <linux/file.h>#include <linux/vmalloc.h>#include <linux/pagemap.h>#include <linux/dcache.h>#include <linux/namei.h>#include <linux/mount.h>#include <linux/fs_stack.h>#include <linux/slab.h>#include <linux/xattr.h>#include <linux/posix_acl.h>#include <linux/posix_acl_xattr.h>#include <linux/fileattr.h>#include <linux/unaligned.h>#include "ecryptfs_kernel.h" static struct dentry *ecryptfs_start_creating_dentry(struct dentry *dentry){ struct dentry *parent = dget_parent(dentry); struct dentry *ret; ret = start_creating_dentry(ecryptfs_dentry_to_lower(parent), ecryptfs_dentry_to_lower(dentry)); dput(parent); return ret;} static struct dentry *ecryptfs_start_removing_dentry(struct dentry *dentry){ struct dentry *parent = dget_parent(dentry); struct dentry *ret; ret = start_removing_dentry(ecryptfs_dentry_to_lower(parent), ecryptfs_dentry_to_lower(dentry)); dput(parent); return ret;} static int ecryptfs_inode_test(struct inode *inode, void *lower_inode){ return ecryptfs_inode_to_lower(inode) == lower_inode;} static int ecryptfs_inode_set(struct inode *inode, void *opaque){ struct inode *lower_inode = opaque; ecryptfs_set_inode_lower(inode, lower_inode); fsstack_copy_attr_all(inode, lower_inode); /* i_size will be overwritten for encrypted regular files */ fsstack_copy_inode_size(inode, lower_inode); inode->i_ino = lower_inode->i_ino; inode->i_mapping->a_ops = &ecryptfs_aops; if (S_ISLNK(inode->i_mode)) inode->i_op = &ecryptfs_symlink_iops; else if (S_ISDIR(inode->i_mode)) inode->i_op = &ecryptfs_dir_iops; else inode->i_op = &ecryptfs_main_iops; if (S_ISDIR(inode->i_mode)) inode->i_fop = &ecryptfs_dir_fops; else if (special_file(inode->i_mode)) init_special_inode(inode, inode->i_mode, inode->i_rdev); else inode->i_fop = &ecryptfs_main_fops; return 0;} static struct inode *__ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb){ struct inode *inode; if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) return ERR_PTR(-EXDEV); /* Reject dealing with casefold directories. */ if (IS_CASEFOLDED(lower_inode)) { pr_err_ratelimited("%s: Can't handle casefolded directory.\n", __func__); return ERR_PTR(-EREMOTE); } if (!igrab(lower_inode)) return ERR_PTR(-ESTALE); inode = iget5_locked(sb, (unsigned long)lower_inode, ecryptfs_inode_test, ecryptfs_inode_set, lower_inode); if (!inode) { iput(lower_inode); return ERR_PTR(-EACCES); } if (!(inode_state_read_once(inode) & I_NEW)) iput(lower_inode); return inode;} struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb){ struct inode *inode = __ecryptfs_get_inode(lower_inode, sb); if (!IS_ERR(inode) && (inode_state_read_once(inode) & I_NEW)) unlock_new_inode(inode); return inode;} /** * ecryptfs_interpose * @lower_dentry: Existing dentry in the lower filesystem * @dentry: ecryptfs' dentry * @sb: ecryptfs's super_block * * Interposes upper and lower dentries. * * Returns zero on success; non-zero otherwise */static int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, struct super_block *sb){ struct inode *inode = ecryptfs_get_inode(d_inode(lower_dentry), sb); if (IS_ERR(inode)) return PTR_ERR(inode); d_instantiate(dentry, inode); return 0;} static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, struct inode *inode){ struct dentry *lower_dentry; struct inode *lower_dir; int rc; lower_dentry = ecryptfs_start_removing_dentry(dentry); if (IS_ERR(lower_dentry)) return PTR_ERR(lower_dentry); lower_dir = lower_dentry->d_parent->d_inode; rc = vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL); if (rc) { printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); goto out_unlock; } fsstack_copy_attr_times(dir, lower_dir); set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); inode_set_ctime_to_ts(inode, inode_get_ctime(dir));out_unlock: end_removing(lower_dentry); if (!rc) d_drop(dentry); return rc;} /** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs * @ecryptfs_dentry: New file's dentry in ecryptfs * @mode: The mode of the new file * * Creates the underlying file and the eCryptfs inode which will link to * it. It will also update the eCryptfs directory inode to mimic the * stat of the lower directory inode. * * Returns the new eCryptfs inode on success; an ERR_PTR on error condition */static struct inode *ecryptfs_do_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, umode_t mode){ int rc; struct dentry *lower_dentry; struct inode *lower_dir; struct inode *inode; lower_dentry = ecryptfs_start_creating_dentry(ecryptfs_dentry); if (IS_ERR(lower_dentry)) return ERR_CAST(lower_dentry); lower_dir = lower_dentry->d_parent->d_inode; rc = vfs_create(&nop_mnt_idmap, lower_dentry, mode, NULL); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); inode = ERR_PTR(rc); goto out_lock; } inode = __ecryptfs_get_inode(d_inode(lower_dentry), directory_inode->i_sb); if (IS_ERR(inode)) { vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL); goto out_lock; } fsstack_copy_attr_times(directory_inode, lower_dir); fsstack_copy_inode_size(directory_inode, lower_dir);out_lock: end_creating(lower_dentry); return inode;} /* * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, struct inode *ecryptfs_inode){ struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc = 0; if (S_ISDIR(ecryptfs_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_inode); if (rc) { ecryptfs_printk(KERN_ERR, "Error creating new file " "context; rc = [%d]\n", rc); goto out; } rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%pd]; rc = [%d]\n", __func__, ecryptfs_dentry, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); ecryptfs_put_lower_file(ecryptfs_inode);out: return rc;} /* * ecryptfs_create * @mode: The mode of the new file. * * Creates a new file. * * Returns zero on success; non-zero on error condition */static intecryptfs_create(struct mnt_idmap *idmap, struct inode *directory_inode, struct dentry *ecryptfs_dentry, umode_t mode){ struct inode *ecryptfs_inode; int rc; ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); if (IS_ERR(ecryptfs_inode)) { ecryptfs_printk(KERN_WARNING, "Failed to create file in" "lower filesystem\n"); rc = PTR_ERR(ecryptfs_inode); goto out; } /* At this point, a file exists on "disk"; we need to make sure * that this on disk file is prepared to be an ecryptfs file */ rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, ecryptfs_inode); iget_failed(ecryptfs_inode); goto out; } d_instantiate_new(ecryptfs_dentry, ecryptfs_inode);out: return rc;} static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode){ struct ecryptfs_crypt_stat *crypt_stat; int rc; rc = ecryptfs_get_lower_file(dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%pd]; rc = [%d]\n", __func__, dentry, rc); return rc; } crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; /* TODO: lock for crypt_stat comparison */ if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); rc = ecryptfs_read_and_validate_header_region(inode); ecryptfs_put_lower_file(inode); if (rc) { rc = ecryptfs_read_and_validate_xattr_region(dentry, inode); if (!rc) crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } /* Must return 0 to allow non-eCryptfs files to be looked up, too */ return 0;} /* * ecryptfs_lookup_interpose - Dentry interposition for a lookup */static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry, struct dentry *lower_dentry){ struct dentry *lower_parent = ecryptfs_dentry_to_lower(dentry->d_parent); struct inode *inode, *lower_inode; int rc = 0; fsstack_copy_attr_atime(d_inode(dentry->d_parent), d_inode(lower_parent)); BUG_ON(!d_count(lower_dentry)); ecryptfs_set_dentry_lower(dentry, lower_dentry); /* * negative dentry can go positive under us here - its parent is not * locked. That's OK and that could happen just as we return from * ecryptfs_lookup() anyway. Just need to be careful and fetch * ->d_inode only once - it's not stable here. */ lower_inode = READ_ONCE(lower_dentry->d_inode); if (!lower_inode) /* We want to add because we couldn't find in lower */ return d_splice_alias(NULL, dentry); inode = __ecryptfs_get_inode(lower_inode, dentry->d_sb); if (IS_ERR(inode)) { printk(KERN_ERR "%s: Error interposing; rc = [%ld]\n", __func__, PTR_ERR(inode)); return ERR_CAST(inode); } if (S_ISREG(inode->i_mode)) { rc = ecryptfs_i_size_read(dentry, inode); if (rc) { make_bad_inode(inode); return ERR_PTR(rc); } } if (inode_state_read_once(inode) & I_NEW) unlock_new_inode(inode); return d_splice_alias(inode, dentry);} /** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @flags: lookup flags * * Find a file on disk. If the file does not exist, then we'll add it to the * dentry cache and continue on to read it from the disk. */static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, struct dentry *ecryptfs_dentry, unsigned int flags){ char *encrypted_and_encoded_name = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *lower_dir_dentry, *lower_dentry; struct qstr qname = QSTR_INIT(ecryptfs_dentry->d_name.name, ecryptfs_dentry->d_name.len); struct dentry *res; int rc = 0; lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { size_t len = qname.len; rc = ecryptfs_encrypt_and_encode_filename( &encrypted_and_encoded_name, &len, mount_crypt_stat, qname.name, len); if (rc) { printk(KERN_ERR "%s: Error attempting to encrypt and encode " "filename; rc = [%d]\n", __func__, rc); return ERR_PTR(rc); } qname.name = encrypted_and_encoded_name; qname.len = len; } lower_dentry = lookup_noperm_unlocked(&qname, lower_dir_dentry); if (IS_ERR(lower_dentry)) { ecryptfs_printk(KERN_DEBUG, "%s: lookup_noperm() returned " "[%ld] on lower_dentry = [%s]\n", __func__, PTR_ERR(lower_dentry), qname.name); res = ERR_CAST(lower_dentry); } else { res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry); } kfree(encrypted_and_encoded_name); return res;} static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry){ struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct inode *lower_dir; u64 file_size_save; int rc; file_size_save = i_size_read(d_inode(old_dentry)); lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_start_creating_dentry(new_dentry); if (IS_ERR(lower_new_dentry)) return PTR_ERR(lower_new_dentry); lower_dir = lower_new_dentry->d_parent->d_inode; rc = vfs_link(lower_old_dentry, &nop_mnt_idmap, lower_dir, lower_new_dentry, NULL); if (rc || d_really_is_negative(lower_new_dentry)) goto out_lock; rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_dir); fsstack_copy_inode_size(dir, lower_dir); set_nlink(d_inode(old_dentry), ecryptfs_inode_to_lower(d_inode(old_dentry))->i_nlink); i_size_write(d_inode(new_dentry), file_size_save);out_lock: end_creating(lower_new_dentry); return rc;} static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry){ return ecryptfs_do_unlink(dir, dentry, d_inode(dentry));} static int ecryptfs_symlink(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *symname){ int rc; struct dentry *lower_dentry; struct inode *lower_dir; char *encoded_symname; size_t encoded_symlen; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; lower_dentry = ecryptfs_start_creating_dentry(dentry); if (IS_ERR(lower_dentry)) return PTR_ERR(lower_dentry); lower_dir = lower_dentry->d_parent->d_inode; mount_crypt_stat = &ecryptfs_superblock_to_private( dir->i_sb)->mount_crypt_stat; rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname, &encoded_symlen, mount_crypt_stat, symname, strlen(symname)); if (rc) goto out_lock; rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry, encoded_symname, NULL); kfree(encoded_symname); if (rc || d_really_is_negative(lower_dentry)) goto out_lock; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_dir); fsstack_copy_inode_size(dir, lower_dir);out_lock: end_creating(lower_dentry);Lines 1–500 of 1183. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * eCryptfs: Linux filesystem encryption layer * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * Michael C. Thompsion <mcthomps@us.ibm.com> */ #include <linux/file.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> #include <linux/dcache.h> #include <linux/namei.h> #include <linux/mount.h> #include <linux/fs_stack.h> #include <linux/slab.h> #include <linux/xattr.h> #include <linux/posix_acl.h> #include <linux/posix_acl_xattr.h> #include <linux/fileattr.h> #include <linux/unaligned.h> #include "ecryptfs_kernel.h" static struct dentry *ecryptfs_start_creating_dentry(struct dentry *dentry) { struct dentry *parent = dget_parent(dentry); struct dentry *ret; ret = start_creating_dentry(ecryptfs_dentry_to_lower(parent), ecryptfs_dentry_to_lower(dentry)); dput(parent); return ret; } static struct dentry *ecryptfs_start_removing_dentry(struct dentry *dentry) { struct dentry *parent = dget_parent(dentry); struct dentry *ret; ret = start_removing_dentry(ecryptfs_dentry_to_lower(parent), ecryptfs_dentry_to_lower(dentry)); dput(parent); return ret; } static int ecryptfs_inode_test(struct inode *inode, void *lower_inode) { return ecryptfs_inode_to_lower(inode) == lower_inode; } static int ecryptfs_inode_set(struct inode *inode, void *opaque) { struct inode *lower_inode = opaque; ecryptfs_set_inode_lower(inode, lower_inode); fsstack_copy_attr_all(inode, lower_inode); /* i_size will be overwritten for encrypted regular files */ fsstack_copy_inode_size(inode, lower_inode); inode->i_ino = lower_inode->i_ino; inode->i_mapping->a_ops = &ecryptfs_aops; if (S_ISLNK(inode->i_mode)) inode->i_op = &ecryptfs_symlink_iops; else if (S_ISDIR(inode->i_mode)) inode->i_op = &ecryptfs_dir_iops; else inode->i_op = &ecryptfs_main_iops; if (S_ISDIR(inode->i_mode)) inode->i_fop = &ecryptfs_dir_fops; else if (special_file(inode->i_mode)) init_special_inode(inode, inode->i_mode, inode->i_rdev); else inode->i_fop = &ecryptfs_main_fops; return 0; } static struct inode *__ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb) { struct inode *inode; if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) return ERR_PTR(-EXDEV); /* Reject dealing with casefold directories. */ if (IS_CASEFOLDED(lower_inode)) { pr_err_ratelimited("%s: Can't handle casefolded directory.\n", __func__); return ERR_PTR(-EREMOTE); } if (!igrab(lower_inode)) return ERR_PTR(-ESTALE); inode = iget5_locked(sb, (unsigned long)lower_inode, ecryptfs_inode_test, ecryptfs_inode_set, lower_inode); if (!inode) { iput(lower_inode); return ERR_PTR(-EACCES); } if (!(inode_state_read_once(inode) & I_NEW)) iput(lower_inode); return inode; } struct inode *ecryptfs_get_inode(struct inode *lower_inode, struct super_block *sb) { struct inode *inode = __ecryptfs_get_inode(lower_inode, sb); if (!IS_ERR(inode) && (inode_state_read_once(inode) & I_NEW)) unlock_new_inode(inode); return inode; } /** * ecryptfs_interpose * @lower_dentry: Existing dentry in the lower filesystem * @dentry: ecryptfs' dentry * @sb: ecryptfs's super_block * * Interposes upper and lower dentries. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, struct super_block *sb) { struct inode *inode = ecryptfs_get_inode(d_inode(lower_dentry), sb); if (IS_ERR(inode)) return PTR_ERR(inode); d_instantiate(dentry, inode); return 0; } static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, struct inode *inode) { struct dentry *lower_dentry; struct inode *lower_dir; int rc; lower_dentry = ecryptfs_start_removing_dentry(dentry); if (IS_ERR(lower_dentry)) return PTR_ERR(lower_dentry); lower_dir = lower_dentry->d_parent->d_inode; rc = vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL); if (rc) { printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); goto out_unlock; } fsstack_copy_attr_times(dir, lower_dir); set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); out_unlock: end_removing(lower_dentry); if (!rc) d_drop(dentry); return rc; } /** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs * @ecryptfs_dentry: New file's dentry in ecryptfs * @mode: The mode of the new file * * Creates the underlying file and the eCryptfs inode which will link to * it. It will also update the eCryptfs directory inode to mimic the * stat of the lower directory inode. * * Returns the new eCryptfs inode on success; an ERR_PTR on error condition */ static struct inode * ecryptfs_do_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, umode_t mode) { int rc; struct dentry *lower_dentry; struct inode *lower_dir; struct inode *inode; lower_dentry = ecryptfs_start_creating_dentry(ecryptfs_dentry); if (IS_ERR(lower_dentry)) return ERR_CAST(lower_dentry); lower_dir = lower_dentry->d_parent->d_inode; rc = vfs_create(&nop_mnt_idmap, lower_dentry, mode, NULL); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); inode = ERR_PTR(rc); goto out_lock; } inode = __ecryptfs_get_inode(d_inode(lower_dentry), directory_inode->i_sb); if (IS_ERR(inode)) { vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL); goto out_lock; } fsstack_copy_attr_times(directory_inode, lower_dir); fsstack_copy_inode_size(directory_inode, lower_dir); out_lock: end_creating(lower_dentry); return inode; } /* * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc = 0; if (S_ISDIR(ecryptfs_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_inode); if (rc) { ecryptfs_printk(KERN_ERR, "Error creating new file " "context; rc = [%d]\n", rc); goto out; } rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%pd]; rc = [%d]\n", __func__, ecryptfs_dentry, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); ecryptfs_put_lower_file(ecryptfs_inode); out: return rc; } /* * ecryptfs_create * @mode: The mode of the new file. * * Creates a new file. * * Returns zero on success; non-zero on error condition */ static int ecryptfs_create(struct mnt_idmap *idmap, struct inode *directory_inode, struct dentry *ecryptfs_dentry, umode_t mode) { struct inode *ecryptfs_inode; int rc; ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); if (IS_ERR(ecryptfs_inode)) { ecryptfs_printk(KERN_WARNING, "Failed to create file in" "lower filesystem\n"); rc = PTR_ERR(ecryptfs_inode); goto out; } /* At this point, a file exists on "disk"; we need to make sure * that this on disk file is prepared to be an ecryptfs file */ rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, ecryptfs_inode); iget_failed(ecryptfs_inode); goto out; } d_instantiate_new(ecryptfs_dentry, ecryptfs_inode); out: return rc; } static int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) { struct ecryptfs_crypt_stat *crypt_stat; int rc; rc = ecryptfs_get_lower_file(dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%pd]; rc = [%d]\n", __func__, dentry, rc); return rc; } crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; /* TODO: lock for crypt_stat comparison */ if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); rc = ecryptfs_read_and_validate_header_region(inode); ecryptfs_put_lower_file(inode); if (rc) { rc = ecryptfs_read_and_validate_xattr_region(dentry, inode); if (!rc) crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } /* Must return 0 to allow non-eCryptfs files to be looked up, too */ return 0; } /* * ecryptfs_lookup_interpose - Dentry interposition for a lookup */ static struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry, struct dentry *lower_dentry) { struct dentry *lower_parent = ecryptfs_dentry_to_lower(dentry->d_parent); struct inode *inode, *lower_inode; int rc = 0; fsstack_copy_attr_atime(d_inode(dentry->d_parent), d_inode(lower_parent)); BUG_ON(!d_count(lower_dentry)); ecryptfs_set_dentry_lower(dentry, lower_dentry); /* * negative dentry can go positive under us here - its parent is not * locked. That's OK and that could happen just as we return from * ecryptfs_lookup() anyway. Just need to be careful and fetch * ->d_inode only once - it's not stable here. */ lower_inode = READ_ONCE(lower_dentry->d_inode); if (!lower_inode) /* We want to add because we couldn't find in lower */ return d_splice_alias(NULL, dentry); inode = __ecryptfs_get_inode(lower_inode, dentry->d_sb); if (IS_ERR(inode)) { printk(KERN_ERR "%s: Error interposing; rc = [%ld]\n", __func__, PTR_ERR(inode)); return ERR_CAST(inode); } if (S_ISREG(inode->i_mode)) { rc = ecryptfs_i_size_read(dentry, inode); if (rc) { make_bad_inode(inode); return ERR_PTR(rc); } } if (inode_state_read_once(inode) & I_NEW) unlock_new_inode(inode); return d_splice_alias(inode, dentry); } /** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @flags: lookup flags * * Find a file on disk. If the file does not exist, then we'll add it to the * dentry cache and continue on to read it from the disk. */ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, struct dentry *ecryptfs_dentry, unsigned int flags) { char *encrypted_and_encoded_name = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *lower_dir_dentry, *lower_dentry; struct qstr qname = QSTR_INIT(ecryptfs_dentry->d_name.name, ecryptfs_dentry->d_name.len); struct dentry *res; int rc = 0; lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { size_t len = qname.len; rc = ecryptfs_encrypt_and_encode_filename( &encrypted_and_encoded_name, &len, mount_crypt_stat, qname.name, len); if (rc) { printk(KERN_ERR "%s: Error attempting to encrypt and encode " "filename; rc = [%d]\n", __func__, rc); return ERR_PTR(rc); } qname.name = encrypted_and_encoded_name; qname.len = len; } lower_dentry = lookup_noperm_unlocked(&qname, lower_dir_dentry); if (IS_ERR(lower_dentry)) { ecryptfs_printk(KERN_DEBUG, "%s: lookup_noperm() returned " "[%ld] on lower_dentry = [%s]\n", __func__, PTR_ERR(lower_dentry), qname.name); res = ERR_CAST(lower_dentry); } else { res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry); } kfree(encrypted_and_encoded_name); return res; } static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct inode *lower_dir; u64 file_size_save; int rc; file_size_save = i_size_read(d_inode(old_dentry)); lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_start_creating_dentry(new_dentry); if (IS_ERR(lower_new_dentry)) return PTR_ERR(lower_new_dentry); lower_dir = lower_new_dentry->d_parent->d_inode; rc = vfs_link(lower_old_dentry, &nop_mnt_idmap, lower_dir, lower_new_dentry, NULL); if (rc || d_really_is_negative(lower_new_dentry)) goto out_lock; rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_dir); fsstack_copy_inode_size(dir, lower_dir); set_nlink(d_inode(old_dentry), ecryptfs_inode_to_lower(d_inode(old_dentry))->i_nlink); i_size_write(d_inode(new_dentry), file_size_save); out_lock: end_creating(lower_new_dentry); return rc; } static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) { return ecryptfs_do_unlink(dir, dentry, d_inode(dentry)); } static int ecryptfs_symlink(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *symname) { int rc; struct dentry *lower_dentry; struct inode *lower_dir; char *encoded_symname; size_t encoded_symlen; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; lower_dentry = ecryptfs_start_creating_dentry(dentry); if (IS_ERR(lower_dentry)) return PTR_ERR(lower_dentry); lower_dir = lower_dentry->d_parent->d_inode; mount_crypt_stat = &ecryptfs_superblock_to_private( dir->i_sb)->mount_crypt_stat; rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname, &encoded_symlen, mount_crypt_stat, symname, strlen(symname)); if (rc) goto out_lock; rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry, encoded_symname, NULL); kfree(encoded_symname); if (rc || d_really_is_negative(lower_dentry)) goto out_lock; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_dir); fsstack_copy_inode_size(dir, lower_dir); out_lock: end_creating(lower_dentry);