xref: /linux-6.15/fs/ecryptfs/read_write.c (revision 6b9c0e81)
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 <[email protected]>
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
44de5ced27SMatthew Wilcox (Oracle)  * @folio_for_lower: The folio containing the data to be written to the
45da0102a1SMichael Halcrow  *                  lower file
46de5ced27SMatthew Wilcox (Oracle)  * @offset_in_page: The offset in the @folio_for_lower from which to
47da0102a1SMichael Halcrow  *                  start writing the data
48de5ced27SMatthew Wilcox (Oracle)  * @size: The amount of data from @folio_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
53de5ced27SMatthew Wilcox (Oracle)  * the contents of @folio_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 folio * folio_for_lower,size_t offset_in_page,size_t size)57da0102a1SMichael Halcrow int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,
58de5ced27SMatthew Wilcox (Oracle) 				      struct folio *folio_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 
65de5ced27SMatthew Wilcox (Oracle) 	offset = (loff_t)folio_for_lower->index * PAGE_SIZE + offset_in_page;
66de5ced27SMatthew Wilcox (Oracle) 	virt = kmap_local_folio(folio_for_lower, 0);
67da0102a1SMichael Halcrow 	rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);
6896a7b9c2STyler Hicks 	if (rc > 0)
6996a7b9c2STyler Hicks 		rc = 0;
708b70deb8SFabio M. De Francesco 	kunmap_local(virt);
71da0102a1SMichael Halcrow 	return rc;
72da0102a1SMichael Halcrow }
73da0102a1SMichael Halcrow 
74da0102a1SMichael Halcrow /**
75da0102a1SMichael Halcrow  * ecryptfs_write
7648c1e44aSAl Viro  * @ecryptfs_inode: The eCryptfs file into which to write
77da0102a1SMichael Halcrow  * @data: Virtual address where data to write is located
78da0102a1SMichael Halcrow  * @offset: Offset in the eCryptfs file at which to begin writing the
79da0102a1SMichael Halcrow  *          data from @data
80da0102a1SMichael Halcrow  * @size: The number of bytes to write from @data
81da0102a1SMichael Halcrow  *
82da0102a1SMichael Halcrow  * Write an arbitrary amount of data to an arbitrary location in the
83da0102a1SMichael Halcrow  * eCryptfs inode page cache. This is done on a page-by-page, and then
84da0102a1SMichael Halcrow  * by an extent-by-extent, basis; individual extents are encrypted and
85da0102a1SMichael Halcrow  * written to the lower page cache (via VFS writes). This function
86da0102a1SMichael Halcrow  * takes care of all the address translation to locations in the lower
87da0102a1SMichael Halcrow  * filesystem; it also handles truncate events, writing out zeros
88da0102a1SMichael Halcrow  * where necessary.
89da0102a1SMichael Halcrow  *
90da0102a1SMichael Halcrow  * Returns zero on success; non-zero otherwise
91da0102a1SMichael Halcrow  */
ecryptfs_write(struct inode * ecryptfs_inode,char * data,loff_t offset,size_t size)9248c1e44aSAl Viro int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset,
93da0102a1SMichael Halcrow 		   size_t size)
94da0102a1SMichael Halcrow {
9513a791b4STyler Hicks 	struct ecryptfs_crypt_stat *crypt_stat;
96da0102a1SMichael Halcrow 	char *ecryptfs_page_virt;
9713a791b4STyler Hicks 	loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);
98da0102a1SMichael Halcrow 	loff_t data_offset = 0;
99da0102a1SMichael Halcrow 	loff_t pos;
100da0102a1SMichael Halcrow 	int rc = 0;
101da0102a1SMichael Halcrow 
10213a791b4STyler Hicks 	crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
1037a3f595cSEric Sandeen 	/*
1047a3f595cSEric Sandeen 	 * if we are writing beyond current size, then start pos
1057a3f595cSEric Sandeen 	 * at the current size - we'll fill in zeros from there.
1067a3f595cSEric Sandeen 	 */
107da0102a1SMichael Halcrow 	if (offset > ecryptfs_file_size)
108da0102a1SMichael Halcrow 		pos = ecryptfs_file_size;
109da0102a1SMichael Halcrow 	else
110da0102a1SMichael Halcrow 		pos = offset;
111da0102a1SMichael Halcrow 	while (pos < (offset + size)) {
1124d3727fdSMatthew Wilcox (Oracle) 		struct folio *ecryptfs_folio;
11309cbfeafSKirill A. Shutemov 		pgoff_t ecryptfs_page_idx = (pos >> PAGE_SHIFT);
11409cbfeafSKirill A. Shutemov 		size_t start_offset_in_page = (pos & ~PAGE_MASK);
11509cbfeafSKirill A. Shutemov 		size_t num_bytes = (PAGE_SIZE - start_offset_in_page);
116684a3ff7SLi Wang 		loff_t total_remaining_bytes = ((offset + size) - pos);
117da0102a1SMichael Halcrow 
1185e6f0d76STyler Hicks 		if (fatal_signal_pending(current)) {
1195e6f0d76STyler Hicks 			rc = -EINTR;
1205e6f0d76STyler Hicks 			break;
1215e6f0d76STyler Hicks 		}
1225e6f0d76STyler Hicks 
123da0102a1SMichael Halcrow 		if (num_bytes > total_remaining_bytes)
124da0102a1SMichael Halcrow 			num_bytes = total_remaining_bytes;
125da0102a1SMichael Halcrow 		if (pos < offset) {
1267a3f595cSEric Sandeen 			/* remaining zeros to write, up to destination offset */
127684a3ff7SLi Wang 			loff_t total_remaining_zeros = (offset - pos);
128da0102a1SMichael Halcrow 
129da0102a1SMichael Halcrow 			if (num_bytes > total_remaining_zeros)
130da0102a1SMichael Halcrow 				num_bytes = total_remaining_zeros;
131da0102a1SMichael Halcrow 		}
1324d3727fdSMatthew Wilcox (Oracle) 		ecryptfs_folio = read_mapping_folio(ecryptfs_inode->i_mapping,
1334d3727fdSMatthew Wilcox (Oracle) 				ecryptfs_page_idx, NULL);
1344d3727fdSMatthew Wilcox (Oracle) 		if (IS_ERR(ecryptfs_folio)) {
1354d3727fdSMatthew Wilcox (Oracle) 			rc = PTR_ERR(ecryptfs_folio);
136da0102a1SMichael Halcrow 			printk(KERN_ERR "%s: Error getting page at "
137da0102a1SMichael Halcrow 			       "index [%ld] from eCryptfs inode "
13818d1dbf1SHarvey Harrison 			       "mapping; rc = [%d]\n", __func__,
139da0102a1SMichael Halcrow 			       ecryptfs_page_idx, rc);
140da0102a1SMichael Halcrow 			goto out;
141da0102a1SMichael Halcrow 		}
1424d3727fdSMatthew Wilcox (Oracle) 		folio_lock(ecryptfs_folio);
1434d3727fdSMatthew Wilcox (Oracle) 		ecryptfs_page_virt = kmap_local_folio(ecryptfs_folio, 0);
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 		}
166c3c6833eSFabio M. De Francesco 		kunmap_local(ecryptfs_page_virt);
1674d3727fdSMatthew Wilcox (Oracle) 		flush_dcache_folio(ecryptfs_folio);
1684d3727fdSMatthew Wilcox (Oracle) 		folio_mark_uptodate(ecryptfs_folio);
1694d3727fdSMatthew Wilcox (Oracle) 		folio_unlock(ecryptfs_folio);
17013a791b4STyler Hicks 		if (crypt_stat->flags & ECRYPTFS_ENCRYPTED)
171*6b9c0e81SMatthew Wilcox (Oracle) 			rc = ecryptfs_encrypt_page(ecryptfs_folio);
17213a791b4STyler Hicks 		else
17313a791b4STyler Hicks 			rc = ecryptfs_write_lower_page_segment(ecryptfs_inode,
174de5ced27SMatthew Wilcox (Oracle) 						ecryptfs_folio,
17513a791b4STyler Hicks 						start_offset_in_page,
17613a791b4STyler Hicks 						data_offset);
1774d3727fdSMatthew Wilcox (Oracle) 		folio_put(ecryptfs_folio);
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
231890d477aSMatthew Wilcox (Oracle)  * @folio_for_ecryptfs: The folio 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 folio * folio_for_ecryptfs,pgoff_t page_index,size_t offset_in_page,size_t size,struct inode * ecryptfs_inode)246890d477aSMatthew Wilcox (Oracle) int ecryptfs_read_lower_page_segment(struct folio *folio_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 
255890d477aSMatthew Wilcox (Oracle) 	offset = (loff_t)page_index * PAGE_SIZE + offset_in_page;
256890d477aSMatthew Wilcox (Oracle) 	virt = kmap_local_folio(folio_for_ecryptfs, 0);
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);
261890d477aSMatthew Wilcox (Oracle) 	flush_dcache_folio(folio_for_ecryptfs);
262da0102a1SMichael Halcrow 	return rc;
263da0102a1SMichael Halcrow }
264