Commit de7badf1 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs:
  eCryptfs: Extend array bounds for all filename chars
  eCryptfs: Flush file in vma close
  eCryptfs: Prevent file create race condition
parents f10cdea6 0f751e64
...@@ -967,7 +967,7 @@ static void ecryptfs_set_default_crypt_stat_vals( ...@@ -967,7 +967,7 @@ static void ecryptfs_set_default_crypt_stat_vals(
/** /**
* ecryptfs_new_file_context * ecryptfs_new_file_context
* @ecryptfs_dentry: The eCryptfs dentry * @ecryptfs_inode: The eCryptfs inode
* *
* If the crypto context for the file has not yet been established, * If the crypto context for the file has not yet been established,
* this is where we do that. Establishing a new crypto context * this is where we do that. Establishing a new crypto context
...@@ -984,13 +984,13 @@ static void ecryptfs_set_default_crypt_stat_vals( ...@@ -984,13 +984,13 @@ static void ecryptfs_set_default_crypt_stat_vals(
* *
* Returns zero on success; non-zero otherwise * Returns zero on success; non-zero otherwise
*/ */
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) int ecryptfs_new_file_context(struct inode *ecryptfs_inode)
{ {
struct ecryptfs_crypt_stat *crypt_stat = struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat = struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&ecryptfs_superblock_to_private( &ecryptfs_superblock_to_private(
ecryptfs_dentry->d_sb)->mount_crypt_stat; ecryptfs_inode->i_sb)->mount_crypt_stat;
int cipher_name_len; int cipher_name_len;
int rc = 0; int rc = 0;
...@@ -1299,12 +1299,12 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t max, ...@@ -1299,12 +1299,12 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t max,
} }
static int static int
ecryptfs_write_metadata_to_contents(struct dentry *ecryptfs_dentry, ecryptfs_write_metadata_to_contents(struct inode *ecryptfs_inode,
char *virt, size_t virt_len) char *virt, size_t virt_len)
{ {
int rc; int rc;
rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt, rc = ecryptfs_write_lower(ecryptfs_inode, virt,
0, virt_len); 0, virt_len);
if (rc < 0) if (rc < 0)
printk(KERN_ERR "%s: Error attempting to write header " printk(KERN_ERR "%s: Error attempting to write header "
...@@ -1338,7 +1338,8 @@ static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask, ...@@ -1338,7 +1338,8 @@ static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask,
/** /**
* ecryptfs_write_metadata * ecryptfs_write_metadata
* @ecryptfs_dentry: The eCryptfs dentry * @ecryptfs_dentry: The eCryptfs dentry, which should be negative
* @ecryptfs_inode: The newly created eCryptfs inode
* *
* Write the file headers out. This will likely involve a userspace * Write the file headers out. This will likely involve a userspace
* callout, in which the session key is encrypted with one or more * callout, in which the session key is encrypted with one or more
...@@ -1348,10 +1349,11 @@ static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask, ...@@ -1348,10 +1349,11 @@ static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask,
* *
* Returns zero on success; non-zero on error * Returns zero on success; non-zero on error
*/ */
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
struct inode *ecryptfs_inode)
{ {
struct ecryptfs_crypt_stat *crypt_stat = struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
unsigned int order; unsigned int order;
char *virt; char *virt;
size_t virt_len; size_t virt_len;
...@@ -1391,7 +1393,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) ...@@ -1391,7 +1393,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt, rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt,
size); size);
else else
rc = ecryptfs_write_metadata_to_contents(ecryptfs_dentry, virt, rc = ecryptfs_write_metadata_to_contents(ecryptfs_inode, virt,
virt_len); virt_len);
if (rc) { if (rc) {
printk(KERN_ERR "%s: Error writing metadata out to lower file; " printk(KERN_ERR "%s: Error writing metadata out to lower file; "
...@@ -1943,7 +1945,7 @@ static unsigned char *portable_filename_chars = ("-.0123456789ABCD" ...@@ -1943,7 +1945,7 @@ static unsigned char *portable_filename_chars = ("-.0123456789ABCD"
/* We could either offset on every reverse map or just pad some 0x00's /* We could either offset on every reverse map or just pad some 0x00's
* at the front here */ * at the front here */
static const unsigned char filename_rev_map[] = { static const unsigned char filename_rev_map[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */
...@@ -1959,7 +1961,7 @@ static const unsigned char filename_rev_map[] = { ...@@ -1959,7 +1961,7 @@ static const unsigned char filename_rev_map[] = {
0x00, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, /* 103 */ 0x00, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, /* 103 */
0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, /* 111 */ 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, /* 111 */
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, /* 119 */ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, /* 119 */
0x3D, 0x3E, 0x3F 0x3D, 0x3E, 0x3F /* 123 - 255 initialized to 0x00 */
}; };
/** /**
......
...@@ -584,9 +584,10 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat); ...@@ -584,9 +584,10 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode); int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode);
int ecryptfs_encrypt_page(struct page *page); int ecryptfs_encrypt_page(struct page *page);
int ecryptfs_decrypt_page(struct page *page); int ecryptfs_decrypt_page(struct page *page);
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry); int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry,
struct inode *ecryptfs_inode);
int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry); int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry);
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry); int ecryptfs_new_file_context(struct inode *ecryptfs_inode);
void ecryptfs_write_crypt_stat_flags(char *page_virt, void ecryptfs_write_crypt_stat_flags(char *page_virt,
struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_crypt_stat *crypt_stat,
size_t *written); size_t *written);
......
...@@ -139,6 +139,27 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) ...@@ -139,6 +139,27 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
return rc; return rc;
} }
static void ecryptfs_vma_close(struct vm_area_struct *vma)
{
filemap_write_and_wait(vma->vm_file->f_mapping);
}
static const struct vm_operations_struct ecryptfs_file_vm_ops = {
.close = ecryptfs_vma_close,
.fault = filemap_fault,
};
static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
int rc;
rc = generic_file_mmap(file, vma);
if (!rc)
vma->vm_ops = &ecryptfs_file_vm_ops;
return rc;
}
struct kmem_cache *ecryptfs_file_info_cache; struct kmem_cache *ecryptfs_file_info_cache;
/** /**
...@@ -349,7 +370,7 @@ const struct file_operations ecryptfs_main_fops = { ...@@ -349,7 +370,7 @@ const struct file_operations ecryptfs_main_fops = {
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_ioctl = ecryptfs_compat_ioctl, .compat_ioctl = ecryptfs_compat_ioctl,
#endif #endif
.mmap = generic_file_mmap, .mmap = ecryptfs_file_mmap,
.open = ecryptfs_open, .open = ecryptfs_open,
.flush = ecryptfs_flush, .flush = ecryptfs_flush,
.release = ecryptfs_release, .release = ecryptfs_release,
......
...@@ -172,22 +172,23 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, ...@@ -172,22 +172,23 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
* it. It will also update the eCryptfs directory inode to mimic the * it. It will also update the eCryptfs directory inode to mimic the
* stat of the lower directory inode. * stat of the lower directory inode.
* *
* Returns zero on success; non-zero on error condition * Returns the new eCryptfs inode on success; an ERR_PTR on error condition
*/ */
static int static struct inode *
ecryptfs_do_create(struct inode *directory_inode, ecryptfs_do_create(struct inode *directory_inode,
struct dentry *ecryptfs_dentry, int mode) struct dentry *ecryptfs_dentry, int mode)
{ {
int rc; int rc;
struct dentry *lower_dentry; struct dentry *lower_dentry;
struct dentry *lower_dir_dentry; struct dentry *lower_dir_dentry;
struct inode *inode;
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
lower_dir_dentry = lock_parent(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry);
if (IS_ERR(lower_dir_dentry)) { if (IS_ERR(lower_dir_dentry)) {
ecryptfs_printk(KERN_ERR, "Error locking directory of " ecryptfs_printk(KERN_ERR, "Error locking directory of "
"dentry\n"); "dentry\n");
rc = PTR_ERR(lower_dir_dentry); inode = ERR_CAST(lower_dir_dentry);
goto out; goto out;
} }
rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
...@@ -195,20 +196,19 @@ ecryptfs_do_create(struct inode *directory_inode, ...@@ -195,20 +196,19 @@ ecryptfs_do_create(struct inode *directory_inode,
if (rc) { if (rc) {
printk(KERN_ERR "%s: Failure to create dentry in lower fs; " printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
"rc = [%d]\n", __func__, rc); "rc = [%d]\n", __func__, rc);
inode = ERR_PTR(rc);
goto out_lock; goto out_lock;
} }
rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, inode = __ecryptfs_get_inode(lower_dentry->d_inode,
directory_inode->i_sb); directory_inode->i_sb);
if (rc) { if (IS_ERR(inode))
ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
goto out_lock; goto out_lock;
}
fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
out_lock: out_lock:
unlock_dir(lower_dir_dentry); unlock_dir(lower_dir_dentry);
out: out:
return rc; return inode;
} }
/** /**
...@@ -219,26 +219,26 @@ ecryptfs_do_create(struct inode *directory_inode, ...@@ -219,26 +219,26 @@ ecryptfs_do_create(struct inode *directory_inode,
* *
* Returns zero on success * Returns zero on success
*/ */
static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
struct inode *ecryptfs_inode)
{ {
struct ecryptfs_crypt_stat *crypt_stat = struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
int rc = 0; int rc = 0;
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { if (S_ISDIR(ecryptfs_inode->i_mode)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
goto out; goto out;
} }
ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");
rc = ecryptfs_new_file_context(ecryptfs_dentry); rc = ecryptfs_new_file_context(ecryptfs_inode);
if (rc) { if (rc) {
ecryptfs_printk(KERN_ERR, "Error creating new file " ecryptfs_printk(KERN_ERR, "Error creating new file "
"context; rc = [%d]\n", rc); "context; rc = [%d]\n", rc);
goto out; goto out;
} }
rc = ecryptfs_get_lower_file(ecryptfs_dentry, rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode);
ecryptfs_dentry->d_inode);
if (rc) { if (rc) {
printk(KERN_ERR "%s: Error attempting to initialize " printk(KERN_ERR "%s: Error attempting to initialize "
"the lower file for the dentry with name " "the lower file for the dentry with name "
...@@ -246,10 +246,10 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) ...@@ -246,10 +246,10 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
ecryptfs_dentry->d_name.name, rc); ecryptfs_dentry->d_name.name, rc);
goto out; goto out;
} }
rc = ecryptfs_write_metadata(ecryptfs_dentry); rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode);
if (rc) if (rc)
printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc);
ecryptfs_put_lower_file(ecryptfs_dentry->d_inode); ecryptfs_put_lower_file(ecryptfs_inode);
out: out:
return rc; return rc;
} }
...@@ -269,18 +269,28 @@ static int ...@@ -269,18 +269,28 @@ static int
ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
int mode, struct nameidata *nd) int mode, struct nameidata *nd)
{ {
struct inode *ecryptfs_inode;
int rc; int rc;
/* ecryptfs_do_create() calls ecryptfs_interpose() */ ecryptfs_inode = ecryptfs_do_create(directory_inode, ecryptfs_dentry,
rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode); mode);
if (unlikely(rc)) { if (unlikely(IS_ERR(ecryptfs_inode))) {
ecryptfs_printk(KERN_WARNING, "Failed to create file in" ecryptfs_printk(KERN_WARNING, "Failed to create file in"
"lower filesystem\n"); "lower filesystem\n");
rc = PTR_ERR(ecryptfs_inode);
goto out; goto out;
} }
/* At this point, a file exists on "disk"; we need to make sure /* 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 */ * that this on disk file is prepared to be an ecryptfs file */
rc = ecryptfs_initialize_file(ecryptfs_dentry); rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);
if (rc) {
drop_nlink(ecryptfs_inode);
unlock_new_inode(ecryptfs_inode);
iput(ecryptfs_inode);
goto out;
}
d_instantiate(ecryptfs_dentry, ecryptfs_inode);
unlock_new_inode(ecryptfs_inode);
out: out:
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment