/** * ecryptfs_copy_up_encrypted_with_header * @page: Sort of a ``virtual'' representation of the encrypted lower * file. The actual lower file does not have the metadata in * the header. This is locked. * @crypt_stat: The eCryptfs inode's cryptographic context * * The ``view'' is the version of the file that userspace winds up * seeing, with the header information inserted. */ static int ecryptfs_copy_up_encrypted_with_header(struct page *page, struct ecryptfs_crypt_stat *crypt_stat) { loff_t extent_num_in_page = 0; loff_t num_extents_per_page = (PAGE_CACHE_SIZE / crypt_stat->extent_size); int rc = 0; while (extent_num_in_page < num_extents_per_page) { loff_t view_extent_num = ((((loff_t)page->index) * num_extents_per_page) + extent_num_in_page); size_t num_header_extents_at_front = (crypt_stat->metadata_size / crypt_stat->extent_size); if (view_extent_num < num_header_extents_at_front) { /* This is a header extent */ char *page_virt; page_virt = kmap_atomic(page); memset(page_virt, 0, PAGE_CACHE_SIZE); /* TODO: Support more than one header extent */ if (view_extent_num == 0) { size_t written; rc = ecryptfs_read_xattr_region( page_virt, page->mapping->host); strip_xattr_flag(page_virt + 16, crypt_stat); ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); } kunmap_atomic(page_virt); flush_dcache_page(page); if (rc) { printk(KERN_ERR "%s: Error reading xattr " "region; rc = [%d]\n", __func__, rc); goto out; } } else { /* This is an encrypted data extent */ loff_t lower_offset = ((view_extent_num * crypt_stat->extent_size) - crypt_stat->metadata_size); rc = ecryptfs_read_lower_page_segment( page, (lower_offset >> PAGE_CACHE_SHIFT), (lower_offset & ~PAGE_CACHE_MASK), crypt_stat->extent_size, page->mapping->host); if (rc) { printk(KERN_ERR "%s: Error attempting to read " "extent at offset [%lld] in the lower " "file; rc = [%d]\n", __func__, lower_offset, rc); goto out; } } extent_num_in_page++; } out: return rc; }
/** * ecryptfs_writepage * @page: Page that is locked before this call is made * * Returns zero on success; non-zero otherwise * * 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_writepage(struct page *page, struct writeback_control *wbc) { #ifndef CONFIG_CRYPTO_DEV_KFIPS int rc; #else struct ecryptfs_page_crypt_req *page_crypt_req; int rc = 0; #endif #ifdef FEATURE_SDCARD_ENCRYPTION struct inode *ecryptfs_inode; struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat; ecryptfs_inode = page->mapping->host; #endif #ifdef FEATURE_SDCARD_ENCRYPTION if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { ecryptfs_printk(KERN_DEBUG, "Passing through unencrypted page\n"); rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0, PAGE_CACHE_SIZE); if (rc) { ClearPageUptodate(page); goto out; } SetPageUptodate(page); } else { #ifndef CONFIG_CRYPTO_DEV_KFIPS rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " "page (upper index [0x%.16lx])\n", page->index); ClearPageUptodate(page); #else // rc = ecryptfs_encrypt_page(page); // if (rc) { // ecryptfs_printk(KERN_WARNING, "Error encrypting " // "page (upper index [0x%.16lx])\n", page->index); // ClearPageUptodate(page); page_crypt_req = ecryptfs_alloc_page_crypt_req( page, ecryptfs_writepage_complete); if (unlikely(!page_crypt_req)) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Failed to allocate page crypt request " "for encryption\n"); #endif goto out; } #ifndef CONFIG_CRYPTO_DEV_KFIPS SetPageUptodate(page); #else // SetPageUptodate(page); set_page_writeback(page); ecryptfs_encrypt_page_async(page_crypt_req); #endif } #else rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " "page (upper index [0x%.16lx])\n", page->index); ClearPageUptodate(page); goto out; } SetPageUptodate(page); #endif out: unlock_page(page); return rc; } static void strip_xattr_flag(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { size_t written; crypt_stat->flags &= ~ECRYPTFS_METADATA_IN_XATTR; ecryptfs_write_crypt_stat_flags(page_virt, crypt_stat, &written); crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } } /** * 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 */ /** * ecryptfs_copy_up_encrypted_with_header * @page: Sort of a ``virtual'' representation of the encrypted lower * file. The actual lower file does not have the metadata in * the header. This is locked. * @crypt_stat: The eCryptfs inode's cryptographic context * * The ``view'' is the version of the file that userspace winds up * seeing, with the header information inserted. */ static int ecryptfs_copy_up_encrypted_with_header(struct page *page, struct ecryptfs_crypt_stat *crypt_stat) { loff_t extent_num_in_page = 0; loff_t num_extents_per_page = (PAGE_CACHE_SIZE / crypt_stat->extent_size); int rc = 0; while (extent_num_in_page < num_extents_per_page) { loff_t view_extent_num = ((((loff_t)page->index) * num_extents_per_page) + extent_num_in_page); size_t num_header_extents_at_front = (crypt_stat->metadata_size / crypt_stat->extent_size); if (view_extent_num < num_header_extents_at_front) { /* This is a header extent */ char *page_virt; page_virt = kmap_atomic(page); memset(page_virt, 0, PAGE_CACHE_SIZE); /* TODO: Support more than one header extent */ if (view_extent_num == 0) { size_t written; rc = ecryptfs_read_xattr_region( page_virt, page->mapping->host); strip_xattr_flag(page_virt + 16, crypt_stat); ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); } kunmap_atomic(page_virt); flush_dcache_page(page); if (rc) { printk(KERN_ERR "%s: Error reading xattr " "region; rc = [%d]\n", __func__, rc); goto out; } } else { /* This is an encrypted data extent */ loff_t lower_offset = ((view_extent_num * crypt_stat->extent_size) - crypt_stat->metadata_size); rc = ecryptfs_read_lower_page_segment( page, (lower_offset >> PAGE_CACHE_SHIFT), (lower_offset & ~PAGE_CACHE_MASK), crypt_stat->extent_size, page->mapping->host); if (rc) { printk(KERN_ERR "%s: Error attempting to read " "extent at offset [%lld] in the lower " "file; rc = [%d]\n", __func__, lower_offset, rc); goto out; } } extent_num_in_page++; } out: return rc; }