xref: /linux/fs/ecryptfs/read_write.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
209d02efaSLee Jones /*
3da0102a1SMichael Halcrow  * eCryptfs: Linux filesystem encryption layer
4da0102a1SMichael Halcrow  *
5da0102a1SMichael Halcrow  * Copyright (C) 2007 International Business Machines Corp.
6da0102a1SMichael Halcrow  *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
7da0102a1SMichael Halcrow  */
8da0102a1SMichael Halcrow 
9da0102a1SMichael Halcrow #include <linux/fs.h>
10da0102a1SMichael Halcrow #include <linux/pagemap.h>
11174cd4b1SIngo Molnar #include <linux/sched/signal.h>
12174cd4b1SIngo Molnar 
13da0102a1SMichael Halcrow #include "ecryptfs_kernel.h"
14da0102a1SMichael Halcrow 
15da0102a1SMichael Halcrow /**
16da0102a1SMichael Halcrow  * ecryptfs_write_lower
17da0102a1SMichael Halcrow  * @ecryptfs_inode: The eCryptfs inode
18da0102a1SMichael Halcrow  * @data: Data to write
19da0102a1SMichael Halcrow  * @offset: Byte offset in the lower file to which to write the data
20da0102a1SMichael Halcrow  * @size: Number of bytes from @data to write at @offset in the lower
21da0102a1SMichael Halcrow  *        file
22da0102a1SMichael Halcrow  *
23da0102a1SMichael Halcrow  * Write data to the lower file.
24da0102a1SMichael Halcrow  *
2596a7b9c2STyler Hicks  * Returns bytes written on success; less than zero on error
26da0102a1SMichael Halcrow  */
ecryptfs_write_lower(struct inode * ecryptfs_inode,char * data,loff_t offset,size_t size)27da0102a1SMichael Halcrow int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
28da0102a1SMichael Halcrow 			 loff_t offset, size_t size)
29da0102a1SMichael Halcrow {
30f61500e0STyler Hicks 	struct file *lower_file;
3196a7b9c2STyler Hicks 	ssize_t rc;
32da0102a1SMichael Halcrow 
33f61500e0STyler Hicks 	lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
34f61500e0STyler Hicks 	if (!lower_file)
35f61500e0STyler Hicks 		return -EIO;
36e13ec939SChristoph Hellwig 	rc = kernel_write(lower_file, data, size, &offset);
37da0102a1SMichael Halcrow 	mark_inode_dirty_sync(ecryptfs_inode);
38da0102a1SMichael Halcrow 	return rc;
39da0102a1SMichael Halcrow }
40da0102a1SMichael Halcrow 
41da0102a1SMichael Halcrow /**
42da0102a1SMichael Halcrow  * ecryptfs_write_lower_page_segment
43da0102a1SMichael Halcrow  * @ecryptfs_inode: The eCryptfs inode
44da0102a1SMichael Halcrow  * @page_for_lower: The page containing the data to be written to the
45da0102a1SMichael Halcrow  *                  lower file
46da0102a1SMichael Halcrow  * @offset_in_page: The offset in the @page_for_lower from which to
47da0102a1SMichael Halcrow  *                  start writing the data
48da0102a1SMichael Halcrow  * @size: The amount of data from @page_for_lower to write to the
49da0102a1SMichael Halcrow  *        lower file
50da0102a1SMichael Halcrow  *
51da0102a1SMichael Halcrow  * Determines the byte offset in the file for the given page and
52da0102a1SMichael Halcrow  * offset within the page, maps the page, and makes the call to write
53da0102a1SMichael Halcrow  * the contents of @page_for_lower to the lower inode.
54da0102a1SMichael Halcrow  *
55da0102a1SMichael Halcrow  * Returns zero on success; non-zero otherwise
56da0102a1SMichael Halcrow  */
ecryptfs_write_lower_page_segment(struct inode * ecryptfs_inode,struct page * page_for_lower,size_t offset_in_page,size_t size)57da0102a1SMichael Halcrow int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
58da0102a1SMichael Halcrow 				      struct page *page_for_lower,
59da0102a1SMichael Halcrow 				      size_t offset_in_page, size_t size)
60da0102a1SMichael Halcrow {
61da0102a1SMichael Halcrow 	char *virt;
62da0102a1SMichael Halcrow 	loff_t offset;
63da0102a1SMichael Halcrow 	int rc;
64da0102a1SMichael Halcrow 
6509cbfeafSKirill A. Shutemov 	offset = ((((loff_t)page_for_lower->index) << PAGE_SHIFT)
66d6a13c17SMichael Halcrow 		  + offset_in_page);
678b70deb8SFabio M. De Francesco 	virt = kmap_local_page(page_for_lower);
68da0102a1SMichael Halcrow 	rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
6996a7b9c2STyler Hicks 	if (rc > 0)
7096a7b9c2STyler Hicks 		rc = 0;
718b70deb8SFabio M. De Francesco 	kunmap_local(virt);
72da0102a1SMichael Halcrow 	return rc;
73da0102a1SMichael Halcrow }
74da0102a1SMichael Halcrow 
75da0102a1SMichael Halcrow /**
76da0102a1SMichael Halcrow  * ecryptfs_write
7748c1e44aSAl Viro  * @ecryptfs_inode: The eCryptfs file into which to write
78da0102a1SMichael Halcrow  * @data: Virtual address where data to write is located
79da0102a1SMichael Halcrow  * @offset: Offset in the eCryptfs file at which to begin writing the
80da0102a1SMichael Halcrow  *          data from @data
81da0102a1SMichael Halcrow  * @size: The number of bytes to write from @data
82da0102a1SMichael Halcrow  *
83da0102a1SMichael Halcrow  * Write an arbitrary amount of data to an arbitrary location in the
84da0102a1SMichael Halcrow  * eCryptfs inode page cache. This is done on a page-by-page, and then
85da0102a1SMichael Halcrow  * by an extent-by-extent, basis; individual extents are encrypted and
86da0102a1SMichael Halcrow  * written to the lower page cache (via VFS writes). This function
87da0102a1SMichael Halcrow  * takes care of all the address translation to locations in the lower
88da0102a1SMichael Halcrow  * filesystem; it also handles truncate events, writing out zeros
89da0102a1SMichael Halcrow  * where necessary.
90da0102a1SMichael Halcrow  *
91da0102a1SMichael Halcrow  * Returns zero on success; non-zero otherwise
92da0102a1SMichael Halcrow  */
ecryptfs_write(struct inode * ecryptfs_inode,char * data,loff_t offset,size_t size)9348c1e44aSAl Viro int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset,
94da0102a1SMichael Halcrow 		   size_t size)
95da0102a1SMichael Halcrow {
96da0102a1SMichael Halcrow 	struct page *ecryptfs_page;
9713a791b4STyler Hicks 	struct ecryptfs_crypt_stat *crypt_stat;
98da0102a1SMichael Halcrow 	char *ecryptfs_page_virt;
9913a791b4STyler Hicks 	loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);
100da0102a1SMichael Halcrow 	loff_t data_offset = 0;
101da0102a1SMichael Halcrow 	loff_t pos;
102da0102a1SMichael Halcrow 	int rc = 0;
103da0102a1SMichael Halcrow 
10413a791b4STyler Hicks 	crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
1057a3f595cSEric Sandeen 	/*
1067a3f595cSEric Sandeen 	 * if we are writing beyond current size, then start pos
1077a3f595cSEric Sandeen 	 * at the current size - we'll fill in zeros from there.
1087a3f595cSEric Sandeen 	 */
109da0102a1SMichael Halcrow 	if (offset > ecryptfs_file_size)
110da0102a1SMichael Halcrow 		pos = ecryptfs_file_size;
111da0102a1SMichael Halcrow 	else
112da0102a1SMichael Halcrow 		pos = offset;
113da0102a1SMichael Halcrow 	while (pos < (offset + size)) {
11409cbfeafSKirill A. Shutemov 		pgoff_t ecryptfs_page_idx = (pos >> PAGE_SHIFT);
11509cbfeafSKirill A. Shutemov 		size_t start_offset_in_page = (pos & ~PAGE_MASK);
11609cbfeafSKirill A. Shutemov 		size_t num_bytes = (PAGE_SIZE - start_offset_in_page);
117684a3ff7SLi Wang 		loff_t total_remaining_bytes = ((offset + size) - pos);
118da0102a1SMichael Halcrow 
1195e6f0d76STyler Hicks 		if (fatal_signal_pending(current)) {
1205e6f0d76STyler Hicks 			rc = -EINTR;
1215e6f0d76STyler Hicks 			break;
1225e6f0d76STyler Hicks 		}
1235e6f0d76STyler Hicks 
124da0102a1SMichael Halcrow 		if (num_bytes > total_remaining_bytes)
125da0102a1SMichael Halcrow 			num_bytes = total_remaining_bytes;
126da0102a1SMichael Halcrow 		if (pos < offset) {
1277a3f595cSEric Sandeen 			/* remaining zeros to write, up to destination offset */
128684a3ff7SLi Wang 			loff_t total_remaining_zeros = (offset - pos);
129da0102a1SMichael Halcrow 
130da0102a1SMichael Halcrow 			if (num_bytes > total_remaining_zeros)
131da0102a1SMichael Halcrow 				num_bytes = total_remaining_zeros;
132da0102a1SMichael Halcrow 		}
13302bd9799SAl Viro 		ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_inode,
134da0102a1SMichael Halcrow 							 ecryptfs_page_idx);
135da0102a1SMichael Halcrow 		if (IS_ERR(ecryptfs_page)) {
136da0102a1SMichael Halcrow 			rc = PTR_ERR(ecryptfs_page);
137da0102a1SMichael Halcrow 			printk(KERN_ERR "%s: Error getting page at "
138da0102a1SMichael Halcrow 			       "index [%ld] from eCryptfs inode "
13918d1dbf1SHarvey Harrison 			       "mapping; rc = [%d]\n", __func__,
140da0102a1SMichael Halcrow 			       ecryptfs_page_idx, rc);
141da0102a1SMichael Halcrow 			goto out;
142da0102a1SMichael Halcrow 		}
143*c3c6833eSFabio M. De Francesco 		ecryptfs_page_virt = kmap_local_page(ecryptfs_page);
1447a3f595cSEric Sandeen 
1457a3f595cSEric Sandeen 		/*
1467a3f595cSEric Sandeen 		 * pos: where we're now writing, offset: where the request was
1477a3f595cSEric Sandeen 		 * If current pos is before request, we are filling zeros
1487a3f595cSEric Sandeen 		 * If we are at or beyond request, we are writing the *data*
1497a3f595cSEric Sandeen 		 * If we're in a fresh page beyond eof, zero it in either case
1507a3f595cSEric Sandeen 		 */
1517a3f595cSEric Sandeen 		if (pos < offset || !start_offset_in_page) {
1527a3f595cSEric Sandeen 			/* We are extending past the previous end of the file.
1537a3f595cSEric Sandeen 			 * Fill in zero values to the end of the page */
1547a3f595cSEric Sandeen 			memset(((char *)ecryptfs_page_virt
1557a3f595cSEric Sandeen 				+ start_offset_in_page), 0,
15609cbfeafSKirill A. Shutemov 				PAGE_SIZE - start_offset_in_page);
1577a3f595cSEric Sandeen 		}
1587a3f595cSEric Sandeen 
1597a3f595cSEric Sandeen 		/* pos >= offset, we are now writing the data request */
160da0102a1SMichael Halcrow 		if (pos >= offset) {
161da0102a1SMichael Halcrow 			memcpy(((char *)ecryptfs_page_virt
162da0102a1SMichael Halcrow 				+ start_offset_in_page),
163da0102a1SMichael Halcrow 			       (data + data_offset), num_bytes);
164da0102a1SMichael Halcrow 			data_offset += num_bytes;
165da0102a1SMichael Halcrow 		}
166*c3c6833eSFabio M. De Francesco 		kunmap_local(ecryptfs_page_virt);
167da0102a1SMichael Halcrow 		flush_dcache_page(ecryptfs_page);
16816a72c45SMichael Halcrow 		SetPageUptodate(ecryptfs_page);
16916a72c45SMichael Halcrow 		unlock_page(ecryptfs_page);
17013a791b4STyler Hicks 		if (crypt_stat->flags & ECRYPTFS_ENCRYPTED)
1710216f7f7SMichael Halcrow 			rc = ecryptfs_encrypt_page(ecryptfs_page);
17213a791b4STyler Hicks 		else
17313a791b4STyler Hicks 			rc = ecryptfs_write_lower_page_segment(ecryptfs_inode,
17413a791b4STyler Hicks 						ecryptfs_page,
17513a791b4STyler Hicks 						start_offset_in_page,
17613a791b4STyler Hicks 						data_offset);
17709cbfeafSKirill A. Shutemov 		put_page(ecryptfs_page);
178da0102a1SMichael Halcrow 		if (rc) {
179da0102a1SMichael Halcrow 			printk(KERN_ERR "%s: Error encrypting "
18018d1dbf1SHarvey Harrison 			       "page; rc = [%d]\n", __func__, rc);
181da0102a1SMichael Halcrow 			goto out;
182da0102a1SMichael Halcrow 		}
183da0102a1SMichael Halcrow 		pos += num_bytes;
184da0102a1SMichael Halcrow 	}
1855e6f0d76STyler Hicks 	if (pos > ecryptfs_file_size) {
1865e6f0d76STyler Hicks 		i_size_write(ecryptfs_inode, pos);
18713a791b4STyler Hicks 		if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) {
1885e6f0d76STyler Hicks 			int rc2;
1895e6f0d76STyler Hicks 
1905e6f0d76STyler Hicks 			rc2 = ecryptfs_write_inode_size_to_metadata(
19113a791b4STyler Hicks 								ecryptfs_inode);
1925e6f0d76STyler Hicks 			if (rc2) {
193da0102a1SMichael Halcrow 				printk(KERN_ERR	"Problem with "
194da0102a1SMichael Halcrow 				       "ecryptfs_write_inode_size_to_metadata; "
1955e6f0d76STyler Hicks 				       "rc = [%d]\n", rc2);
1965e6f0d76STyler Hicks 				if (!rc)
1975e6f0d76STyler Hicks 					rc = rc2;
198da0102a1SMichael Halcrow 				goto out;
199da0102a1SMichael Halcrow 			}
200da0102a1SMichael Halcrow 		}
20113a791b4STyler Hicks 	}
202da0102a1SMichael Halcrow out:
203da0102a1SMichael Halcrow 	return rc;
204da0102a1SMichael Halcrow }
205da0102a1SMichael Halcrow 
206da0102a1SMichael Halcrow /**
207da0102a1SMichael Halcrow  * ecryptfs_read_lower
208da0102a1SMichael Halcrow  * @data: The read data is stored here by this function
209da0102a1SMichael Halcrow  * @offset: Byte offset in the lower file from which to read the data
210da0102a1SMichael Halcrow  * @size: Number of bytes to read from @offset of the lower file and
211da0102a1SMichael Halcrow  *        store into @data
212da0102a1SMichael Halcrow  * @ecryptfs_inode: The eCryptfs inode
213da0102a1SMichael Halcrow  *
214da0102a1SMichael Halcrow  * Read @size bytes of data at byte offset @offset from the lower
215da0102a1SMichael Halcrow  * inode into memory location @data.
216da0102a1SMichael Halcrow  *
21796a7b9c2STyler Hicks  * Returns bytes read on success; 0 on EOF; less than zero on error
218da0102a1SMichael Halcrow  */
ecryptfs_read_lower(char * data,loff_t offset,size_t size,struct inode * ecryptfs_inode)219da0102a1SMichael Halcrow int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
220da0102a1SMichael Halcrow 			struct inode *ecryptfs_inode)
221da0102a1SMichael Halcrow {
222f61500e0STyler Hicks 	struct file *lower_file;
223f61500e0STyler Hicks 	lower_file = ecryptfs_inode_to_private(ecryptfs_inode)->lower_file;
224f61500e0STyler Hicks 	if (!lower_file)
225f61500e0STyler Hicks 		return -EIO;
226bdd1d2d3SChristoph Hellwig 	return kernel_read(lower_file, data, size, &offset);
227da0102a1SMichael Halcrow }
228da0102a1SMichael Halcrow 
229da0102a1SMichael Halcrow /**
230da0102a1SMichael Halcrow  * ecryptfs_read_lower_page_segment
231da0102a1SMichael Halcrow  * @page_for_ecryptfs: The page into which data for eCryptfs will be
232da0102a1SMichael Halcrow  *                     written
23309d02efaSLee Jones  * @page_index: Page index in @page_for_ecryptfs from which to start
23409d02efaSLee Jones  *		writing
235da0102a1SMichael Halcrow  * @offset_in_page: Offset in @page_for_ecryptfs from which to start
236da0102a1SMichael Halcrow  *                  writing
237da0102a1SMichael Halcrow  * @size: The number of bytes to write into @page_for_ecryptfs
238da0102a1SMichael Halcrow  * @ecryptfs_inode: The eCryptfs inode
239da0102a1SMichael Halcrow  *
240da0102a1SMichael Halcrow  * Determines the byte offset in the file for the given page and
241da0102a1SMichael Halcrow  * offset within the page, maps the page, and makes the call to read
242da0102a1SMichael Halcrow  * the contents of @page_for_ecryptfs from the lower inode.
243da0102a1SMichael Halcrow  *
244da0102a1SMichael Halcrow  * Returns zero on success; non-zero otherwise
245da0102a1SMichael Halcrow  */
ecryptfs_read_lower_page_segment(struct page * page_for_ecryptfs,pgoff_t page_index,size_t offset_in_page,size_t size,struct inode * ecryptfs_inode)246da0102a1SMichael Halcrow int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
247da0102a1SMichael Halcrow 				     pgoff_t page_index,
248da0102a1SMichael Halcrow 				     size_t offset_in_page, size_t size,
249da0102a1SMichael Halcrow 				     struct inode *ecryptfs_inode)
250da0102a1SMichael Halcrow {
251da0102a1SMichael Halcrow 	char *virt;
252da0102a1SMichael Halcrow 	loff_t offset;
253da0102a1SMichael Halcrow 	int rc;
254da0102a1SMichael Halcrow 
25509cbfeafSKirill A. Shutemov 	offset = ((((loff_t)page_index) << PAGE_SHIFT) + offset_in_page);
2568b70deb8SFabio M. De Francesco 	virt = kmap_local_page(page_for_ecryptfs);
257da0102a1SMichael Halcrow 	rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);
25896a7b9c2STyler Hicks 	if (rc > 0)
25996a7b9c2STyler Hicks 		rc = 0;
2608b70deb8SFabio M. De Francesco 	kunmap_local(virt);
26116a72c45SMichael Halcrow 	flush_dcache_page(page_for_ecryptfs);
262da0102a1SMichael Halcrow 	return rc;
263da0102a1SMichael Halcrow }
264