162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1997-2004 Erez Zadok 662306a36Sopenharmony_ci * Copyright (C) 2001-2004 Stony Brook University 762306a36Sopenharmony_ci * Copyright (C) 2004-2007 International Business Machines Corp. 862306a36Sopenharmony_ci * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> 962306a36Sopenharmony_ci * Michael C. Thompsion <mcthomps@us.ibm.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/file.h> 1362306a36Sopenharmony_ci#include <linux/vmalloc.h> 1462306a36Sopenharmony_ci#include <linux/pagemap.h> 1562306a36Sopenharmony_ci#include <linux/dcache.h> 1662306a36Sopenharmony_ci#include <linux/namei.h> 1762306a36Sopenharmony_ci#include <linux/mount.h> 1862306a36Sopenharmony_ci#include <linux/fs_stack.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/xattr.h> 2162306a36Sopenharmony_ci#include <linux/posix_acl.h> 2262306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 2362306a36Sopenharmony_ci#include <linux/fileattr.h> 2462306a36Sopenharmony_ci#include <asm/unaligned.h> 2562306a36Sopenharmony_ci#include "ecryptfs_kernel.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int lock_parent(struct dentry *dentry, 2862306a36Sopenharmony_ci struct dentry **lower_dentry, 2962306a36Sopenharmony_ci struct inode **lower_dir) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci struct dentry *lower_dir_dentry; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); 3462306a36Sopenharmony_ci *lower_dir = d_inode(lower_dir_dentry); 3562306a36Sopenharmony_ci *lower_dentry = ecryptfs_dentry_to_lower(dentry); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci inode_lock_nested(*lower_dir, I_MUTEX_PARENT); 3862306a36Sopenharmony_ci return (*lower_dentry)->d_parent == lower_dir_dentry ? 0 : -EINVAL; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int ecryptfs_inode_test(struct inode *inode, void *lower_inode) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return ecryptfs_inode_to_lower(inode) == lower_inode; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int ecryptfs_inode_set(struct inode *inode, void *opaque) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct inode *lower_inode = opaque; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci ecryptfs_set_inode_lower(inode, lower_inode); 5162306a36Sopenharmony_ci fsstack_copy_attr_all(inode, lower_inode); 5262306a36Sopenharmony_ci /* i_size will be overwritten for encrypted regular files */ 5362306a36Sopenharmony_ci fsstack_copy_inode_size(inode, lower_inode); 5462306a36Sopenharmony_ci inode->i_ino = lower_inode->i_ino; 5562306a36Sopenharmony_ci inode->i_mapping->a_ops = &ecryptfs_aops; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 5862306a36Sopenharmony_ci inode->i_op = &ecryptfs_symlink_iops; 5962306a36Sopenharmony_ci else if (S_ISDIR(inode->i_mode)) 6062306a36Sopenharmony_ci inode->i_op = &ecryptfs_dir_iops; 6162306a36Sopenharmony_ci else 6262306a36Sopenharmony_ci inode->i_op = &ecryptfs_main_iops; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 6562306a36Sopenharmony_ci inode->i_fop = &ecryptfs_dir_fops; 6662306a36Sopenharmony_ci else if (special_file(inode->i_mode)) 6762306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, inode->i_rdev); 6862306a36Sopenharmony_ci else 6962306a36Sopenharmony_ci inode->i_fop = &ecryptfs_main_fops; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct inode *__ecryptfs_get_inode(struct inode *lower_inode, 7562306a36Sopenharmony_ci struct super_block *sb) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct inode *inode; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) 8062306a36Sopenharmony_ci return ERR_PTR(-EXDEV); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* Reject dealing with casefold directories. */ 8362306a36Sopenharmony_ci if (IS_CASEFOLDED(lower_inode)) { 8462306a36Sopenharmony_ci pr_err_ratelimited("%s: Can't handle casefolded directory.\n", 8562306a36Sopenharmony_ci __func__); 8662306a36Sopenharmony_ci return ERR_PTR(-EREMOTE); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (!igrab(lower_inode)) 9062306a36Sopenharmony_ci return ERR_PTR(-ESTALE); 9162306a36Sopenharmony_ci inode = iget5_locked(sb, (unsigned long)lower_inode, 9262306a36Sopenharmony_ci ecryptfs_inode_test, ecryptfs_inode_set, 9362306a36Sopenharmony_ci lower_inode); 9462306a36Sopenharmony_ci if (!inode) { 9562306a36Sopenharmony_ci iput(lower_inode); 9662306a36Sopenharmony_ci return ERR_PTR(-EACCES); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci if (!(inode->i_state & I_NEW)) 9962306a36Sopenharmony_ci iput(lower_inode); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return inode; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct inode *ecryptfs_get_inode(struct inode *lower_inode, 10562306a36Sopenharmony_ci struct super_block *sb) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct inode *inode = __ecryptfs_get_inode(lower_inode, sb); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (!IS_ERR(inode) && (inode->i_state & I_NEW)) 11062306a36Sopenharmony_ci unlock_new_inode(inode); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return inode; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/** 11662306a36Sopenharmony_ci * ecryptfs_interpose 11762306a36Sopenharmony_ci * @lower_dentry: Existing dentry in the lower filesystem 11862306a36Sopenharmony_ci * @dentry: ecryptfs' dentry 11962306a36Sopenharmony_ci * @sb: ecryptfs's super_block 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Interposes upper and lower dentries. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic int ecryptfs_interpose(struct dentry *lower_dentry, 12662306a36Sopenharmony_ci struct dentry *dentry, struct super_block *sb) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct inode *inode = ecryptfs_get_inode(d_inode(lower_dentry), sb); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (IS_ERR(inode)) 13162306a36Sopenharmony_ci return PTR_ERR(inode); 13262306a36Sopenharmony_ci d_instantiate(dentry, inode); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, 13862306a36Sopenharmony_ci struct inode *inode) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct dentry *lower_dentry; 14162306a36Sopenharmony_ci struct inode *lower_dir; 14262306a36Sopenharmony_ci int rc; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci rc = lock_parent(dentry, &lower_dentry, &lower_dir); 14562306a36Sopenharmony_ci dget(lower_dentry); // don't even try to make the lower negative 14662306a36Sopenharmony_ci if (!rc) { 14762306a36Sopenharmony_ci if (d_unhashed(lower_dentry)) 14862306a36Sopenharmony_ci rc = -EINVAL; 14962306a36Sopenharmony_ci else 15062306a36Sopenharmony_ci rc = vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, 15162306a36Sopenharmony_ci NULL); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci if (rc) { 15462306a36Sopenharmony_ci printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); 15562306a36Sopenharmony_ci goto out_unlock; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci fsstack_copy_attr_times(dir, lower_dir); 15862306a36Sopenharmony_ci set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); 15962306a36Sopenharmony_ci inode_set_ctime_to_ts(inode, inode_get_ctime(dir)); 16062306a36Sopenharmony_ciout_unlock: 16162306a36Sopenharmony_ci dput(lower_dentry); 16262306a36Sopenharmony_ci inode_unlock(lower_dir); 16362306a36Sopenharmony_ci if (!rc) 16462306a36Sopenharmony_ci d_drop(dentry); 16562306a36Sopenharmony_ci return rc; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/** 16962306a36Sopenharmony_ci * ecryptfs_do_create 17062306a36Sopenharmony_ci * @directory_inode: inode of the new file's dentry's parent in ecryptfs 17162306a36Sopenharmony_ci * @ecryptfs_dentry: New file's dentry in ecryptfs 17262306a36Sopenharmony_ci * @mode: The mode of the new file 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * Creates the underlying file and the eCryptfs inode which will link to 17562306a36Sopenharmony_ci * it. It will also update the eCryptfs directory inode to mimic the 17662306a36Sopenharmony_ci * stat of the lower directory inode. 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * Returns the new eCryptfs inode on success; an ERR_PTR on error condition 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cistatic struct inode * 18162306a36Sopenharmony_ciecryptfs_do_create(struct inode *directory_inode, 18262306a36Sopenharmony_ci struct dentry *ecryptfs_dentry, umode_t mode) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int rc; 18562306a36Sopenharmony_ci struct dentry *lower_dentry; 18662306a36Sopenharmony_ci struct inode *lower_dir; 18762306a36Sopenharmony_ci struct inode *inode; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci rc = lock_parent(ecryptfs_dentry, &lower_dentry, &lower_dir); 19062306a36Sopenharmony_ci if (!rc) 19162306a36Sopenharmony_ci rc = vfs_create(&nop_mnt_idmap, lower_dir, 19262306a36Sopenharmony_ci lower_dentry, mode, true); 19362306a36Sopenharmony_ci if (rc) { 19462306a36Sopenharmony_ci printk(KERN_ERR "%s: Failure to create dentry in lower fs; " 19562306a36Sopenharmony_ci "rc = [%d]\n", __func__, rc); 19662306a36Sopenharmony_ci inode = ERR_PTR(rc); 19762306a36Sopenharmony_ci goto out_lock; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci inode = __ecryptfs_get_inode(d_inode(lower_dentry), 20062306a36Sopenharmony_ci directory_inode->i_sb); 20162306a36Sopenharmony_ci if (IS_ERR(inode)) { 20262306a36Sopenharmony_ci vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL); 20362306a36Sopenharmony_ci goto out_lock; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci fsstack_copy_attr_times(directory_inode, lower_dir); 20662306a36Sopenharmony_ci fsstack_copy_inode_size(directory_inode, lower_dir); 20762306a36Sopenharmony_ciout_lock: 20862306a36Sopenharmony_ci inode_unlock(lower_dir); 20962306a36Sopenharmony_ci return inode; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/* 21362306a36Sopenharmony_ci * ecryptfs_initialize_file 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Cause the file to be changed from a basic empty file to an ecryptfs 21662306a36Sopenharmony_ci * file with a header and first data page. 21762306a36Sopenharmony_ci * 21862306a36Sopenharmony_ci * Returns zero on success 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ciint ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, 22162306a36Sopenharmony_ci struct inode *ecryptfs_inode) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct ecryptfs_crypt_stat *crypt_stat = 22462306a36Sopenharmony_ci &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; 22562306a36Sopenharmony_ci int rc = 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (S_ISDIR(ecryptfs_inode->i_mode)) { 22862306a36Sopenharmony_ci ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); 22962306a36Sopenharmony_ci crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); 23062306a36Sopenharmony_ci goto out; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); 23362306a36Sopenharmony_ci rc = ecryptfs_new_file_context(ecryptfs_inode); 23462306a36Sopenharmony_ci if (rc) { 23562306a36Sopenharmony_ci ecryptfs_printk(KERN_ERR, "Error creating new file " 23662306a36Sopenharmony_ci "context; rc = [%d]\n", rc); 23762306a36Sopenharmony_ci goto out; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode); 24062306a36Sopenharmony_ci if (rc) { 24162306a36Sopenharmony_ci printk(KERN_ERR "%s: Error attempting to initialize " 24262306a36Sopenharmony_ci "the lower file for the dentry with name " 24362306a36Sopenharmony_ci "[%pd]; rc = [%d]\n", __func__, 24462306a36Sopenharmony_ci ecryptfs_dentry, rc); 24562306a36Sopenharmony_ci goto out; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); 24862306a36Sopenharmony_ci if (rc) 24962306a36Sopenharmony_ci printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); 25062306a36Sopenharmony_ci ecryptfs_put_lower_file(ecryptfs_inode); 25162306a36Sopenharmony_ciout: 25262306a36Sopenharmony_ci return rc; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * ecryptfs_create 25762306a36Sopenharmony_ci * @mode: The mode of the new file. 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Creates a new file. 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Returns zero on success; non-zero on error condition 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_cistatic int 26462306a36Sopenharmony_ciecryptfs_create(struct mnt_idmap *idmap, 26562306a36Sopenharmony_ci struct inode *directory_inode, struct dentry *ecryptfs_dentry, 26662306a36Sopenharmony_ci umode_t mode, bool excl) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct inode *ecryptfs_inode; 26962306a36Sopenharmony_ci int rc; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry, 27262306a36Sopenharmony_ci mode); 27362306a36Sopenharmony_ci if (IS_ERR(ecryptfs_inode)) { 27462306a36Sopenharmony_ci ecryptfs_printk(KERN_WARNING, "Failed to create file in" 27562306a36Sopenharmony_ci "lower filesystem\n"); 27662306a36Sopenharmony_ci rc = PTR_ERR(ecryptfs_inode); 27762306a36Sopenharmony_ci goto out; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci /* At this point, a file exists on "disk"; we need to make sure 28062306a36Sopenharmony_ci * that this on disk file is prepared to be an ecryptfs file */ 28162306a36Sopenharmony_ci rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode); 28262306a36Sopenharmony_ci if (rc) { 28362306a36Sopenharmony_ci ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, 28462306a36Sopenharmony_ci ecryptfs_inode); 28562306a36Sopenharmony_ci iget_failed(ecryptfs_inode); 28662306a36Sopenharmony_ci goto out; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci d_instantiate_new(ecryptfs_dentry, ecryptfs_inode); 28962306a36Sopenharmony_ciout: 29062306a36Sopenharmony_ci return rc; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int ecryptfs_i_size_read(struct dentry *dentry, struct inode *inode) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct ecryptfs_crypt_stat *crypt_stat; 29662306a36Sopenharmony_ci int rc; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci rc = ecryptfs_get_lower_file(dentry, inode); 29962306a36Sopenharmony_ci if (rc) { 30062306a36Sopenharmony_ci printk(KERN_ERR "%s: Error attempting to initialize " 30162306a36Sopenharmony_ci "the lower file for the dentry with name " 30262306a36Sopenharmony_ci "[%pd]; rc = [%d]\n", __func__, 30362306a36Sopenharmony_ci dentry, rc); 30462306a36Sopenharmony_ci return rc; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; 30862306a36Sopenharmony_ci /* TODO: lock for crypt_stat comparison */ 30962306a36Sopenharmony_ci if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) 31062306a36Sopenharmony_ci ecryptfs_set_default_sizes(crypt_stat); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci rc = ecryptfs_read_and_validate_header_region(inode); 31362306a36Sopenharmony_ci ecryptfs_put_lower_file(inode); 31462306a36Sopenharmony_ci if (rc) { 31562306a36Sopenharmony_ci rc = ecryptfs_read_and_validate_xattr_region(dentry, inode); 31662306a36Sopenharmony_ci if (!rc) 31762306a36Sopenharmony_ci crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Must return 0 to allow non-eCryptfs files to be looked up, too */ 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * ecryptfs_lookup_interpose - Dentry interposition for a lookup 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_cistatic struct dentry *ecryptfs_lookup_interpose(struct dentry *dentry, 32862306a36Sopenharmony_ci struct dentry *lower_dentry) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci const struct path *path = ecryptfs_dentry_to_lower_path(dentry->d_parent); 33162306a36Sopenharmony_ci struct inode *inode, *lower_inode; 33262306a36Sopenharmony_ci struct ecryptfs_dentry_info *dentry_info; 33362306a36Sopenharmony_ci int rc = 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL); 33662306a36Sopenharmony_ci if (!dentry_info) { 33762306a36Sopenharmony_ci dput(lower_dentry); 33862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci fsstack_copy_attr_atime(d_inode(dentry->d_parent), 34262306a36Sopenharmony_ci d_inode(path->dentry)); 34362306a36Sopenharmony_ci BUG_ON(!d_count(lower_dentry)); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci ecryptfs_set_dentry_private(dentry, dentry_info); 34662306a36Sopenharmony_ci dentry_info->lower_path.mnt = mntget(path->mnt); 34762306a36Sopenharmony_ci dentry_info->lower_path.dentry = lower_dentry; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * negative dentry can go positive under us here - its parent is not 35162306a36Sopenharmony_ci * locked. That's OK and that could happen just as we return from 35262306a36Sopenharmony_ci * ecryptfs_lookup() anyway. Just need to be careful and fetch 35362306a36Sopenharmony_ci * ->d_inode only once - it's not stable here. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci lower_inode = READ_ONCE(lower_dentry->d_inode); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (!lower_inode) { 35862306a36Sopenharmony_ci /* We want to add because we couldn't find in lower */ 35962306a36Sopenharmony_ci d_add(dentry, NULL); 36062306a36Sopenharmony_ci return NULL; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci inode = __ecryptfs_get_inode(lower_inode, dentry->d_sb); 36362306a36Sopenharmony_ci if (IS_ERR(inode)) { 36462306a36Sopenharmony_ci printk(KERN_ERR "%s: Error interposing; rc = [%ld]\n", 36562306a36Sopenharmony_ci __func__, PTR_ERR(inode)); 36662306a36Sopenharmony_ci return ERR_CAST(inode); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 36962306a36Sopenharmony_ci rc = ecryptfs_i_size_read(dentry, inode); 37062306a36Sopenharmony_ci if (rc) { 37162306a36Sopenharmony_ci make_bad_inode(inode); 37262306a36Sopenharmony_ci return ERR_PTR(rc); 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (inode->i_state & I_NEW) 37762306a36Sopenharmony_ci unlock_new_inode(inode); 37862306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci/** 38262306a36Sopenharmony_ci * ecryptfs_lookup 38362306a36Sopenharmony_ci * @ecryptfs_dir_inode: The eCryptfs directory inode 38462306a36Sopenharmony_ci * @ecryptfs_dentry: The eCryptfs dentry that we are looking up 38562306a36Sopenharmony_ci * @flags: lookup flags 38662306a36Sopenharmony_ci * 38762306a36Sopenharmony_ci * Find a file on disk. If the file does not exist, then we'll add it to the 38862306a36Sopenharmony_ci * dentry cache and continue on to read it from the disk. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_cistatic struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, 39162306a36Sopenharmony_ci struct dentry *ecryptfs_dentry, 39262306a36Sopenharmony_ci unsigned int flags) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci char *encrypted_and_encoded_name = NULL; 39562306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat; 39662306a36Sopenharmony_ci struct dentry *lower_dir_dentry, *lower_dentry; 39762306a36Sopenharmony_ci const char *name = ecryptfs_dentry->d_name.name; 39862306a36Sopenharmony_ci size_t len = ecryptfs_dentry->d_name.len; 39962306a36Sopenharmony_ci struct dentry *res; 40062306a36Sopenharmony_ci int rc = 0; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci mount_crypt_stat = &ecryptfs_superblock_to_private( 40562306a36Sopenharmony_ci ecryptfs_dentry->d_sb)->mount_crypt_stat; 40662306a36Sopenharmony_ci if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { 40762306a36Sopenharmony_ci rc = ecryptfs_encrypt_and_encode_filename( 40862306a36Sopenharmony_ci &encrypted_and_encoded_name, &len, 40962306a36Sopenharmony_ci mount_crypt_stat, name, len); 41062306a36Sopenharmony_ci if (rc) { 41162306a36Sopenharmony_ci printk(KERN_ERR "%s: Error attempting to encrypt and encode " 41262306a36Sopenharmony_ci "filename; rc = [%d]\n", __func__, rc); 41362306a36Sopenharmony_ci return ERR_PTR(rc); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci name = encrypted_and_encoded_name; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci lower_dentry = lookup_one_len_unlocked(name, lower_dir_dentry, len); 41962306a36Sopenharmony_ci if (IS_ERR(lower_dentry)) { 42062306a36Sopenharmony_ci ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " 42162306a36Sopenharmony_ci "[%ld] on lower_dentry = [%s]\n", __func__, 42262306a36Sopenharmony_ci PTR_ERR(lower_dentry), 42362306a36Sopenharmony_ci name); 42462306a36Sopenharmony_ci res = ERR_CAST(lower_dentry); 42562306a36Sopenharmony_ci } else { 42662306a36Sopenharmony_ci res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci kfree(encrypted_and_encoded_name); 42962306a36Sopenharmony_ci return res; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, 43362306a36Sopenharmony_ci struct dentry *new_dentry) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct dentry *lower_old_dentry; 43662306a36Sopenharmony_ci struct dentry *lower_new_dentry; 43762306a36Sopenharmony_ci struct inode *lower_dir; 43862306a36Sopenharmony_ci u64 file_size_save; 43962306a36Sopenharmony_ci int rc; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci file_size_save = i_size_read(d_inode(old_dentry)); 44262306a36Sopenharmony_ci lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); 44362306a36Sopenharmony_ci rc = lock_parent(new_dentry, &lower_new_dentry, &lower_dir); 44462306a36Sopenharmony_ci if (!rc) 44562306a36Sopenharmony_ci rc = vfs_link(lower_old_dentry, &nop_mnt_idmap, lower_dir, 44662306a36Sopenharmony_ci lower_new_dentry, NULL); 44762306a36Sopenharmony_ci if (rc || d_really_is_negative(lower_new_dentry)) 44862306a36Sopenharmony_ci goto out_lock; 44962306a36Sopenharmony_ci rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb); 45062306a36Sopenharmony_ci if (rc) 45162306a36Sopenharmony_ci goto out_lock; 45262306a36Sopenharmony_ci fsstack_copy_attr_times(dir, lower_dir); 45362306a36Sopenharmony_ci fsstack_copy_inode_size(dir, lower_dir); 45462306a36Sopenharmony_ci set_nlink(d_inode(old_dentry), 45562306a36Sopenharmony_ci ecryptfs_inode_to_lower(d_inode(old_dentry))->i_nlink); 45662306a36Sopenharmony_ci i_size_write(d_inode(new_dentry), file_size_save); 45762306a36Sopenharmony_ciout_lock: 45862306a36Sopenharmony_ci inode_unlock(lower_dir); 45962306a36Sopenharmony_ci return rc; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci return ecryptfs_do_unlink(dir, dentry, d_inode(dentry)); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic int ecryptfs_symlink(struct mnt_idmap *idmap, 46862306a36Sopenharmony_ci struct inode *dir, struct dentry *dentry, 46962306a36Sopenharmony_ci const char *symname) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci int rc; 47262306a36Sopenharmony_ci struct dentry *lower_dentry; 47362306a36Sopenharmony_ci struct inode *lower_dir; 47462306a36Sopenharmony_ci char *encoded_symname; 47562306a36Sopenharmony_ci size_t encoded_symlen; 47662306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci rc = lock_parent(dentry, &lower_dentry, &lower_dir); 47962306a36Sopenharmony_ci if (rc) 48062306a36Sopenharmony_ci goto out_lock; 48162306a36Sopenharmony_ci mount_crypt_stat = &ecryptfs_superblock_to_private( 48262306a36Sopenharmony_ci dir->i_sb)->mount_crypt_stat; 48362306a36Sopenharmony_ci rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname, 48462306a36Sopenharmony_ci &encoded_symlen, 48562306a36Sopenharmony_ci mount_crypt_stat, symname, 48662306a36Sopenharmony_ci strlen(symname)); 48762306a36Sopenharmony_ci if (rc) 48862306a36Sopenharmony_ci goto out_lock; 48962306a36Sopenharmony_ci rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry, 49062306a36Sopenharmony_ci encoded_symname); 49162306a36Sopenharmony_ci kfree(encoded_symname); 49262306a36Sopenharmony_ci if (rc || d_really_is_negative(lower_dentry)) 49362306a36Sopenharmony_ci goto out_lock; 49462306a36Sopenharmony_ci rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); 49562306a36Sopenharmony_ci if (rc) 49662306a36Sopenharmony_ci goto out_lock; 49762306a36Sopenharmony_ci fsstack_copy_attr_times(dir, lower_dir); 49862306a36Sopenharmony_ci fsstack_copy_inode_size(dir, lower_dir); 49962306a36Sopenharmony_ciout_lock: 50062306a36Sopenharmony_ci inode_unlock(lower_dir); 50162306a36Sopenharmony_ci if (d_really_is_negative(dentry)) 50262306a36Sopenharmony_ci d_drop(dentry); 50362306a36Sopenharmony_ci return rc; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic int ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, 50762306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci int rc; 51062306a36Sopenharmony_ci struct dentry *lower_dentry; 51162306a36Sopenharmony_ci struct inode *lower_dir; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci rc = lock_parent(dentry, &lower_dentry, &lower_dir); 51462306a36Sopenharmony_ci if (!rc) 51562306a36Sopenharmony_ci rc = vfs_mkdir(&nop_mnt_idmap, lower_dir, 51662306a36Sopenharmony_ci lower_dentry, mode); 51762306a36Sopenharmony_ci if (rc || d_really_is_negative(lower_dentry)) 51862306a36Sopenharmony_ci goto out; 51962306a36Sopenharmony_ci rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); 52062306a36Sopenharmony_ci if (rc) 52162306a36Sopenharmony_ci goto out; 52262306a36Sopenharmony_ci fsstack_copy_attr_times(dir, lower_dir); 52362306a36Sopenharmony_ci fsstack_copy_inode_size(dir, lower_dir); 52462306a36Sopenharmony_ci set_nlink(dir, lower_dir->i_nlink); 52562306a36Sopenharmony_ciout: 52662306a36Sopenharmony_ci inode_unlock(lower_dir); 52762306a36Sopenharmony_ci if (d_really_is_negative(dentry)) 52862306a36Sopenharmony_ci d_drop(dentry); 52962306a36Sopenharmony_ci return rc; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct dentry *lower_dentry; 53562306a36Sopenharmony_ci struct inode *lower_dir; 53662306a36Sopenharmony_ci int rc; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci rc = lock_parent(dentry, &lower_dentry, &lower_dir); 53962306a36Sopenharmony_ci dget(lower_dentry); // don't even try to make the lower negative 54062306a36Sopenharmony_ci if (!rc) { 54162306a36Sopenharmony_ci if (d_unhashed(lower_dentry)) 54262306a36Sopenharmony_ci rc = -EINVAL; 54362306a36Sopenharmony_ci else 54462306a36Sopenharmony_ci rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci if (!rc) { 54762306a36Sopenharmony_ci clear_nlink(d_inode(dentry)); 54862306a36Sopenharmony_ci fsstack_copy_attr_times(dir, lower_dir); 54962306a36Sopenharmony_ci set_nlink(dir, lower_dir->i_nlink); 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci dput(lower_dentry); 55262306a36Sopenharmony_ci inode_unlock(lower_dir); 55362306a36Sopenharmony_ci if (!rc) 55462306a36Sopenharmony_ci d_drop(dentry); 55562306a36Sopenharmony_ci return rc; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic int 55962306a36Sopenharmony_ciecryptfs_mknod(struct mnt_idmap *idmap, struct inode *dir, 56062306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, dev_t dev) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci int rc; 56362306a36Sopenharmony_ci struct dentry *lower_dentry; 56462306a36Sopenharmony_ci struct inode *lower_dir; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci rc = lock_parent(dentry, &lower_dentry, &lower_dir); 56762306a36Sopenharmony_ci if (!rc) 56862306a36Sopenharmony_ci rc = vfs_mknod(&nop_mnt_idmap, lower_dir, 56962306a36Sopenharmony_ci lower_dentry, mode, dev); 57062306a36Sopenharmony_ci if (rc || d_really_is_negative(lower_dentry)) 57162306a36Sopenharmony_ci goto out; 57262306a36Sopenharmony_ci rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); 57362306a36Sopenharmony_ci if (rc) 57462306a36Sopenharmony_ci goto out; 57562306a36Sopenharmony_ci fsstack_copy_attr_times(dir, lower_dir); 57662306a36Sopenharmony_ci fsstack_copy_inode_size(dir, lower_dir); 57762306a36Sopenharmony_ciout: 57862306a36Sopenharmony_ci inode_unlock(lower_dir); 57962306a36Sopenharmony_ci if (d_really_is_negative(dentry)) 58062306a36Sopenharmony_ci d_drop(dentry); 58162306a36Sopenharmony_ci return rc; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int 58562306a36Sopenharmony_ciecryptfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, 58662306a36Sopenharmony_ci struct dentry *old_dentry, struct inode *new_dir, 58762306a36Sopenharmony_ci struct dentry *new_dentry, unsigned int flags) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci int rc; 59062306a36Sopenharmony_ci struct dentry *lower_old_dentry; 59162306a36Sopenharmony_ci struct dentry *lower_new_dentry; 59262306a36Sopenharmony_ci struct dentry *lower_old_dir_dentry; 59362306a36Sopenharmony_ci struct dentry *lower_new_dir_dentry; 59462306a36Sopenharmony_ci struct dentry *trap; 59562306a36Sopenharmony_ci struct inode *target_inode; 59662306a36Sopenharmony_ci struct renamedata rd = {}; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (flags) 59962306a36Sopenharmony_ci return -EINVAL; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci lower_old_dir_dentry = ecryptfs_dentry_to_lower(old_dentry->d_parent); 60262306a36Sopenharmony_ci lower_new_dir_dentry = ecryptfs_dentry_to_lower(new_dentry->d_parent); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); 60562306a36Sopenharmony_ci lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci target_inode = d_inode(new_dentry); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); 61062306a36Sopenharmony_ci dget(lower_new_dentry); 61162306a36Sopenharmony_ci rc = -EINVAL; 61262306a36Sopenharmony_ci if (lower_old_dentry->d_parent != lower_old_dir_dentry) 61362306a36Sopenharmony_ci goto out_lock; 61462306a36Sopenharmony_ci if (lower_new_dentry->d_parent != lower_new_dir_dentry) 61562306a36Sopenharmony_ci goto out_lock; 61662306a36Sopenharmony_ci if (d_unhashed(lower_old_dentry) || d_unhashed(lower_new_dentry)) 61762306a36Sopenharmony_ci goto out_lock; 61862306a36Sopenharmony_ci /* source should not be ancestor of target */ 61962306a36Sopenharmony_ci if (trap == lower_old_dentry) 62062306a36Sopenharmony_ci goto out_lock; 62162306a36Sopenharmony_ci /* target should not be ancestor of source */ 62262306a36Sopenharmony_ci if (trap == lower_new_dentry) { 62362306a36Sopenharmony_ci rc = -ENOTEMPTY; 62462306a36Sopenharmony_ci goto out_lock; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci rd.old_mnt_idmap = &nop_mnt_idmap; 62862306a36Sopenharmony_ci rd.old_dir = d_inode(lower_old_dir_dentry); 62962306a36Sopenharmony_ci rd.old_dentry = lower_old_dentry; 63062306a36Sopenharmony_ci rd.new_mnt_idmap = &nop_mnt_idmap; 63162306a36Sopenharmony_ci rd.new_dir = d_inode(lower_new_dir_dentry); 63262306a36Sopenharmony_ci rd.new_dentry = lower_new_dentry; 63362306a36Sopenharmony_ci rc = vfs_rename(&rd); 63462306a36Sopenharmony_ci if (rc) 63562306a36Sopenharmony_ci goto out_lock; 63662306a36Sopenharmony_ci if (target_inode) 63762306a36Sopenharmony_ci fsstack_copy_attr_all(target_inode, 63862306a36Sopenharmony_ci ecryptfs_inode_to_lower(target_inode)); 63962306a36Sopenharmony_ci fsstack_copy_attr_all(new_dir, d_inode(lower_new_dir_dentry)); 64062306a36Sopenharmony_ci if (new_dir != old_dir) 64162306a36Sopenharmony_ci fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry)); 64262306a36Sopenharmony_ciout_lock: 64362306a36Sopenharmony_ci dput(lower_new_dentry); 64462306a36Sopenharmony_ci unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); 64562306a36Sopenharmony_ci return rc; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci DEFINE_DELAYED_CALL(done); 65162306a36Sopenharmony_ci struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 65262306a36Sopenharmony_ci const char *link; 65362306a36Sopenharmony_ci char *buf; 65462306a36Sopenharmony_ci int rc; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci link = vfs_get_link(lower_dentry, &done); 65762306a36Sopenharmony_ci if (IS_ERR(link)) 65862306a36Sopenharmony_ci return ERR_CAST(link); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb, 66162306a36Sopenharmony_ci link, strlen(link)); 66262306a36Sopenharmony_ci do_delayed_call(&done); 66362306a36Sopenharmony_ci if (rc) 66462306a36Sopenharmony_ci return ERR_PTR(rc); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci return buf; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic const char *ecryptfs_get_link(struct dentry *dentry, 67062306a36Sopenharmony_ci struct inode *inode, 67162306a36Sopenharmony_ci struct delayed_call *done) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci size_t len; 67462306a36Sopenharmony_ci char *buf; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (!dentry) 67762306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci buf = ecryptfs_readlink_lower(dentry, &len); 68062306a36Sopenharmony_ci if (IS_ERR(buf)) 68162306a36Sopenharmony_ci return buf; 68262306a36Sopenharmony_ci fsstack_copy_attr_atime(d_inode(dentry), 68362306a36Sopenharmony_ci d_inode(ecryptfs_dentry_to_lower(dentry))); 68462306a36Sopenharmony_ci buf[len] = '\0'; 68562306a36Sopenharmony_ci set_delayed_call(done, kfree_link, buf); 68662306a36Sopenharmony_ci return buf; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/** 69062306a36Sopenharmony_ci * upper_size_to_lower_size 69162306a36Sopenharmony_ci * @crypt_stat: Crypt_stat associated with file 69262306a36Sopenharmony_ci * @upper_size: Size of the upper file 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * Calculate the required size of the lower file based on the 69562306a36Sopenharmony_ci * specified size of the upper file. This calculation is based on the 69662306a36Sopenharmony_ci * number of headers in the underlying file and the extent size. 69762306a36Sopenharmony_ci * 69862306a36Sopenharmony_ci * Returns Calculated size of the lower file. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_cistatic loff_t 70162306a36Sopenharmony_ciupper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, 70262306a36Sopenharmony_ci loff_t upper_size) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci loff_t lower_size; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci lower_size = ecryptfs_lower_header_size(crypt_stat); 70762306a36Sopenharmony_ci if (upper_size != 0) { 70862306a36Sopenharmony_ci loff_t num_extents; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci num_extents = upper_size >> crypt_stat->extent_shift; 71162306a36Sopenharmony_ci if (upper_size & ~crypt_stat->extent_mask) 71262306a36Sopenharmony_ci num_extents++; 71362306a36Sopenharmony_ci lower_size += (num_extents * crypt_stat->extent_size); 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci return lower_size; 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci/** 71962306a36Sopenharmony_ci * truncate_upper 72062306a36Sopenharmony_ci * @dentry: The ecryptfs layer dentry 72162306a36Sopenharmony_ci * @ia: Address of the ecryptfs inode's attributes 72262306a36Sopenharmony_ci * @lower_ia: Address of the lower inode's attributes 72362306a36Sopenharmony_ci * 72462306a36Sopenharmony_ci * Function to handle truncations modifying the size of the file. Note 72562306a36Sopenharmony_ci * that the file sizes are interpolated. When expanding, we are simply 72662306a36Sopenharmony_ci * writing strings of 0's out. When truncating, we truncate the upper 72762306a36Sopenharmony_ci * inode and update the lower_ia according to the page index 72862306a36Sopenharmony_ci * interpolations. If ATTR_SIZE is set in lower_ia->ia_valid upon return, 72962306a36Sopenharmony_ci * the caller must use lower_ia in a call to notify_change() to perform 73062306a36Sopenharmony_ci * the truncation of the lower inode. 73162306a36Sopenharmony_ci * 73262306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_cistatic int truncate_upper(struct dentry *dentry, struct iattr *ia, 73562306a36Sopenharmony_ci struct iattr *lower_ia) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci int rc = 0; 73862306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 73962306a36Sopenharmony_ci struct ecryptfs_crypt_stat *crypt_stat; 74062306a36Sopenharmony_ci loff_t i_size = i_size_read(inode); 74162306a36Sopenharmony_ci loff_t lower_size_before_truncate; 74262306a36Sopenharmony_ci loff_t lower_size_after_truncate; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (unlikely((ia->ia_size == i_size))) { 74562306a36Sopenharmony_ci lower_ia->ia_valid &= ~ATTR_SIZE; 74662306a36Sopenharmony_ci return 0; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci rc = ecryptfs_get_lower_file(dentry, inode); 74962306a36Sopenharmony_ci if (rc) 75062306a36Sopenharmony_ci return rc; 75162306a36Sopenharmony_ci crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat; 75262306a36Sopenharmony_ci /* Switch on growing or shrinking file */ 75362306a36Sopenharmony_ci if (ia->ia_size > i_size) { 75462306a36Sopenharmony_ci char zero[] = { 0x00 }; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci lower_ia->ia_valid &= ~ATTR_SIZE; 75762306a36Sopenharmony_ci /* Write a single 0 at the last position of the file; 75862306a36Sopenharmony_ci * this triggers code that will fill in 0's throughout 75962306a36Sopenharmony_ci * the intermediate portion of the previous end of the 76062306a36Sopenharmony_ci * file and the new and of the file */ 76162306a36Sopenharmony_ci rc = ecryptfs_write(inode, zero, 76262306a36Sopenharmony_ci (ia->ia_size - 1), 1); 76362306a36Sopenharmony_ci } else { /* ia->ia_size < i_size_read(inode) */ 76462306a36Sopenharmony_ci /* We're chopping off all the pages down to the page 76562306a36Sopenharmony_ci * in which ia->ia_size is located. Fill in the end of 76662306a36Sopenharmony_ci * that page from (ia->ia_size & ~PAGE_MASK) to 76762306a36Sopenharmony_ci * PAGE_SIZE with zeros. */ 76862306a36Sopenharmony_ci size_t num_zeros = (PAGE_SIZE 76962306a36Sopenharmony_ci - (ia->ia_size & ~PAGE_MASK)); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { 77262306a36Sopenharmony_ci truncate_setsize(inode, ia->ia_size); 77362306a36Sopenharmony_ci lower_ia->ia_size = ia->ia_size; 77462306a36Sopenharmony_ci lower_ia->ia_valid |= ATTR_SIZE; 77562306a36Sopenharmony_ci goto out; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci if (num_zeros) { 77862306a36Sopenharmony_ci char *zeros_virt; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci zeros_virt = kzalloc(num_zeros, GFP_KERNEL); 78162306a36Sopenharmony_ci if (!zeros_virt) { 78262306a36Sopenharmony_ci rc = -ENOMEM; 78362306a36Sopenharmony_ci goto out; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci rc = ecryptfs_write(inode, zeros_virt, 78662306a36Sopenharmony_ci ia->ia_size, num_zeros); 78762306a36Sopenharmony_ci kfree(zeros_virt); 78862306a36Sopenharmony_ci if (rc) { 78962306a36Sopenharmony_ci printk(KERN_ERR "Error attempting to zero out " 79062306a36Sopenharmony_ci "the remainder of the end page on " 79162306a36Sopenharmony_ci "reducing truncate; rc = [%d]\n", rc); 79262306a36Sopenharmony_ci goto out; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci truncate_setsize(inode, ia->ia_size); 79662306a36Sopenharmony_ci rc = ecryptfs_write_inode_size_to_metadata(inode); 79762306a36Sopenharmony_ci if (rc) { 79862306a36Sopenharmony_ci printk(KERN_ERR "Problem with " 79962306a36Sopenharmony_ci "ecryptfs_write_inode_size_to_metadata; " 80062306a36Sopenharmony_ci "rc = [%d]\n", rc); 80162306a36Sopenharmony_ci goto out; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci /* We are reducing the size of the ecryptfs file, and need to 80462306a36Sopenharmony_ci * know if we need to reduce the size of the lower file. */ 80562306a36Sopenharmony_ci lower_size_before_truncate = 80662306a36Sopenharmony_ci upper_size_to_lower_size(crypt_stat, i_size); 80762306a36Sopenharmony_ci lower_size_after_truncate = 80862306a36Sopenharmony_ci upper_size_to_lower_size(crypt_stat, ia->ia_size); 80962306a36Sopenharmony_ci if (lower_size_after_truncate < lower_size_before_truncate) { 81062306a36Sopenharmony_ci lower_ia->ia_size = lower_size_after_truncate; 81162306a36Sopenharmony_ci lower_ia->ia_valid |= ATTR_SIZE; 81262306a36Sopenharmony_ci } else 81362306a36Sopenharmony_ci lower_ia->ia_valid &= ~ATTR_SIZE; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ciout: 81662306a36Sopenharmony_ci ecryptfs_put_lower_file(inode); 81762306a36Sopenharmony_ci return rc; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int ecryptfs_inode_newsize_ok(struct inode *inode, loff_t offset) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct ecryptfs_crypt_stat *crypt_stat; 82362306a36Sopenharmony_ci loff_t lower_oldsize, lower_newsize; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; 82662306a36Sopenharmony_ci lower_oldsize = upper_size_to_lower_size(crypt_stat, 82762306a36Sopenharmony_ci i_size_read(inode)); 82862306a36Sopenharmony_ci lower_newsize = upper_size_to_lower_size(crypt_stat, offset); 82962306a36Sopenharmony_ci if (lower_newsize > lower_oldsize) { 83062306a36Sopenharmony_ci /* 83162306a36Sopenharmony_ci * The eCryptfs inode and the new *lower* size are mixed here 83262306a36Sopenharmony_ci * because we may not have the lower i_mutex held and/or it may 83362306a36Sopenharmony_ci * not be appropriate to call inode_newsize_ok() with inodes 83462306a36Sopenharmony_ci * from other filesystems. 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_ci return inode_newsize_ok(inode, lower_newsize); 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return 0; 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/** 84362306a36Sopenharmony_ci * ecryptfs_truncate 84462306a36Sopenharmony_ci * @dentry: The ecryptfs layer dentry 84562306a36Sopenharmony_ci * @new_length: The length to expand the file to 84662306a36Sopenharmony_ci * 84762306a36Sopenharmony_ci * Simple function that handles the truncation of an eCryptfs inode and 84862306a36Sopenharmony_ci * its corresponding lower inode. 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * Returns zero on success; non-zero otherwise 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ciint ecryptfs_truncate(struct dentry *dentry, loff_t new_length) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci struct iattr ia = { .ia_valid = ATTR_SIZE, .ia_size = new_length }; 85562306a36Sopenharmony_ci struct iattr lower_ia = { .ia_valid = 0 }; 85662306a36Sopenharmony_ci int rc; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci rc = ecryptfs_inode_newsize_ok(d_inode(dentry), new_length); 85962306a36Sopenharmony_ci if (rc) 86062306a36Sopenharmony_ci return rc; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci rc = truncate_upper(dentry, &ia, &lower_ia); 86362306a36Sopenharmony_ci if (!rc && lower_ia.ia_valid & ATTR_SIZE) { 86462306a36Sopenharmony_ci struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci inode_lock(d_inode(lower_dentry)); 86762306a36Sopenharmony_ci rc = notify_change(&nop_mnt_idmap, lower_dentry, 86862306a36Sopenharmony_ci &lower_ia, NULL); 86962306a36Sopenharmony_ci inode_unlock(d_inode(lower_dentry)); 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci return rc; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistatic int 87562306a36Sopenharmony_ciecryptfs_permission(struct mnt_idmap *idmap, struct inode *inode, 87662306a36Sopenharmony_ci int mask) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci return inode_permission(&nop_mnt_idmap, 87962306a36Sopenharmony_ci ecryptfs_inode_to_lower(inode), mask); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/** 88362306a36Sopenharmony_ci * ecryptfs_setattr 88462306a36Sopenharmony_ci * @idmap: idmap of the target mount 88562306a36Sopenharmony_ci * @dentry: dentry handle to the inode to modify 88662306a36Sopenharmony_ci * @ia: Structure with flags of what to change and values 88762306a36Sopenharmony_ci * 88862306a36Sopenharmony_ci * Updates the metadata of an inode. If the update is to the size 88962306a36Sopenharmony_ci * i.e. truncation, then ecryptfs_truncate will handle the size modification 89062306a36Sopenharmony_ci * of both the ecryptfs inode and the lower inode. 89162306a36Sopenharmony_ci * 89262306a36Sopenharmony_ci * All other metadata changes will be passed right to the lower filesystem, 89362306a36Sopenharmony_ci * and we will just update our inode to look like the lower. 89462306a36Sopenharmony_ci */ 89562306a36Sopenharmony_cistatic int ecryptfs_setattr(struct mnt_idmap *idmap, 89662306a36Sopenharmony_ci struct dentry *dentry, struct iattr *ia) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci int rc = 0; 89962306a36Sopenharmony_ci struct dentry *lower_dentry; 90062306a36Sopenharmony_ci struct iattr lower_ia; 90162306a36Sopenharmony_ci struct inode *inode; 90262306a36Sopenharmony_ci struct inode *lower_inode; 90362306a36Sopenharmony_ci struct ecryptfs_crypt_stat *crypt_stat; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci crypt_stat = &ecryptfs_inode_to_private(d_inode(dentry))->crypt_stat; 90662306a36Sopenharmony_ci if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)) { 90762306a36Sopenharmony_ci rc = ecryptfs_init_crypt_stat(crypt_stat); 90862306a36Sopenharmony_ci if (rc) 90962306a36Sopenharmony_ci return rc; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci inode = d_inode(dentry); 91262306a36Sopenharmony_ci lower_inode = ecryptfs_inode_to_lower(inode); 91362306a36Sopenharmony_ci lower_dentry = ecryptfs_dentry_to_lower(dentry); 91462306a36Sopenharmony_ci mutex_lock(&crypt_stat->cs_mutex); 91562306a36Sopenharmony_ci if (d_is_dir(dentry)) 91662306a36Sopenharmony_ci crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); 91762306a36Sopenharmony_ci else if (d_is_reg(dentry) 91862306a36Sopenharmony_ci && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) 91962306a36Sopenharmony_ci || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) { 92062306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci mount_crypt_stat = &ecryptfs_superblock_to_private( 92362306a36Sopenharmony_ci dentry->d_sb)->mount_crypt_stat; 92462306a36Sopenharmony_ci rc = ecryptfs_get_lower_file(dentry, inode); 92562306a36Sopenharmony_ci if (rc) { 92662306a36Sopenharmony_ci mutex_unlock(&crypt_stat->cs_mutex); 92762306a36Sopenharmony_ci goto out; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci rc = ecryptfs_read_metadata(dentry); 93062306a36Sopenharmony_ci ecryptfs_put_lower_file(inode); 93162306a36Sopenharmony_ci if (rc) { 93262306a36Sopenharmony_ci if (!(mount_crypt_stat->flags 93362306a36Sopenharmony_ci & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { 93462306a36Sopenharmony_ci rc = -EIO; 93562306a36Sopenharmony_ci printk(KERN_WARNING "Either the lower file " 93662306a36Sopenharmony_ci "is not in a valid eCryptfs format, " 93762306a36Sopenharmony_ci "or the key could not be retrieved. " 93862306a36Sopenharmony_ci "Plaintext passthrough mode is not " 93962306a36Sopenharmony_ci "enabled; returning -EIO\n"); 94062306a36Sopenharmony_ci mutex_unlock(&crypt_stat->cs_mutex); 94162306a36Sopenharmony_ci goto out; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci rc = 0; 94462306a36Sopenharmony_ci crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED 94562306a36Sopenharmony_ci | ECRYPTFS_ENCRYPTED); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci mutex_unlock(&crypt_stat->cs_mutex); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci rc = setattr_prepare(&nop_mnt_idmap, dentry, ia); 95162306a36Sopenharmony_ci if (rc) 95262306a36Sopenharmony_ci goto out; 95362306a36Sopenharmony_ci if (ia->ia_valid & ATTR_SIZE) { 95462306a36Sopenharmony_ci rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size); 95562306a36Sopenharmony_ci if (rc) 95662306a36Sopenharmony_ci goto out; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci memcpy(&lower_ia, ia, sizeof(lower_ia)); 96062306a36Sopenharmony_ci if (ia->ia_valid & ATTR_FILE) 96162306a36Sopenharmony_ci lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file); 96262306a36Sopenharmony_ci if (ia->ia_valid & ATTR_SIZE) { 96362306a36Sopenharmony_ci rc = truncate_upper(dentry, ia, &lower_ia); 96462306a36Sopenharmony_ci if (rc < 0) 96562306a36Sopenharmony_ci goto out; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * mode change is for clearing setuid/setgid bits. Allow lower fs 97062306a36Sopenharmony_ci * to interpret this in its own way. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) 97362306a36Sopenharmony_ci lower_ia.ia_valid &= ~ATTR_MODE; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci inode_lock(d_inode(lower_dentry)); 97662306a36Sopenharmony_ci rc = notify_change(&nop_mnt_idmap, lower_dentry, &lower_ia, NULL); 97762306a36Sopenharmony_ci inode_unlock(d_inode(lower_dentry)); 97862306a36Sopenharmony_ciout: 97962306a36Sopenharmony_ci fsstack_copy_attr_all(inode, lower_inode); 98062306a36Sopenharmony_ci return rc; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic int ecryptfs_getattr_link(struct mnt_idmap *idmap, 98462306a36Sopenharmony_ci const struct path *path, struct kstat *stat, 98562306a36Sopenharmony_ci u32 request_mask, unsigned int flags) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci struct dentry *dentry = path->dentry; 98862306a36Sopenharmony_ci struct ecryptfs_mount_crypt_stat *mount_crypt_stat; 98962306a36Sopenharmony_ci int rc = 0; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci mount_crypt_stat = &ecryptfs_superblock_to_private( 99262306a36Sopenharmony_ci dentry->d_sb)->mount_crypt_stat; 99362306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat); 99462306a36Sopenharmony_ci if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { 99562306a36Sopenharmony_ci char *target; 99662306a36Sopenharmony_ci size_t targetsiz; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci target = ecryptfs_readlink_lower(dentry, &targetsiz); 99962306a36Sopenharmony_ci if (!IS_ERR(target)) { 100062306a36Sopenharmony_ci kfree(target); 100162306a36Sopenharmony_ci stat->size = targetsiz; 100262306a36Sopenharmony_ci } else { 100362306a36Sopenharmony_ci rc = PTR_ERR(target); 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci return rc; 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cistatic int ecryptfs_do_getattr(const struct path *path, struct kstat *stat, 101062306a36Sopenharmony_ci u32 request_mask, unsigned int flags) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci if (flags & AT_GETATTR_NOSEC) 101362306a36Sopenharmony_ci return vfs_getattr_nosec(path, stat, request_mask, flags); 101462306a36Sopenharmony_ci return vfs_getattr(path, stat, request_mask, flags); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int ecryptfs_getattr(struct mnt_idmap *idmap, 101862306a36Sopenharmony_ci const struct path *path, struct kstat *stat, 101962306a36Sopenharmony_ci u32 request_mask, unsigned int flags) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct dentry *dentry = path->dentry; 102262306a36Sopenharmony_ci struct kstat lower_stat; 102362306a36Sopenharmony_ci int rc; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci rc = ecryptfs_do_getattr(ecryptfs_dentry_to_lower_path(dentry), 102662306a36Sopenharmony_ci &lower_stat, request_mask, flags); 102762306a36Sopenharmony_ci if (!rc) { 102862306a36Sopenharmony_ci fsstack_copy_attr_all(d_inode(dentry), 102962306a36Sopenharmony_ci ecryptfs_inode_to_lower(d_inode(dentry))); 103062306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, 103162306a36Sopenharmony_ci d_inode(dentry), stat); 103262306a36Sopenharmony_ci stat->blocks = lower_stat.blocks; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci return rc; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ciint 103862306a36Sopenharmony_ciecryptfs_setxattr(struct dentry *dentry, struct inode *inode, 103962306a36Sopenharmony_ci const char *name, const void *value, 104062306a36Sopenharmony_ci size_t size, int flags) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci int rc; 104362306a36Sopenharmony_ci struct dentry *lower_dentry; 104462306a36Sopenharmony_ci struct inode *lower_inode; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci lower_dentry = ecryptfs_dentry_to_lower(dentry); 104762306a36Sopenharmony_ci lower_inode = d_inode(lower_dentry); 104862306a36Sopenharmony_ci if (!(lower_inode->i_opflags & IOP_XATTR)) { 104962306a36Sopenharmony_ci rc = -EOPNOTSUPP; 105062306a36Sopenharmony_ci goto out; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci inode_lock(lower_inode); 105362306a36Sopenharmony_ci rc = __vfs_setxattr_locked(&nop_mnt_idmap, lower_dentry, name, value, size, flags, NULL); 105462306a36Sopenharmony_ci inode_unlock(lower_inode); 105562306a36Sopenharmony_ci if (!rc && inode) 105662306a36Sopenharmony_ci fsstack_copy_attr_all(inode, lower_inode); 105762306a36Sopenharmony_ciout: 105862306a36Sopenharmony_ci return rc; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cissize_t 106262306a36Sopenharmony_ciecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode, 106362306a36Sopenharmony_ci const char *name, void *value, size_t size) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci int rc; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (!(lower_inode->i_opflags & IOP_XATTR)) { 106862306a36Sopenharmony_ci rc = -EOPNOTSUPP; 106962306a36Sopenharmony_ci goto out; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci inode_lock(lower_inode); 107262306a36Sopenharmony_ci rc = __vfs_getxattr(lower_dentry, lower_inode, name, value, size); 107362306a36Sopenharmony_ci inode_unlock(lower_inode); 107462306a36Sopenharmony_ciout: 107562306a36Sopenharmony_ci return rc; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic ssize_t 107962306a36Sopenharmony_ciecryptfs_getxattr(struct dentry *dentry, struct inode *inode, 108062306a36Sopenharmony_ci const char *name, void *value, size_t size) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), 108362306a36Sopenharmony_ci ecryptfs_inode_to_lower(inode), 108462306a36Sopenharmony_ci name, value, size); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic ssize_t 108862306a36Sopenharmony_ciecryptfs_listxattr(struct dentry *dentry, char *list, size_t size) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci int rc = 0; 109162306a36Sopenharmony_ci struct dentry *lower_dentry; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci lower_dentry = ecryptfs_dentry_to_lower(dentry); 109462306a36Sopenharmony_ci if (!d_inode(lower_dentry)->i_op->listxattr) { 109562306a36Sopenharmony_ci rc = -EOPNOTSUPP; 109662306a36Sopenharmony_ci goto out; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci inode_lock(d_inode(lower_dentry)); 109962306a36Sopenharmony_ci rc = d_inode(lower_dentry)->i_op->listxattr(lower_dentry, list, size); 110062306a36Sopenharmony_ci inode_unlock(d_inode(lower_dentry)); 110162306a36Sopenharmony_ciout: 110262306a36Sopenharmony_ci return rc; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode, 110662306a36Sopenharmony_ci const char *name) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci int rc; 110962306a36Sopenharmony_ci struct dentry *lower_dentry; 111062306a36Sopenharmony_ci struct inode *lower_inode; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci lower_dentry = ecryptfs_dentry_to_lower(dentry); 111362306a36Sopenharmony_ci lower_inode = ecryptfs_inode_to_lower(inode); 111462306a36Sopenharmony_ci if (!(lower_inode->i_opflags & IOP_XATTR)) { 111562306a36Sopenharmony_ci rc = -EOPNOTSUPP; 111662306a36Sopenharmony_ci goto out; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci inode_lock(lower_inode); 111962306a36Sopenharmony_ci rc = __vfs_removexattr(&nop_mnt_idmap, lower_dentry, name); 112062306a36Sopenharmony_ci inode_unlock(lower_inode); 112162306a36Sopenharmony_ciout: 112262306a36Sopenharmony_ci return rc; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic int ecryptfs_fileattr_get(struct dentry *dentry, struct fileattr *fa) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci return vfs_fileattr_get(ecryptfs_dentry_to_lower(dentry), fa); 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic int ecryptfs_fileattr_set(struct mnt_idmap *idmap, 113162306a36Sopenharmony_ci struct dentry *dentry, struct fileattr *fa) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 113462306a36Sopenharmony_ci int rc; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci rc = vfs_fileattr_set(&nop_mnt_idmap, lower_dentry, fa); 113762306a36Sopenharmony_ci fsstack_copy_attr_all(d_inode(dentry), d_inode(lower_dentry)); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci return rc; 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_cistatic struct posix_acl *ecryptfs_get_acl(struct mnt_idmap *idmap, 114362306a36Sopenharmony_ci struct dentry *dentry, int type) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci return vfs_get_acl(idmap, ecryptfs_dentry_to_lower(dentry), 114662306a36Sopenharmony_ci posix_acl_xattr_name(type)); 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic int ecryptfs_set_acl(struct mnt_idmap *idmap, 115062306a36Sopenharmony_ci struct dentry *dentry, struct posix_acl *acl, 115162306a36Sopenharmony_ci int type) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci int rc; 115462306a36Sopenharmony_ci struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 115562306a36Sopenharmony_ci struct inode *lower_inode = d_inode(lower_dentry); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci rc = vfs_set_acl(&nop_mnt_idmap, lower_dentry, 115862306a36Sopenharmony_ci posix_acl_xattr_name(type), acl); 115962306a36Sopenharmony_ci if (!rc) 116062306a36Sopenharmony_ci fsstack_copy_attr_all(d_inode(dentry), lower_inode); 116162306a36Sopenharmony_ci return rc; 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ciconst struct inode_operations ecryptfs_symlink_iops = { 116562306a36Sopenharmony_ci .get_link = ecryptfs_get_link, 116662306a36Sopenharmony_ci .permission = ecryptfs_permission, 116762306a36Sopenharmony_ci .setattr = ecryptfs_setattr, 116862306a36Sopenharmony_ci .getattr = ecryptfs_getattr_link, 116962306a36Sopenharmony_ci .listxattr = ecryptfs_listxattr, 117062306a36Sopenharmony_ci}; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ciconst struct inode_operations ecryptfs_dir_iops = { 117362306a36Sopenharmony_ci .create = ecryptfs_create, 117462306a36Sopenharmony_ci .lookup = ecryptfs_lookup, 117562306a36Sopenharmony_ci .link = ecryptfs_link, 117662306a36Sopenharmony_ci .unlink = ecryptfs_unlink, 117762306a36Sopenharmony_ci .symlink = ecryptfs_symlink, 117862306a36Sopenharmony_ci .mkdir = ecryptfs_mkdir, 117962306a36Sopenharmony_ci .rmdir = ecryptfs_rmdir, 118062306a36Sopenharmony_ci .mknod = ecryptfs_mknod, 118162306a36Sopenharmony_ci .rename = ecryptfs_rename, 118262306a36Sopenharmony_ci .permission = ecryptfs_permission, 118362306a36Sopenharmony_ci .setattr = ecryptfs_setattr, 118462306a36Sopenharmony_ci .listxattr = ecryptfs_listxattr, 118562306a36Sopenharmony_ci .fileattr_get = ecryptfs_fileattr_get, 118662306a36Sopenharmony_ci .fileattr_set = ecryptfs_fileattr_set, 118762306a36Sopenharmony_ci .get_acl = ecryptfs_get_acl, 118862306a36Sopenharmony_ci .set_acl = ecryptfs_set_acl, 118962306a36Sopenharmony_ci}; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ciconst struct inode_operations ecryptfs_main_iops = { 119262306a36Sopenharmony_ci .permission = ecryptfs_permission, 119362306a36Sopenharmony_ci .setattr = ecryptfs_setattr, 119462306a36Sopenharmony_ci .getattr = ecryptfs_getattr, 119562306a36Sopenharmony_ci .listxattr = ecryptfs_listxattr, 119662306a36Sopenharmony_ci .fileattr_get = ecryptfs_fileattr_get, 119762306a36Sopenharmony_ci .fileattr_set = ecryptfs_fileattr_set, 119862306a36Sopenharmony_ci .get_acl = ecryptfs_get_acl, 119962306a36Sopenharmony_ci .set_acl = ecryptfs_set_acl, 120062306a36Sopenharmony_ci}; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_cistatic int ecryptfs_xattr_get(const struct xattr_handler *handler, 120362306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 120462306a36Sopenharmony_ci const char *name, void *buffer, size_t size) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci return ecryptfs_getxattr(dentry, inode, name, buffer, size); 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int ecryptfs_xattr_set(const struct xattr_handler *handler, 121062306a36Sopenharmony_ci struct mnt_idmap *idmap, 121162306a36Sopenharmony_ci struct dentry *dentry, struct inode *inode, 121262306a36Sopenharmony_ci const char *name, const void *value, size_t size, 121362306a36Sopenharmony_ci int flags) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci if (value) 121662306a36Sopenharmony_ci return ecryptfs_setxattr(dentry, inode, name, value, size, flags); 121762306a36Sopenharmony_ci else { 121862306a36Sopenharmony_ci BUG_ON(flags != XATTR_REPLACE); 121962306a36Sopenharmony_ci return ecryptfs_removexattr(dentry, inode, name); 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic const struct xattr_handler ecryptfs_xattr_handler = { 122462306a36Sopenharmony_ci .prefix = "", /* match anything */ 122562306a36Sopenharmony_ci .get = ecryptfs_xattr_get, 122662306a36Sopenharmony_ci .set = ecryptfs_xattr_set, 122762306a36Sopenharmony_ci}; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ciconst struct xattr_handler *ecryptfs_xattr_handlers[] = { 123062306a36Sopenharmony_ci &ecryptfs_xattr_handler, 123162306a36Sopenharmony_ci NULL 123262306a36Sopenharmony_ci}; 1233