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