|  | /** | 
|  | * eCryptfs: Linux filesystem encryption layer | 
|  | * This is where eCryptfs coordinates the symmetric encryption and | 
|  | * decryption of the file data as it passes between the lower | 
|  | * encrypted file and the upper decrypted file. | 
|  | * | 
|  | * Copyright (C) 1997-2003 Erez Zadok | 
|  | * Copyright (C) 2001-2003 Stony Brook University | 
|  | * Copyright (C) 2004-2007 International Business Machines Corp. | 
|  | *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of the | 
|  | * License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, but | 
|  | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | 
|  | * 02111-1307, USA. | 
|  | */ | 
|  |  | 
|  | #include <linux/pagemap.h> | 
|  | #include <linux/writeback.h> | 
|  | #include <linux/page-flags.h> | 
|  | #include <linux/mount.h> | 
|  | #include <linux/file.h> | 
|  | #include <linux/crypto.h> | 
|  | #include <linux/scatterlist.h> | 
|  | #include "ecryptfs_kernel.h" | 
|  |  | 
|  | struct kmem_cache *ecryptfs_lower_page_cache; | 
|  |  | 
|  | /** | 
|  | * ecryptfs_get1page | 
|  | * | 
|  | * Get one page from cache or lower f/s, return error otherwise. | 
|  | * | 
|  | * Returns unlocked and up-to-date page (if ok), with increased | 
|  | * refcnt. | 
|  | */ | 
|  | static struct page *ecryptfs_get1page(struct file *file, int index) | 
|  | { | 
|  | struct page *page; | 
|  | struct dentry *dentry; | 
|  | struct inode *inode; | 
|  | struct address_space *mapping; | 
|  |  | 
|  | dentry = file->f_path.dentry; | 
|  | inode = dentry->d_inode; | 
|  | mapping = inode->i_mapping; | 
|  | page = read_cache_page(mapping, index, | 
|  | (filler_t *)mapping->a_ops->readpage, | 
|  | (void *)file); | 
|  | if (IS_ERR(page)) | 
|  | goto out; | 
|  | wait_on_page_locked(page); | 
|  | out: | 
|  | return page; | 
|  | } | 
|  |  | 
|  | static | 
|  | int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); | 
|  |  | 
|  | /** | 
|  | * ecryptfs_fill_zeros | 
|  | * @file: The ecryptfs file | 
|  | * @new_length: The new length of the data in the underlying file; | 
|  | *              everything between the prior end of the file and the | 
|  | *              new end of the file will be filled with zero's. | 
|  | *              new_length must be greater than  current length | 
|  | * | 
|  | * Function for handling lseek-ing past the end of the file. | 
|  | * | 
|  | * This function does not support shrinking, only growing a file. | 
|  | * | 
|  | * Returns zero on success; non-zero otherwise. | 
|  | */ | 
|  | int ecryptfs_fill_zeros(struct file *file, loff_t new_length) | 
|  | { | 
|  | int rc = 0; | 
|  | struct dentry *dentry = file->f_path.dentry; | 
|  | struct inode *inode = dentry->d_inode; | 
|  | pgoff_t old_end_page_index = 0; | 
|  | pgoff_t index = old_end_page_index; | 
|  | int old_end_pos_in_page = -1; | 
|  | pgoff_t new_end_page_index; | 
|  | int new_end_pos_in_page; | 
|  | loff_t cur_length = i_size_read(inode); | 
|  |  | 
|  | if (cur_length != 0) { | 
|  | index = old_end_page_index = | 
|  | ((cur_length - 1) >> PAGE_CACHE_SHIFT); | 
|  | old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK); | 
|  | } | 
|  | new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT); | 
|  | new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK); | 
|  | ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; " | 
|  | "old_end_pos_in_page = [%d]; " | 
|  | "new_end_page_index = [0x%.16x]; " | 
|  | "new_end_pos_in_page = [%d]\n", | 
|  | old_end_page_index, old_end_pos_in_page, | 
|  | new_end_page_index, new_end_pos_in_page); | 
|  | if (old_end_page_index == new_end_page_index) { | 
|  | /* Start and end are in the same page; we just need to | 
|  | * set a portion of the existing page to zero's */ | 
|  | rc = write_zeros(file, index, (old_end_pos_in_page + 1), | 
|  | (new_end_pos_in_page - old_end_pos_in_page)); | 
|  | if (rc) | 
|  | ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " | 
|  | "index=[0x%.16x], " | 
|  | "old_end_pos_in_page=[d], " | 
|  | "(PAGE_CACHE_SIZE - new_end_pos_in_page" | 
|  | "=[%d]" | 
|  | ")=[d]) returned [%d]\n", file, index, | 
|  | old_end_pos_in_page, | 
|  | new_end_pos_in_page, | 
|  | (PAGE_CACHE_SIZE - new_end_pos_in_page), | 
|  | rc); | 
|  | goto out; | 
|  | } | 
|  | /* Fill the remainder of the previous last page with zeros */ | 
|  | rc = write_zeros(file, index, (old_end_pos_in_page + 1), | 
|  | ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page)); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " | 
|  | "index=[0x%.16x], old_end_pos_in_page=[d], " | 
|  | "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) " | 
|  | "returned [%d]\n", file, index, | 
|  | old_end_pos_in_page, | 
|  | (PAGE_CACHE_SIZE - old_end_pos_in_page), rc); | 
|  | goto out; | 
|  | } | 
|  | index++; | 
|  | while (index < new_end_page_index) { | 
|  | /* Fill all intermediate pages with zeros */ | 
|  | rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], " | 
|  | "index=[0x%.16x], " | 
|  | "old_end_pos_in_page=[d], " | 
|  | "(PAGE_CACHE_SIZE - new_end_pos_in_page" | 
|  | "=[%d]" | 
|  | ")=[d]) returned [%d]\n", file, index, | 
|  | old_end_pos_in_page, | 
|  | new_end_pos_in_page, | 
|  | (PAGE_CACHE_SIZE - new_end_pos_in_page), | 
|  | rc); | 
|  | goto out; | 
|  | } | 
|  | index++; | 
|  | } | 
|  | /* Fill the portion at the beginning of the last new page with | 
|  | * zero's */ | 
|  | rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1)); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "write_zeros(file=" | 
|  | "[%p], index=[0x%.16x], 0, " | 
|  | "new_end_pos_in_page=[%d]" | 
|  | "returned [%d]\n", file, index, | 
|  | new_end_pos_in_page, rc); | 
|  | goto out; | 
|  | } | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * ecryptfs_writepage | 
|  | * @page: Page that is locked before this call is made | 
|  | * | 
|  | * Returns zero on success; non-zero otherwise | 
|  | */ | 
|  | static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) | 
|  | { | 
|  | struct ecryptfs_page_crypt_context ctx; | 
|  | int rc; | 
|  |  | 
|  | ctx.page = page; | 
|  | ctx.mode = ECRYPTFS_WRITEPAGE_MODE; | 
|  | ctx.param.wbc = wbc; | 
|  | rc = ecryptfs_encrypt_page(&ctx); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_WARNING, "Error encrypting " | 
|  | "page (upper index [0x%.16x])\n", page->index); | 
|  | ClearPageUptodate(page); | 
|  | goto out; | 
|  | } | 
|  | SetPageUptodate(page); | 
|  | unlock_page(page); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Reads the data from the lower file file at index lower_page_index | 
|  | * and copies that data into page. | 
|  | * | 
|  | * @param page	Page to fill | 
|  | * @param lower_page_index Index of the page in the lower file to get | 
|  | */ | 
|  | int ecryptfs_do_readpage(struct file *file, struct page *page, | 
|  | pgoff_t lower_page_index) | 
|  | { | 
|  | int rc; | 
|  | struct dentry *dentry; | 
|  | struct file *lower_file; | 
|  | struct dentry *lower_dentry; | 
|  | struct inode *inode; | 
|  | struct inode *lower_inode; | 
|  | char *page_data; | 
|  | struct page *lower_page = NULL; | 
|  | char *lower_page_data; | 
|  | const struct address_space_operations *lower_a_ops; | 
|  |  | 
|  | dentry = file->f_path.dentry; | 
|  | lower_file = ecryptfs_file_to_lower(file); | 
|  | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 
|  | inode = dentry->d_inode; | 
|  | lower_inode = ecryptfs_inode_to_lower(inode); | 
|  | lower_a_ops = lower_inode->i_mapping->a_ops; | 
|  | lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index, | 
|  | (filler_t *)lower_a_ops->readpage, | 
|  | (void *)lower_file); | 
|  | if (IS_ERR(lower_page)) { | 
|  | rc = PTR_ERR(lower_page); | 
|  | lower_page = NULL; | 
|  | ecryptfs_printk(KERN_ERR, "Error reading from page cache\n"); | 
|  | goto out; | 
|  | } | 
|  | wait_on_page_locked(lower_page); | 
|  | page_data = kmap_atomic(page, KM_USER0); | 
|  | lower_page_data = kmap_atomic(lower_page, KM_USER1); | 
|  | memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); | 
|  | kunmap_atomic(lower_page_data, KM_USER1); | 
|  | kunmap_atomic(page_data, KM_USER0); | 
|  | flush_dcache_page(page); | 
|  | rc = 0; | 
|  | out: | 
|  | if (likely(lower_page)) | 
|  | page_cache_release(lower_page); | 
|  | if (rc == 0) | 
|  | SetPageUptodate(page); | 
|  | else | 
|  | ClearPageUptodate(page); | 
|  | return rc; | 
|  | } | 
|  | /** | 
|  | *   Header Extent: | 
|  | *     Octets 0-7:        Unencrypted file size (big-endian) | 
|  | *     Octets 8-15:       eCryptfs special marker | 
|  | *     Octets 16-19:      Flags | 
|  | *      Octet 16:         File format version number (between 0 and 255) | 
|  | *      Octets 17-18:     Reserved | 
|  | *      Octet 19:         Bit 1 (lsb): Reserved | 
|  | *                        Bit 2: Encrypted? | 
|  | *                        Bits 3-8: Reserved | 
|  | *     Octets 20-23:      Header extent size (big-endian) | 
|  | *     Octets 24-25:      Number of header extents at front of file | 
|  | *                        (big-endian) | 
|  | *     Octet  26:         Begin RFC 2440 authentication token packet set | 
|  | */ | 
|  | static void set_header_info(char *page_virt, | 
|  | struct ecryptfs_crypt_stat *crypt_stat) | 
|  | { | 
|  | size_t written; | 
|  | int save_num_header_extents_at_front = | 
|  | crypt_stat->num_header_extents_at_front; | 
|  |  | 
|  | crypt_stat->num_header_extents_at_front = 1; | 
|  | ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); | 
|  | crypt_stat->num_header_extents_at_front = | 
|  | save_num_header_extents_at_front; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * ecryptfs_readpage | 
|  | * @file: This is an ecryptfs file | 
|  | * @page: ecryptfs associated page to stick the read data into | 
|  | * | 
|  | * Read in a page, decrypting if necessary. | 
|  | * | 
|  | * Returns zero on success; non-zero on error. | 
|  | */ | 
|  | static int ecryptfs_readpage(struct file *file, struct page *page) | 
|  | { | 
|  | int rc = 0; | 
|  | struct ecryptfs_crypt_stat *crypt_stat; | 
|  |  | 
|  | BUG_ON(!(file && file->f_path.dentry && file->f_path.dentry->d_inode)); | 
|  | crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) | 
|  | ->crypt_stat; | 
|  | if (!crypt_stat | 
|  | || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED) | 
|  | || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { | 
|  | ecryptfs_printk(KERN_DEBUG, | 
|  | "Passing through unencrypted page\n"); | 
|  | rc = ecryptfs_do_readpage(file, page, page->index); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "Error reading page; rc = " | 
|  | "[%d]\n", rc); | 
|  | goto out; | 
|  | } | 
|  | } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { | 
|  | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { | 
|  | int num_pages_in_header_region = | 
|  | (crypt_stat->header_extent_size | 
|  | / PAGE_CACHE_SIZE); | 
|  |  | 
|  | if (page->index < num_pages_in_header_region) { | 
|  | char *page_virt; | 
|  |  | 
|  | page_virt = kmap_atomic(page, KM_USER0); | 
|  | memset(page_virt, 0, PAGE_CACHE_SIZE); | 
|  | if (page->index == 0) { | 
|  | rc = ecryptfs_read_xattr_region( | 
|  | page_virt, file->f_path.dentry); | 
|  | set_header_info(page_virt, crypt_stat); | 
|  | } | 
|  | kunmap_atomic(page_virt, KM_USER0); | 
|  | flush_dcache_page(page); | 
|  | if (rc) { | 
|  | printk(KERN_ERR "Error reading xattr " | 
|  | "region\n"); | 
|  | goto out; | 
|  | } | 
|  | } else { | 
|  | rc = ecryptfs_do_readpage( | 
|  | file, page, | 
|  | (page->index | 
|  | - num_pages_in_header_region)); | 
|  | if (rc) { | 
|  | printk(KERN_ERR "Error reading page; " | 
|  | "rc = [%d]\n", rc); | 
|  | goto out; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | rc = ecryptfs_do_readpage(file, page, page->index); | 
|  | if (rc) { | 
|  | printk(KERN_ERR "Error reading page; rc = " | 
|  | "[%d]\n", rc); | 
|  | goto out; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | rc = ecryptfs_decrypt_page(file, page); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "Error decrypting page; " | 
|  | "rc = [%d]\n", rc); | 
|  | goto out; | 
|  | } | 
|  | } | 
|  | SetPageUptodate(page); | 
|  | out: | 
|  | if (rc) | 
|  | ClearPageUptodate(page); | 
|  | ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", | 
|  | page->index); | 
|  | unlock_page(page); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Called with lower inode mutex held. | 
|  | */ | 
|  | static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) | 
|  | { | 
|  | struct inode *inode = page->mapping->host; | 
|  | int end_byte_in_page; | 
|  | char *page_virt; | 
|  |  | 
|  | if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) | 
|  | goto out; | 
|  | end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; | 
|  | if (to > end_byte_in_page) | 
|  | end_byte_in_page = to; | 
|  | page_virt = kmap_atomic(page, KM_USER0); | 
|  | memset((page_virt + end_byte_in_page), 0, | 
|  | (PAGE_CACHE_SIZE - end_byte_in_page)); | 
|  | kunmap_atomic(page_virt, KM_USER0); | 
|  | flush_dcache_page(page); | 
|  | out: | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int ecryptfs_prepare_write(struct file *file, struct page *page, | 
|  | unsigned from, unsigned to) | 
|  | { | 
|  | int rc = 0; | 
|  |  | 
|  | if (from == 0 && to == PAGE_CACHE_SIZE) | 
|  | goto out;	/* If we are writing a full page, it will be | 
|  | up to date. */ | 
|  | if (!PageUptodate(page)) | 
|  | rc = ecryptfs_do_readpage(file, page, page->index); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, | 
|  | struct inode *lower_inode, | 
|  | struct writeback_control *wbc) | 
|  | { | 
|  | int rc = 0; | 
|  |  | 
|  | rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); " | 
|  | "rc = [%d]\n", rc); | 
|  | goto out; | 
|  | } | 
|  | lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; | 
|  | page_cache_release(lower_page); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static | 
|  | void ecryptfs_release_lower_page(struct page *lower_page, int page_locked) | 
|  | { | 
|  | if (page_locked) | 
|  | unlock_page(lower_page); | 
|  | page_cache_release(lower_page); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * ecryptfs_write_inode_size_to_header | 
|  | * | 
|  | * Writes the lower file size to the first 8 bytes of the header. | 
|  | * | 
|  | * Returns zero on success; non-zero on error. | 
|  | */ | 
|  | static int ecryptfs_write_inode_size_to_header(struct file *lower_file, | 
|  | struct inode *lower_inode, | 
|  | struct inode *inode) | 
|  | { | 
|  | int rc = 0; | 
|  | struct page *header_page; | 
|  | char *header_virt; | 
|  | const struct address_space_operations *lower_a_ops; | 
|  | u64 file_size; | 
|  |  | 
|  | header_page = grab_cache_page(lower_inode->i_mapping, 0); | 
|  | if (!header_page) { | 
|  | ecryptfs_printk(KERN_ERR, "grab_cache_page for " | 
|  | "lower_page_index 0 failed\n"); | 
|  | rc = -EINVAL; | 
|  | goto out; | 
|  | } | 
|  | lower_a_ops = lower_inode->i_mapping->a_ops; | 
|  | rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8); | 
|  | if (rc) { | 
|  | if (rc == AOP_TRUNCATED_PAGE) | 
|  | ecryptfs_release_lower_page(header_page, 0); | 
|  | else | 
|  | ecryptfs_release_lower_page(header_page, 1); | 
|  | goto out; | 
|  | } | 
|  | file_size = (u64)i_size_read(inode); | 
|  | ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size); | 
|  | file_size = cpu_to_be64(file_size); | 
|  | header_virt = kmap_atomic(header_page, KM_USER0); | 
|  | memcpy(header_virt, &file_size, sizeof(u64)); | 
|  | kunmap_atomic(header_virt, KM_USER0); | 
|  | flush_dcache_page(header_page); | 
|  | rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8); | 
|  | if (rc < 0) | 
|  | ecryptfs_printk(KERN_ERR, "Error commiting header page " | 
|  | "write\n"); | 
|  | if (rc == AOP_TRUNCATED_PAGE) | 
|  | ecryptfs_release_lower_page(header_page, 0); | 
|  | else | 
|  | ecryptfs_release_lower_page(header_page, 1); | 
|  | lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; | 
|  | mark_inode_dirty_sync(inode); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode, | 
|  | struct inode *inode, | 
|  | struct dentry *ecryptfs_dentry, | 
|  | int lower_i_mutex_held) | 
|  | { | 
|  | ssize_t size; | 
|  | void *xattr_virt; | 
|  | struct dentry *lower_dentry; | 
|  | u64 file_size; | 
|  | int rc; | 
|  |  | 
|  | xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL); | 
|  | if (!xattr_virt) { | 
|  | printk(KERN_ERR "Out of memory whilst attempting to write " | 
|  | "inode size to xattr\n"); | 
|  | rc = -ENOMEM; | 
|  | goto out; | 
|  | } | 
|  | lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); | 
|  | if (!lower_dentry->d_inode->i_op->getxattr) { | 
|  | printk(KERN_WARNING | 
|  | "No support for setting xattr in lower filesystem\n"); | 
|  | rc = -ENOSYS; | 
|  | kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); | 
|  | goto out; | 
|  | } | 
|  | if (!lower_i_mutex_held) | 
|  | mutex_lock(&lower_dentry->d_inode->i_mutex); | 
|  | size = lower_dentry->d_inode->i_op->getxattr(lower_dentry, | 
|  | ECRYPTFS_XATTR_NAME, | 
|  | xattr_virt, | 
|  | PAGE_CACHE_SIZE); | 
|  | if (!lower_i_mutex_held) | 
|  | mutex_unlock(&lower_dentry->d_inode->i_mutex); | 
|  | if (size < 0) | 
|  | size = 8; | 
|  | file_size = (u64)i_size_read(inode); | 
|  | file_size = cpu_to_be64(file_size); | 
|  | memcpy(xattr_virt, &file_size, sizeof(u64)); | 
|  | if (!lower_i_mutex_held) | 
|  | mutex_lock(&lower_dentry->d_inode->i_mutex); | 
|  | rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, | 
|  | ECRYPTFS_XATTR_NAME, | 
|  | xattr_virt, size, 0); | 
|  | if (!lower_i_mutex_held) | 
|  | mutex_unlock(&lower_dentry->d_inode->i_mutex); | 
|  | if (rc) | 
|  | printk(KERN_ERR "Error whilst attempting to write inode size " | 
|  | "to lower file xattr; rc = [%d]\n", rc); | 
|  | kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | int | 
|  | ecryptfs_write_inode_size_to_metadata(struct file *lower_file, | 
|  | struct inode *lower_inode, | 
|  | struct inode *inode, | 
|  | struct dentry *ecryptfs_dentry, | 
|  | int lower_i_mutex_held) | 
|  | { | 
|  | struct ecryptfs_crypt_stat *crypt_stat; | 
|  |  | 
|  | crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; | 
|  | if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) | 
|  | return ecryptfs_write_inode_size_to_xattr(lower_inode, inode, | 
|  | ecryptfs_dentry, | 
|  | lower_i_mutex_held); | 
|  | else | 
|  | return ecryptfs_write_inode_size_to_header(lower_file, | 
|  | lower_inode, | 
|  | inode); | 
|  | } | 
|  |  | 
|  | int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, | 
|  | struct file *lower_file, | 
|  | unsigned long lower_page_index, int byte_offset, | 
|  | int region_bytes) | 
|  | { | 
|  | int rc = 0; | 
|  |  | 
|  | *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); | 
|  | if (!(*lower_page)) { | 
|  | rc = -EINVAL; | 
|  | ecryptfs_printk(KERN_ERR, "Error attempting to grab " | 
|  | "lower page with index [0x%.16x]\n", | 
|  | lower_page_index); | 
|  | goto out; | 
|  | } | 
|  | rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file, | 
|  | (*lower_page), | 
|  | byte_offset, | 
|  | region_bytes); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "prepare_write for " | 
|  | "lower_page_index = [0x%.16x] failed; rc = " | 
|  | "[%d]\n", lower_page_index, rc); | 
|  | } | 
|  | out: | 
|  | if (rc && (*lower_page)) { | 
|  | if (rc == AOP_TRUNCATED_PAGE) | 
|  | ecryptfs_release_lower_page(*lower_page, 0); | 
|  | else | 
|  | ecryptfs_release_lower_page(*lower_page, 1); | 
|  | (*lower_page) = NULL; | 
|  | } | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * ecryptfs_commit_lower_page | 
|  | * | 
|  | * Returns zero on success; non-zero on error | 
|  | */ | 
|  | int | 
|  | ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, | 
|  | struct file *lower_file, int byte_offset, | 
|  | int region_size) | 
|  | { | 
|  | int page_locked = 1; | 
|  | int rc = 0; | 
|  |  | 
|  | rc = lower_inode->i_mapping->a_ops->commit_write( | 
|  | lower_file, lower_page, byte_offset, region_size); | 
|  | if (rc == AOP_TRUNCATED_PAGE) | 
|  | page_locked = 0; | 
|  | if (rc < 0) { | 
|  | ecryptfs_printk(KERN_ERR, | 
|  | "Error committing write; rc = [%d]\n", rc); | 
|  | } else | 
|  | rc = 0; | 
|  | ecryptfs_release_lower_page(lower_page, page_locked); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * ecryptfs_copy_page_to_lower | 
|  | * | 
|  | * Used for plaintext pass-through; no page index interpolation | 
|  | * required. | 
|  | */ | 
|  | int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, | 
|  | struct file *lower_file) | 
|  | { | 
|  | int rc = 0; | 
|  | struct page *lower_page; | 
|  |  | 
|  | rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file, | 
|  | page->index, 0, PAGE_CACHE_SIZE); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "Error attempting to get page " | 
|  | "at index [0x%.16x]\n", page->index); | 
|  | goto out; | 
|  | } | 
|  | /* TODO: aops */ | 
|  | memcpy((char *)page_address(lower_page), page_address(page), | 
|  | PAGE_CACHE_SIZE); | 
|  | rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file, | 
|  | 0, PAGE_CACHE_SIZE); | 
|  | if (rc) | 
|  | ecryptfs_printk(KERN_ERR, "Error attempting to commit page " | 
|  | "at index [0x%.16x]\n", page->index); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | struct kmem_cache *ecryptfs_xattr_cache; | 
|  |  | 
|  | /** | 
|  | * ecryptfs_commit_write | 
|  | * @file: The eCryptfs file object | 
|  | * @page: The eCryptfs page | 
|  | * @from: Ignored (we rotate the page IV on each write) | 
|  | * @to: Ignored | 
|  | * | 
|  | * This is where we encrypt the data and pass the encrypted data to | 
|  | * the lower filesystem.  In OpenPGP-compatible mode, we operate on | 
|  | * entire underlying packets. | 
|  | */ | 
|  | static int ecryptfs_commit_write(struct file *file, struct page *page, | 
|  | unsigned from, unsigned to) | 
|  | { | 
|  | struct ecryptfs_page_crypt_context ctx; | 
|  | loff_t pos; | 
|  | struct inode *inode; | 
|  | struct inode *lower_inode; | 
|  | struct file *lower_file; | 
|  | struct ecryptfs_crypt_stat *crypt_stat; | 
|  | int rc; | 
|  |  | 
|  | inode = page->mapping->host; | 
|  | lower_inode = ecryptfs_inode_to_lower(inode); | 
|  | lower_file = ecryptfs_file_to_lower(file); | 
|  | mutex_lock(&lower_inode->i_mutex); | 
|  | crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) | 
|  | ->crypt_stat; | 
|  | if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { | 
|  | ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " | 
|  | "crypt_stat at memory location [%p]\n", crypt_stat); | 
|  | crypt_stat->flags &= ~(ECRYPTFS_NEW_FILE); | 
|  | } else | 
|  | ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); | 
|  | ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" | 
|  | "(page w/ index = [0x%.16x], to = [%d])\n", page->index, | 
|  | to); | 
|  | rc = fill_zeros_to_end_of_page(page, to); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_WARNING, "Error attempting to fill " | 
|  | "zeros in page with index = [0x%.16x]\n", | 
|  | page->index); | 
|  | goto out; | 
|  | } | 
|  | ctx.page = page; | 
|  | ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE; | 
|  | ctx.param.lower_file = lower_file; | 
|  | rc = ecryptfs_encrypt_page(&ctx); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " | 
|  | "index [0x%.16x])\n", page->index); | 
|  | goto out; | 
|  | } | 
|  | inode->i_blocks = lower_inode->i_blocks; | 
|  | pos = (page->index << PAGE_CACHE_SHIFT) + to; | 
|  | if (pos > i_size_read(inode)) { | 
|  | i_size_write(inode, pos); | 
|  | ecryptfs_printk(KERN_DEBUG, "Expanded file size to " | 
|  | "[0x%.16x]\n", i_size_read(inode)); | 
|  | } | 
|  | rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, | 
|  | inode, file->f_dentry, | 
|  | ECRYPTFS_LOWER_I_MUTEX_HELD); | 
|  | if (rc) | 
|  | printk(KERN_ERR "Error writing inode size to metadata; " | 
|  | "rc = [%d]\n", rc); | 
|  | lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; | 
|  | mark_inode_dirty_sync(inode); | 
|  | out: | 
|  | if (rc < 0) | 
|  | ClearPageUptodate(page); | 
|  | else | 
|  | SetPageUptodate(page); | 
|  | mutex_unlock(&lower_inode->i_mutex); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * write_zeros | 
|  | * @file: The ecryptfs file | 
|  | * @index: The index in which we are writing | 
|  | * @start: The position after the last block of data | 
|  | * @num_zeros: The number of zeros to write | 
|  | * | 
|  | * Write a specified number of zero's to a page. | 
|  | * | 
|  | * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE | 
|  | */ | 
|  | static | 
|  | int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) | 
|  | { | 
|  | int rc = 0; | 
|  | struct page *tmp_page; | 
|  | char *tmp_page_virt; | 
|  |  | 
|  | tmp_page = ecryptfs_get1page(file, index); | 
|  | if (IS_ERR(tmp_page)) { | 
|  | ecryptfs_printk(KERN_ERR, "Error getting page at index " | 
|  | "[0x%.16x]\n", index); | 
|  | rc = PTR_ERR(tmp_page); | 
|  | goto out; | 
|  | } | 
|  | rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros); | 
|  | if (rc) { | 
|  | ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " | 
|  | "to remainder of page at index [0x%.16x]\n", | 
|  | index); | 
|  | page_cache_release(tmp_page); | 
|  | goto out; | 
|  | } | 
|  | tmp_page_virt = kmap_atomic(tmp_page, KM_USER0); | 
|  | memset(((char *)tmp_page_virt + start), 0, num_zeros); | 
|  | kunmap_atomic(tmp_page_virt, KM_USER0); | 
|  | flush_dcache_page(tmp_page); | 
|  | rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); | 
|  | if (rc < 0) { | 
|  | ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " | 
|  | "to remainder of page at index [0x%.16x]\n", | 
|  | index); | 
|  | page_cache_release(tmp_page); | 
|  | goto out; | 
|  | } | 
|  | rc = 0; | 
|  | page_cache_release(tmp_page); | 
|  | out: | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) | 
|  | { | 
|  | int rc = 0; | 
|  | struct inode *inode; | 
|  | struct inode *lower_inode; | 
|  |  | 
|  | inode = (struct inode *)mapping->host; | 
|  | lower_inode = ecryptfs_inode_to_lower(inode); | 
|  | if (lower_inode->i_mapping->a_ops->bmap) | 
|  | rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping, | 
|  | block); | 
|  | return rc; | 
|  | } | 
|  |  | 
|  | static void ecryptfs_sync_page(struct page *page) | 
|  | { | 
|  | struct inode *inode; | 
|  | struct inode *lower_inode; | 
|  | struct page *lower_page; | 
|  |  | 
|  | inode = page->mapping->host; | 
|  | lower_inode = ecryptfs_inode_to_lower(inode); | 
|  | /* NOTE: Recently swapped with grab_cache_page(), since | 
|  | * sync_page() just makes sure that pending I/O gets done. */ | 
|  | lower_page = find_lock_page(lower_inode->i_mapping, page->index); | 
|  | if (!lower_page) { | 
|  | ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n"); | 
|  | return; | 
|  | } | 
|  | lower_page->mapping->a_ops->sync_page(lower_page); | 
|  | ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", | 
|  | lower_page->index); | 
|  | unlock_page(lower_page); | 
|  | page_cache_release(lower_page); | 
|  | } | 
|  |  | 
|  | struct address_space_operations ecryptfs_aops = { | 
|  | .writepage = ecryptfs_writepage, | 
|  | .readpage = ecryptfs_readpage, | 
|  | .prepare_write = ecryptfs_prepare_write, | 
|  | .commit_write = ecryptfs_commit_write, | 
|  | .bmap = ecryptfs_bmap, | 
|  | .sync_page = ecryptfs_sync_page, | 
|  | }; |