18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer
48c2ecf20Sopenharmony_ci * This is where eCryptfs coordinates the symmetric encryption and
58c2ecf20Sopenharmony_ci * decryption of the file data as it passes between the lower
68c2ecf20Sopenharmony_ci * encrypted file and the upper decrypted file.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 1997-2003 Erez Zadok
98c2ecf20Sopenharmony_ci * Copyright (C) 2001-2003 Stony Brook University
108c2ecf20Sopenharmony_ci * Copyright (C) 2004-2007 International Business Machines Corp.
118c2ecf20Sopenharmony_ci *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
158c2ecf20Sopenharmony_ci#include <linux/writeback.h>
168c2ecf20Sopenharmony_ci#include <linux/page-flags.h>
178c2ecf20Sopenharmony_ci#include <linux/mount.h>
188c2ecf20Sopenharmony_ci#include <linux/file.h>
198c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/xattr.h>
228c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
238c2ecf20Sopenharmony_ci#include "ecryptfs_kernel.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/**
268c2ecf20Sopenharmony_ci * ecryptfs_get_locked_page
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * Get one page from cache or lower f/s, return error otherwise.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * Returns locked and up-to-date page (if ok), with increased
318c2ecf20Sopenharmony_ci * refcnt.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_cistruct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct page *page = read_mapping_page(inode->i_mapping, index, NULL);
368c2ecf20Sopenharmony_ci	if (!IS_ERR(page))
378c2ecf20Sopenharmony_ci		lock_page(page);
388c2ecf20Sopenharmony_ci	return page;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/**
428c2ecf20Sopenharmony_ci * ecryptfs_writepage
438c2ecf20Sopenharmony_ci * @page: Page that is locked before this call is made
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * This is where we encrypt the data and pass the encrypted data to
488c2ecf20Sopenharmony_ci * the lower filesystem.  In OpenPGP-compatible mode, we operate on
498c2ecf20Sopenharmony_ci * entire underlying packets.
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistatic int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int rc;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	rc = ecryptfs_encrypt_page(page);
568c2ecf20Sopenharmony_ci	if (rc) {
578c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Error encrypting "
588c2ecf20Sopenharmony_ci				"page (upper index [0x%.16lx])\n", page->index);
598c2ecf20Sopenharmony_ci		ClearPageUptodate(page);
608c2ecf20Sopenharmony_ci		goto out;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	SetPageUptodate(page);
638c2ecf20Sopenharmony_ciout:
648c2ecf20Sopenharmony_ci	unlock_page(page);
658c2ecf20Sopenharmony_ci	return rc;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic void strip_xattr_flag(char *page_virt,
698c2ecf20Sopenharmony_ci			     struct ecryptfs_crypt_stat *crypt_stat)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
728c2ecf20Sopenharmony_ci		size_t written;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		crypt_stat->flags &= ~ECRYPTFS_METADATA_IN_XATTR;
758c2ecf20Sopenharmony_ci		ecryptfs_write_crypt_stat_flags(page_virt, crypt_stat,
768c2ecf20Sopenharmony_ci						&written);
778c2ecf20Sopenharmony_ci		crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/**
828c2ecf20Sopenharmony_ci *   Header Extent:
838c2ecf20Sopenharmony_ci *     Octets 0-7:        Unencrypted file size (big-endian)
848c2ecf20Sopenharmony_ci *     Octets 8-15:       eCryptfs special marker
858c2ecf20Sopenharmony_ci *     Octets 16-19:      Flags
868c2ecf20Sopenharmony_ci *      Octet 16:         File format version number (between 0 and 255)
878c2ecf20Sopenharmony_ci *      Octets 17-18:     Reserved
888c2ecf20Sopenharmony_ci *      Octet 19:         Bit 1 (lsb): Reserved
898c2ecf20Sopenharmony_ci *                        Bit 2: Encrypted?
908c2ecf20Sopenharmony_ci *                        Bits 3-8: Reserved
918c2ecf20Sopenharmony_ci *     Octets 20-23:      Header extent size (big-endian)
928c2ecf20Sopenharmony_ci *     Octets 24-25:      Number of header extents at front of file
938c2ecf20Sopenharmony_ci *                        (big-endian)
948c2ecf20Sopenharmony_ci *     Octet  26:         Begin RFC 2440 authentication token packet set
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci * ecryptfs_copy_up_encrypted_with_header
998c2ecf20Sopenharmony_ci * @page: Sort of a ``virtual'' representation of the encrypted lower
1008c2ecf20Sopenharmony_ci *        file. The actual lower file does not have the metadata in
1018c2ecf20Sopenharmony_ci *        the header. This is locked.
1028c2ecf20Sopenharmony_ci * @crypt_stat: The eCryptfs inode's cryptographic context
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * The ``view'' is the version of the file that userspace winds up
1058c2ecf20Sopenharmony_ci * seeing, with the header information inserted.
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_cistatic int
1088c2ecf20Sopenharmony_ciecryptfs_copy_up_encrypted_with_header(struct page *page,
1098c2ecf20Sopenharmony_ci				       struct ecryptfs_crypt_stat *crypt_stat)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	loff_t extent_num_in_page = 0;
1128c2ecf20Sopenharmony_ci	loff_t num_extents_per_page = (PAGE_SIZE
1138c2ecf20Sopenharmony_ci				       / crypt_stat->extent_size);
1148c2ecf20Sopenharmony_ci	int rc = 0;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	while (extent_num_in_page < num_extents_per_page) {
1178c2ecf20Sopenharmony_ci		loff_t view_extent_num = ((((loff_t)page->index)
1188c2ecf20Sopenharmony_ci					   * num_extents_per_page)
1198c2ecf20Sopenharmony_ci					  + extent_num_in_page);
1208c2ecf20Sopenharmony_ci		size_t num_header_extents_at_front =
1218c2ecf20Sopenharmony_ci			(crypt_stat->metadata_size / crypt_stat->extent_size);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		if (view_extent_num < num_header_extents_at_front) {
1248c2ecf20Sopenharmony_ci			/* This is a header extent */
1258c2ecf20Sopenharmony_ci			char *page_virt;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci			page_virt = kmap_atomic(page);
1288c2ecf20Sopenharmony_ci			memset(page_virt, 0, PAGE_SIZE);
1298c2ecf20Sopenharmony_ci			/* TODO: Support more than one header extent */
1308c2ecf20Sopenharmony_ci			if (view_extent_num == 0) {
1318c2ecf20Sopenharmony_ci				size_t written;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci				rc = ecryptfs_read_xattr_region(
1348c2ecf20Sopenharmony_ci					page_virt, page->mapping->host);
1358c2ecf20Sopenharmony_ci				strip_xattr_flag(page_virt + 16, crypt_stat);
1368c2ecf20Sopenharmony_ci				ecryptfs_write_header_metadata(page_virt + 20,
1378c2ecf20Sopenharmony_ci							       crypt_stat,
1388c2ecf20Sopenharmony_ci							       &written);
1398c2ecf20Sopenharmony_ci			}
1408c2ecf20Sopenharmony_ci			kunmap_atomic(page_virt);
1418c2ecf20Sopenharmony_ci			flush_dcache_page(page);
1428c2ecf20Sopenharmony_ci			if (rc) {
1438c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Error reading xattr "
1448c2ecf20Sopenharmony_ci				       "region; rc = [%d]\n", __func__, rc);
1458c2ecf20Sopenharmony_ci				goto out;
1468c2ecf20Sopenharmony_ci			}
1478c2ecf20Sopenharmony_ci		} else {
1488c2ecf20Sopenharmony_ci			/* This is an encrypted data extent */
1498c2ecf20Sopenharmony_ci			loff_t lower_offset =
1508c2ecf20Sopenharmony_ci				((view_extent_num * crypt_stat->extent_size)
1518c2ecf20Sopenharmony_ci				 - crypt_stat->metadata_size);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci			rc = ecryptfs_read_lower_page_segment(
1548c2ecf20Sopenharmony_ci				page, (lower_offset >> PAGE_SHIFT),
1558c2ecf20Sopenharmony_ci				(lower_offset & ~PAGE_MASK),
1568c2ecf20Sopenharmony_ci				crypt_stat->extent_size, page->mapping->host);
1578c2ecf20Sopenharmony_ci			if (rc) {
1588c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Error attempting to read "
1598c2ecf20Sopenharmony_ci				       "extent at offset [%lld] in the lower "
1608c2ecf20Sopenharmony_ci				       "file; rc = [%d]\n", __func__,
1618c2ecf20Sopenharmony_ci				       lower_offset, rc);
1628c2ecf20Sopenharmony_ci				goto out;
1638c2ecf20Sopenharmony_ci			}
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci		extent_num_in_page++;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ciout:
1688c2ecf20Sopenharmony_ci	return rc;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/**
1728c2ecf20Sopenharmony_ci * ecryptfs_readpage
1738c2ecf20Sopenharmony_ci * @file: An eCryptfs file
1748c2ecf20Sopenharmony_ci * @page: Page from eCryptfs inode mapping into which to stick the read data
1758c2ecf20Sopenharmony_ci *
1768c2ecf20Sopenharmony_ci * Read in a page, decrypting if necessary.
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_cistatic int ecryptfs_readpage(struct file *file, struct page *page)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct ecryptfs_crypt_stat *crypt_stat =
1838c2ecf20Sopenharmony_ci		&ecryptfs_inode_to_private(page->mapping->host)->crypt_stat;
1848c2ecf20Sopenharmony_ci	int rc = 0;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
1878c2ecf20Sopenharmony_ci		rc = ecryptfs_read_lower_page_segment(page, page->index, 0,
1888c2ecf20Sopenharmony_ci						      PAGE_SIZE,
1898c2ecf20Sopenharmony_ci						      page->mapping->host);
1908c2ecf20Sopenharmony_ci	} else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
1918c2ecf20Sopenharmony_ci		if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
1928c2ecf20Sopenharmony_ci			rc = ecryptfs_copy_up_encrypted_with_header(page,
1938c2ecf20Sopenharmony_ci								    crypt_stat);
1948c2ecf20Sopenharmony_ci			if (rc) {
1958c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Error attempting to copy "
1968c2ecf20Sopenharmony_ci				       "the encrypted content from the lower "
1978c2ecf20Sopenharmony_ci				       "file whilst inserting the metadata "
1988c2ecf20Sopenharmony_ci				       "from the xattr into the header; rc = "
1998c2ecf20Sopenharmony_ci				       "[%d]\n", __func__, rc);
2008c2ecf20Sopenharmony_ci				goto out;
2018c2ecf20Sopenharmony_ci			}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		} else {
2048c2ecf20Sopenharmony_ci			rc = ecryptfs_read_lower_page_segment(
2058c2ecf20Sopenharmony_ci				page, page->index, 0, PAGE_SIZE,
2068c2ecf20Sopenharmony_ci				page->mapping->host);
2078c2ecf20Sopenharmony_ci			if (rc) {
2088c2ecf20Sopenharmony_ci				printk(KERN_ERR "Error reading page; rc = "
2098c2ecf20Sopenharmony_ci				       "[%d]\n", rc);
2108c2ecf20Sopenharmony_ci				goto out;
2118c2ecf20Sopenharmony_ci			}
2128c2ecf20Sopenharmony_ci		}
2138c2ecf20Sopenharmony_ci	} else {
2148c2ecf20Sopenharmony_ci		rc = ecryptfs_decrypt_page(page);
2158c2ecf20Sopenharmony_ci		if (rc) {
2168c2ecf20Sopenharmony_ci			ecryptfs_printk(KERN_ERR, "Error decrypting page; "
2178c2ecf20Sopenharmony_ci					"rc = [%d]\n", rc);
2188c2ecf20Sopenharmony_ci			goto out;
2198c2ecf20Sopenharmony_ci		}
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ciout:
2228c2ecf20Sopenharmony_ci	if (rc)
2238c2ecf20Sopenharmony_ci		ClearPageUptodate(page);
2248c2ecf20Sopenharmony_ci	else
2258c2ecf20Sopenharmony_ci		SetPageUptodate(page);
2268c2ecf20Sopenharmony_ci	ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16lx]\n",
2278c2ecf20Sopenharmony_ci			page->index);
2288c2ecf20Sopenharmony_ci	unlock_page(page);
2298c2ecf20Sopenharmony_ci	return rc;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci/**
2338c2ecf20Sopenharmony_ci * Called with lower inode mutex held.
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_cistatic int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct inode *inode = page->mapping->host;
2388c2ecf20Sopenharmony_ci	int end_byte_in_page;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if ((i_size_read(inode) / PAGE_SIZE) != page->index)
2418c2ecf20Sopenharmony_ci		goto out;
2428c2ecf20Sopenharmony_ci	end_byte_in_page = i_size_read(inode) % PAGE_SIZE;
2438c2ecf20Sopenharmony_ci	if (to > end_byte_in_page)
2448c2ecf20Sopenharmony_ci		end_byte_in_page = to;
2458c2ecf20Sopenharmony_ci	zero_user_segment(page, end_byte_in_page, PAGE_SIZE);
2468c2ecf20Sopenharmony_ciout:
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/**
2518c2ecf20Sopenharmony_ci * ecryptfs_write_begin
2528c2ecf20Sopenharmony_ci * @file: The eCryptfs file
2538c2ecf20Sopenharmony_ci * @mapping: The eCryptfs object
2548c2ecf20Sopenharmony_ci * @pos: The file offset at which to start writing
2558c2ecf20Sopenharmony_ci * @len: Length of the write
2568c2ecf20Sopenharmony_ci * @flags: Various flags
2578c2ecf20Sopenharmony_ci * @pagep: Pointer to return the page
2588c2ecf20Sopenharmony_ci * @fsdata: Pointer to return fs data (unused)
2598c2ecf20Sopenharmony_ci *
2608c2ecf20Sopenharmony_ci * This function must zero any hole we create
2618c2ecf20Sopenharmony_ci *
2628c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
2638c2ecf20Sopenharmony_ci */
2648c2ecf20Sopenharmony_cistatic int ecryptfs_write_begin(struct file *file,
2658c2ecf20Sopenharmony_ci			struct address_space *mapping,
2668c2ecf20Sopenharmony_ci			loff_t pos, unsigned len, unsigned flags,
2678c2ecf20Sopenharmony_ci			struct page **pagep, void **fsdata)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	pgoff_t index = pos >> PAGE_SHIFT;
2708c2ecf20Sopenharmony_ci	struct page *page;
2718c2ecf20Sopenharmony_ci	loff_t prev_page_end_size;
2728c2ecf20Sopenharmony_ci	int rc = 0;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	page = grab_cache_page_write_begin(mapping, index, flags);
2758c2ecf20Sopenharmony_ci	if (!page)
2768c2ecf20Sopenharmony_ci		return -ENOMEM;
2778c2ecf20Sopenharmony_ci	*pagep = page;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	prev_page_end_size = ((loff_t)index << PAGE_SHIFT);
2808c2ecf20Sopenharmony_ci	if (!PageUptodate(page)) {
2818c2ecf20Sopenharmony_ci		struct ecryptfs_crypt_stat *crypt_stat =
2828c2ecf20Sopenharmony_ci			&ecryptfs_inode_to_private(mapping->host)->crypt_stat;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
2858c2ecf20Sopenharmony_ci			rc = ecryptfs_read_lower_page_segment(
2868c2ecf20Sopenharmony_ci				page, index, 0, PAGE_SIZE, mapping->host);
2878c2ecf20Sopenharmony_ci			if (rc) {
2888c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Error attempting to read "
2898c2ecf20Sopenharmony_ci				       "lower page segment; rc = [%d]\n",
2908c2ecf20Sopenharmony_ci				       __func__, rc);
2918c2ecf20Sopenharmony_ci				ClearPageUptodate(page);
2928c2ecf20Sopenharmony_ci				goto out;
2938c2ecf20Sopenharmony_ci			} else
2948c2ecf20Sopenharmony_ci				SetPageUptodate(page);
2958c2ecf20Sopenharmony_ci		} else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) {
2968c2ecf20Sopenharmony_ci			if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
2978c2ecf20Sopenharmony_ci				rc = ecryptfs_copy_up_encrypted_with_header(
2988c2ecf20Sopenharmony_ci					page, crypt_stat);
2998c2ecf20Sopenharmony_ci				if (rc) {
3008c2ecf20Sopenharmony_ci					printk(KERN_ERR "%s: Error attempting "
3018c2ecf20Sopenharmony_ci					       "to copy the encrypted content "
3028c2ecf20Sopenharmony_ci					       "from the lower file whilst "
3038c2ecf20Sopenharmony_ci					       "inserting the metadata from "
3048c2ecf20Sopenharmony_ci					       "the xattr into the header; rc "
3058c2ecf20Sopenharmony_ci					       "= [%d]\n", __func__, rc);
3068c2ecf20Sopenharmony_ci					ClearPageUptodate(page);
3078c2ecf20Sopenharmony_ci					goto out;
3088c2ecf20Sopenharmony_ci				}
3098c2ecf20Sopenharmony_ci				SetPageUptodate(page);
3108c2ecf20Sopenharmony_ci			} else {
3118c2ecf20Sopenharmony_ci				rc = ecryptfs_read_lower_page_segment(
3128c2ecf20Sopenharmony_ci					page, index, 0, PAGE_SIZE,
3138c2ecf20Sopenharmony_ci					mapping->host);
3148c2ecf20Sopenharmony_ci				if (rc) {
3158c2ecf20Sopenharmony_ci					printk(KERN_ERR "%s: Error reading "
3168c2ecf20Sopenharmony_ci					       "page; rc = [%d]\n",
3178c2ecf20Sopenharmony_ci					       __func__, rc);
3188c2ecf20Sopenharmony_ci					ClearPageUptodate(page);
3198c2ecf20Sopenharmony_ci					goto out;
3208c2ecf20Sopenharmony_ci				}
3218c2ecf20Sopenharmony_ci				SetPageUptodate(page);
3228c2ecf20Sopenharmony_ci			}
3238c2ecf20Sopenharmony_ci		} else {
3248c2ecf20Sopenharmony_ci			if (prev_page_end_size
3258c2ecf20Sopenharmony_ci			    >= i_size_read(page->mapping->host)) {
3268c2ecf20Sopenharmony_ci				zero_user(page, 0, PAGE_SIZE);
3278c2ecf20Sopenharmony_ci				SetPageUptodate(page);
3288c2ecf20Sopenharmony_ci			} else if (len < PAGE_SIZE) {
3298c2ecf20Sopenharmony_ci				rc = ecryptfs_decrypt_page(page);
3308c2ecf20Sopenharmony_ci				if (rc) {
3318c2ecf20Sopenharmony_ci					printk(KERN_ERR "%s: Error decrypting "
3328c2ecf20Sopenharmony_ci					       "page at index [%ld]; "
3338c2ecf20Sopenharmony_ci					       "rc = [%d]\n",
3348c2ecf20Sopenharmony_ci					       __func__, page->index, rc);
3358c2ecf20Sopenharmony_ci					ClearPageUptodate(page);
3368c2ecf20Sopenharmony_ci					goto out;
3378c2ecf20Sopenharmony_ci				}
3388c2ecf20Sopenharmony_ci				SetPageUptodate(page);
3398c2ecf20Sopenharmony_ci			}
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci	/* If creating a page or more of holes, zero them out via truncate.
3438c2ecf20Sopenharmony_ci	 * Note, this will increase i_size. */
3448c2ecf20Sopenharmony_ci	if (index != 0) {
3458c2ecf20Sopenharmony_ci		if (prev_page_end_size > i_size_read(page->mapping->host)) {
3468c2ecf20Sopenharmony_ci			rc = ecryptfs_truncate(file->f_path.dentry,
3478c2ecf20Sopenharmony_ci					       prev_page_end_size);
3488c2ecf20Sopenharmony_ci			if (rc) {
3498c2ecf20Sopenharmony_ci				printk(KERN_ERR "%s: Error on attempt to "
3508c2ecf20Sopenharmony_ci				       "truncate to (higher) offset [%lld];"
3518c2ecf20Sopenharmony_ci				       " rc = [%d]\n", __func__,
3528c2ecf20Sopenharmony_ci				       prev_page_end_size, rc);
3538c2ecf20Sopenharmony_ci				goto out;
3548c2ecf20Sopenharmony_ci			}
3558c2ecf20Sopenharmony_ci		}
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	/* Writing to a new page, and creating a small hole from start
3588c2ecf20Sopenharmony_ci	 * of page?  Zero it out. */
3598c2ecf20Sopenharmony_ci	if ((i_size_read(mapping->host) == prev_page_end_size)
3608c2ecf20Sopenharmony_ci	    && (pos != 0))
3618c2ecf20Sopenharmony_ci		zero_user(page, 0, PAGE_SIZE);
3628c2ecf20Sopenharmony_ciout:
3638c2ecf20Sopenharmony_ci	if (unlikely(rc)) {
3648c2ecf20Sopenharmony_ci		unlock_page(page);
3658c2ecf20Sopenharmony_ci		put_page(page);
3668c2ecf20Sopenharmony_ci		*pagep = NULL;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci	return rc;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci/**
3728c2ecf20Sopenharmony_ci * ecryptfs_write_inode_size_to_header
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * Writes the lower file size to the first 8 bytes of the header.
3758c2ecf20Sopenharmony_ci *
3768c2ecf20Sopenharmony_ci * Returns zero on success; non-zero on error.
3778c2ecf20Sopenharmony_ci */
3788c2ecf20Sopenharmony_cistatic int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	char *file_size_virt;
3818c2ecf20Sopenharmony_ci	int rc;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL);
3848c2ecf20Sopenharmony_ci	if (!file_size_virt) {
3858c2ecf20Sopenharmony_ci		rc = -ENOMEM;
3868c2ecf20Sopenharmony_ci		goto out;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci	put_unaligned_be64(i_size_read(ecryptfs_inode), file_size_virt);
3898c2ecf20Sopenharmony_ci	rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0,
3908c2ecf20Sopenharmony_ci				  sizeof(u64));
3918c2ecf20Sopenharmony_ci	kfree(file_size_virt);
3928c2ecf20Sopenharmony_ci	if (rc < 0)
3938c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error writing file size to header; "
3948c2ecf20Sopenharmony_ci		       "rc = [%d]\n", __func__, rc);
3958c2ecf20Sopenharmony_ci	else
3968c2ecf20Sopenharmony_ci		rc = 0;
3978c2ecf20Sopenharmony_ciout:
3988c2ecf20Sopenharmony_ci	return rc;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistruct kmem_cache *ecryptfs_xattr_cache;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	ssize_t size;
4068c2ecf20Sopenharmony_ci	void *xattr_virt;
4078c2ecf20Sopenharmony_ci	struct dentry *lower_dentry =
4088c2ecf20Sopenharmony_ci		ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_path.dentry;
4098c2ecf20Sopenharmony_ci	struct inode *lower_inode = d_inode(lower_dentry);
4108c2ecf20Sopenharmony_ci	int rc;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (!(lower_inode->i_opflags & IOP_XATTR)) {
4138c2ecf20Sopenharmony_ci		printk(KERN_WARNING
4148c2ecf20Sopenharmony_ci		       "No support for setting xattr in lower filesystem\n");
4158c2ecf20Sopenharmony_ci		rc = -ENOSYS;
4168c2ecf20Sopenharmony_ci		goto out;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci	xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL);
4198c2ecf20Sopenharmony_ci	if (!xattr_virt) {
4208c2ecf20Sopenharmony_ci		rc = -ENOMEM;
4218c2ecf20Sopenharmony_ci		goto out;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	inode_lock(lower_inode);
4248c2ecf20Sopenharmony_ci	size = __vfs_getxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
4258c2ecf20Sopenharmony_ci			      xattr_virt, PAGE_SIZE);
4268c2ecf20Sopenharmony_ci	if (size < 0)
4278c2ecf20Sopenharmony_ci		size = 8;
4288c2ecf20Sopenharmony_ci	put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);
4298c2ecf20Sopenharmony_ci	rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
4308c2ecf20Sopenharmony_ci			    xattr_virt, size, 0);
4318c2ecf20Sopenharmony_ci	inode_unlock(lower_inode);
4328c2ecf20Sopenharmony_ci	if (rc)
4338c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error whilst attempting to write inode size "
4348c2ecf20Sopenharmony_ci		       "to lower file xattr; rc = [%d]\n", rc);
4358c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_xattr_cache, xattr_virt);
4368c2ecf20Sopenharmony_ciout:
4378c2ecf20Sopenharmony_ci	return rc;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ciint ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	struct ecryptfs_crypt_stat *crypt_stat;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
4458c2ecf20Sopenharmony_ci	BUG_ON(!(crypt_stat->flags & ECRYPTFS_ENCRYPTED));
4468c2ecf20Sopenharmony_ci	if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
4478c2ecf20Sopenharmony_ci		return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode);
4488c2ecf20Sopenharmony_ci	else
4498c2ecf20Sopenharmony_ci		return ecryptfs_write_inode_size_to_header(ecryptfs_inode);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/**
4538c2ecf20Sopenharmony_ci * ecryptfs_write_end
4548c2ecf20Sopenharmony_ci * @file: The eCryptfs file object
4558c2ecf20Sopenharmony_ci * @mapping: The eCryptfs object
4568c2ecf20Sopenharmony_ci * @pos: The file position
4578c2ecf20Sopenharmony_ci * @len: The length of the data (unused)
4588c2ecf20Sopenharmony_ci * @copied: The amount of data copied
4598c2ecf20Sopenharmony_ci * @page: The eCryptfs page
4608c2ecf20Sopenharmony_ci * @fsdata: The fsdata (unused)
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_cistatic int ecryptfs_write_end(struct file *file,
4638c2ecf20Sopenharmony_ci			struct address_space *mapping,
4648c2ecf20Sopenharmony_ci			loff_t pos, unsigned len, unsigned copied,
4658c2ecf20Sopenharmony_ci			struct page *page, void *fsdata)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	pgoff_t index = pos >> PAGE_SHIFT;
4688c2ecf20Sopenharmony_ci	unsigned from = pos & (PAGE_SIZE - 1);
4698c2ecf20Sopenharmony_ci	unsigned to = from + copied;
4708c2ecf20Sopenharmony_ci	struct inode *ecryptfs_inode = mapping->host;
4718c2ecf20Sopenharmony_ci	struct ecryptfs_crypt_stat *crypt_stat =
4728c2ecf20Sopenharmony_ci		&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
4738c2ecf20Sopenharmony_ci	int rc;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
4768c2ecf20Sopenharmony_ci			"(page w/ index = [0x%.16lx], to = [%d])\n", index, to);
4778c2ecf20Sopenharmony_ci	if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
4788c2ecf20Sopenharmony_ci		rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0,
4798c2ecf20Sopenharmony_ci						       to);
4808c2ecf20Sopenharmony_ci		if (!rc) {
4818c2ecf20Sopenharmony_ci			rc = copied;
4828c2ecf20Sopenharmony_ci			fsstack_copy_inode_size(ecryptfs_inode,
4838c2ecf20Sopenharmony_ci				ecryptfs_inode_to_lower(ecryptfs_inode));
4848c2ecf20Sopenharmony_ci		}
4858c2ecf20Sopenharmony_ci		goto out;
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci	if (!PageUptodate(page)) {
4888c2ecf20Sopenharmony_ci		if (copied < PAGE_SIZE) {
4898c2ecf20Sopenharmony_ci			rc = 0;
4908c2ecf20Sopenharmony_ci			goto out;
4918c2ecf20Sopenharmony_ci		}
4928c2ecf20Sopenharmony_ci		SetPageUptodate(page);
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci	/* Fills in zeros if 'to' goes beyond inode size */
4958c2ecf20Sopenharmony_ci	rc = fill_zeros_to_end_of_page(page, to);
4968c2ecf20Sopenharmony_ci	if (rc) {
4978c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
4988c2ecf20Sopenharmony_ci			"zeros in page with index = [0x%.16lx]\n", index);
4998c2ecf20Sopenharmony_ci		goto out;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	rc = ecryptfs_encrypt_page(page);
5028c2ecf20Sopenharmony_ci	if (rc) {
5038c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
5048c2ecf20Sopenharmony_ci				"index [0x%.16lx])\n", index);
5058c2ecf20Sopenharmony_ci		goto out;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci	if (pos + copied > i_size_read(ecryptfs_inode)) {
5088c2ecf20Sopenharmony_ci		i_size_write(ecryptfs_inode, pos + copied);
5098c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
5108c2ecf20Sopenharmony_ci			"[0x%.16llx]\n",
5118c2ecf20Sopenharmony_ci			(unsigned long long)i_size_read(ecryptfs_inode));
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci	rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
5148c2ecf20Sopenharmony_ci	if (rc)
5158c2ecf20Sopenharmony_ci		printk(KERN_ERR "Error writing inode size to metadata; "
5168c2ecf20Sopenharmony_ci		       "rc = [%d]\n", rc);
5178c2ecf20Sopenharmony_ci	else
5188c2ecf20Sopenharmony_ci		rc = copied;
5198c2ecf20Sopenharmony_ciout:
5208c2ecf20Sopenharmony_ci	unlock_page(page);
5218c2ecf20Sopenharmony_ci	put_page(page);
5228c2ecf20Sopenharmony_ci	return rc;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_cistatic sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
5268c2ecf20Sopenharmony_ci{
5278c2ecf20Sopenharmony_ci	struct inode *lower_inode = ecryptfs_inode_to_lower(mapping->host);
5288c2ecf20Sopenharmony_ci	int ret = bmap(lower_inode, &block);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (ret)
5318c2ecf20Sopenharmony_ci		return 0;
5328c2ecf20Sopenharmony_ci	return block;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ciconst struct address_space_operations ecryptfs_aops = {
5368c2ecf20Sopenharmony_ci	.writepage = ecryptfs_writepage,
5378c2ecf20Sopenharmony_ci	.readpage = ecryptfs_readpage,
5388c2ecf20Sopenharmony_ci	.write_begin = ecryptfs_write_begin,
5398c2ecf20Sopenharmony_ci	.write_end = ecryptfs_write_end,
5408c2ecf20Sopenharmony_ci	.bmap = ecryptfs_bmap,
5418c2ecf20Sopenharmony_ci};
542