cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

file.c (10628B)


      1// SPDX-License-Identifier: MIT
      2/*
      3 * VirtualBox Guest Shared Folders support: Regular file inode and file ops.
      4 *
      5 * Copyright (C) 2006-2018 Oracle Corporation
      6 */
      7
      8#include <linux/mm.h>
      9#include <linux/page-flags.h>
     10#include <linux/pagemap.h>
     11#include <linux/highmem.h>
     12#include <linux/sizes.h>
     13#include "vfsmod.h"
     14
     15struct vboxsf_handle {
     16	u64 handle;
     17	u32 root;
     18	u32 access_flags;
     19	struct kref refcount;
     20	struct list_head head;
     21};
     22
     23struct vboxsf_handle *vboxsf_create_sf_handle(struct inode *inode,
     24					      u64 handle, u32 access_flags)
     25{
     26	struct vboxsf_inode *sf_i = VBOXSF_I(inode);
     27	struct vboxsf_handle *sf_handle;
     28
     29	sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL);
     30	if (!sf_handle)
     31		return ERR_PTR(-ENOMEM);
     32
     33	/* the host may have given us different attr then requested */
     34	sf_i->force_restat = 1;
     35
     36	/* init our handle struct and add it to the inode's handles list */
     37	sf_handle->handle = handle;
     38	sf_handle->root = VBOXSF_SBI(inode->i_sb)->root;
     39	sf_handle->access_flags = access_flags;
     40	kref_init(&sf_handle->refcount);
     41
     42	mutex_lock(&sf_i->handle_list_mutex);
     43	list_add(&sf_handle->head, &sf_i->handle_list);
     44	mutex_unlock(&sf_i->handle_list_mutex);
     45
     46	return sf_handle;
     47}
     48
     49static int vboxsf_file_open(struct inode *inode, struct file *file)
     50{
     51	struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
     52	struct shfl_createparms params = {};
     53	struct vboxsf_handle *sf_handle;
     54	u32 access_flags = 0;
     55	int err;
     56
     57	/*
     58	 * We check the value of params.handle afterwards to find out if
     59	 * the call succeeded or failed, as the API does not seem to cleanly
     60	 * distinguish error and informational messages.
     61	 *
     62	 * Furthermore, we must set params.handle to SHFL_HANDLE_NIL to
     63	 * make the shared folders host service use our mode parameter.
     64	 */
     65	params.handle = SHFL_HANDLE_NIL;
     66	if (file->f_flags & O_CREAT) {
     67		params.create_flags |= SHFL_CF_ACT_CREATE_IF_NEW;
     68		/*
     69		 * We ignore O_EXCL, as the Linux kernel seems to call create
     70		 * beforehand itself, so O_EXCL should always fail.
     71		 */
     72		if (file->f_flags & O_TRUNC)
     73			params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
     74		else
     75			params.create_flags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
     76	} else {
     77		params.create_flags |= SHFL_CF_ACT_FAIL_IF_NEW;
     78		if (file->f_flags & O_TRUNC)
     79			params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS;
     80	}
     81
     82	switch (file->f_flags & O_ACCMODE) {
     83	case O_RDONLY:
     84		access_flags |= SHFL_CF_ACCESS_READ;
     85		break;
     86
     87	case O_WRONLY:
     88		access_flags |= SHFL_CF_ACCESS_WRITE;
     89		break;
     90
     91	case O_RDWR:
     92		access_flags |= SHFL_CF_ACCESS_READWRITE;
     93		break;
     94
     95	default:
     96		WARN_ON(1);
     97	}
     98
     99	if (file->f_flags & O_APPEND)
    100		access_flags |= SHFL_CF_ACCESS_APPEND;
    101
    102	params.create_flags |= access_flags;
    103	params.info.attr.mode = inode->i_mode;
    104
    105	err = vboxsf_create_at_dentry(file_dentry(file), &params);
    106	if (err == 0 && params.handle == SHFL_HANDLE_NIL)
    107		err = (params.result == SHFL_FILE_EXISTS) ? -EEXIST : -ENOENT;
    108	if (err)
    109		return err;
    110
    111	sf_handle = vboxsf_create_sf_handle(inode, params.handle, access_flags);
    112	if (IS_ERR(sf_handle)) {
    113		vboxsf_close(sbi->root, params.handle);
    114		return PTR_ERR(sf_handle);
    115	}
    116
    117	file->private_data = sf_handle;
    118	return 0;
    119}
    120
    121static void vboxsf_handle_release(struct kref *refcount)
    122{
    123	struct vboxsf_handle *sf_handle =
    124		container_of(refcount, struct vboxsf_handle, refcount);
    125
    126	vboxsf_close(sf_handle->root, sf_handle->handle);
    127	kfree(sf_handle);
    128}
    129
    130void vboxsf_release_sf_handle(struct inode *inode, struct vboxsf_handle *sf_handle)
    131{
    132	struct vboxsf_inode *sf_i = VBOXSF_I(inode);
    133
    134	mutex_lock(&sf_i->handle_list_mutex);
    135	list_del(&sf_handle->head);
    136	mutex_unlock(&sf_i->handle_list_mutex);
    137
    138	kref_put(&sf_handle->refcount, vboxsf_handle_release);
    139}
    140
    141static int vboxsf_file_release(struct inode *inode, struct file *file)
    142{
    143	/*
    144	 * When a file is closed on our (the guest) side, we want any subsequent
    145	 * accesses done on the host side to see all changes done from our side.
    146	 */
    147	filemap_write_and_wait(inode->i_mapping);
    148
    149	vboxsf_release_sf_handle(inode, file->private_data);
    150	return 0;
    151}
    152
    153/*
    154 * Write back dirty pages now, because there may not be any suitable
    155 * open files later
    156 */
    157static void vboxsf_vma_close(struct vm_area_struct *vma)
    158{
    159	filemap_write_and_wait(vma->vm_file->f_mapping);
    160}
    161
    162static const struct vm_operations_struct vboxsf_file_vm_ops = {
    163	.close		= vboxsf_vma_close,
    164	.fault		= filemap_fault,
    165	.map_pages	= filemap_map_pages,
    166};
    167
    168static int vboxsf_file_mmap(struct file *file, struct vm_area_struct *vma)
    169{
    170	int err;
    171
    172	err = generic_file_mmap(file, vma);
    173	if (!err)
    174		vma->vm_ops = &vboxsf_file_vm_ops;
    175
    176	return err;
    177}
    178
    179/*
    180 * Note that since we are accessing files on the host's filesystem, files
    181 * may always be changed underneath us by the host!
    182 *
    183 * The vboxsf API between the guest and the host does not offer any functions
    184 * to deal with this. There is no inode-generation to check for changes, no
    185 * events / callback on changes and no way to lock files.
    186 *
    187 * To avoid returning stale data when a file gets *opened* on our (the guest)
    188 * side, we do a "stat" on the host side, then compare the mtime with the
    189 * last known mtime and invalidate the page-cache if they differ.
    190 * This is done from vboxsf_inode_revalidate().
    191 *
    192 * When reads are done through the read_iter fop, it is possible to do
    193 * further cache revalidation then, there are 3 options to deal with this:
    194 *
    195 * 1)  Rely solely on the revalidation done at open time
    196 * 2)  Do another "stat" and compare mtime again. Unfortunately the vboxsf
    197 *     host API does not allow stat on handles, so we would need to use
    198 *     file->f_path.dentry and the stat will then fail if the file was unlinked
    199 *     or renamed (and there is no thing like NFS' silly-rename). So we get:
    200 * 2a) "stat" and compare mtime, on stat failure invalidate the cache
    201 * 2b) "stat" and compare mtime, on stat failure do nothing
    202 * 3)  Simply always call invalidate_inode_pages2_range on the range of the read
    203 *
    204 * Currently we are keeping things KISS and using option 1. this allows
    205 * directly using generic_file_read_iter without wrapping it.
    206 *
    207 * This means that only data written on the host side before open() on
    208 * the guest side is guaranteed to be seen by the guest. If necessary
    209 * we may provide other read-cache strategies in the future and make this
    210 * configurable through a mount option.
    211 */
    212const struct file_operations vboxsf_reg_fops = {
    213	.llseek = generic_file_llseek,
    214	.read_iter = generic_file_read_iter,
    215	.write_iter = generic_file_write_iter,
    216	.mmap = vboxsf_file_mmap,
    217	.open = vboxsf_file_open,
    218	.release = vboxsf_file_release,
    219	.fsync = noop_fsync,
    220	.splice_read = generic_file_splice_read,
    221};
    222
    223const struct inode_operations vboxsf_reg_iops = {
    224	.getattr = vboxsf_getattr,
    225	.setattr = vboxsf_setattr
    226};
    227
    228static int vboxsf_read_folio(struct file *file, struct folio *folio)
    229{
    230	struct page *page = &folio->page;
    231	struct vboxsf_handle *sf_handle = file->private_data;
    232	loff_t off = page_offset(page);
    233	u32 nread = PAGE_SIZE;
    234	u8 *buf;
    235	int err;
    236
    237	buf = kmap(page);
    238
    239	err = vboxsf_read(sf_handle->root, sf_handle->handle, off, &nread, buf);
    240	if (err == 0) {
    241		memset(&buf[nread], 0, PAGE_SIZE - nread);
    242		flush_dcache_page(page);
    243		SetPageUptodate(page);
    244	} else {
    245		SetPageError(page);
    246	}
    247
    248	kunmap(page);
    249	unlock_page(page);
    250	return err;
    251}
    252
    253static struct vboxsf_handle *vboxsf_get_write_handle(struct vboxsf_inode *sf_i)
    254{
    255	struct vboxsf_handle *h, *sf_handle = NULL;
    256
    257	mutex_lock(&sf_i->handle_list_mutex);
    258	list_for_each_entry(h, &sf_i->handle_list, head) {
    259		if (h->access_flags == SHFL_CF_ACCESS_WRITE ||
    260		    h->access_flags == SHFL_CF_ACCESS_READWRITE) {
    261			kref_get(&h->refcount);
    262			sf_handle = h;
    263			break;
    264		}
    265	}
    266	mutex_unlock(&sf_i->handle_list_mutex);
    267
    268	return sf_handle;
    269}
    270
    271static int vboxsf_writepage(struct page *page, struct writeback_control *wbc)
    272{
    273	struct inode *inode = page->mapping->host;
    274	struct vboxsf_inode *sf_i = VBOXSF_I(inode);
    275	struct vboxsf_handle *sf_handle;
    276	loff_t off = page_offset(page);
    277	loff_t size = i_size_read(inode);
    278	u32 nwrite = PAGE_SIZE;
    279	u8 *buf;
    280	int err;
    281
    282	if (off + PAGE_SIZE > size)
    283		nwrite = size & ~PAGE_MASK;
    284
    285	sf_handle = vboxsf_get_write_handle(sf_i);
    286	if (!sf_handle)
    287		return -EBADF;
    288
    289	buf = kmap(page);
    290	err = vboxsf_write(sf_handle->root, sf_handle->handle,
    291			   off, &nwrite, buf);
    292	kunmap(page);
    293
    294	kref_put(&sf_handle->refcount, vboxsf_handle_release);
    295
    296	if (err == 0) {
    297		ClearPageError(page);
    298		/* mtime changed */
    299		sf_i->force_restat = 1;
    300	} else {
    301		ClearPageUptodate(page);
    302	}
    303
    304	unlock_page(page);
    305	return err;
    306}
    307
    308static int vboxsf_write_end(struct file *file, struct address_space *mapping,
    309			    loff_t pos, unsigned int len, unsigned int copied,
    310			    struct page *page, void *fsdata)
    311{
    312	struct inode *inode = mapping->host;
    313	struct vboxsf_handle *sf_handle = file->private_data;
    314	unsigned int from = pos & ~PAGE_MASK;
    315	u32 nwritten = len;
    316	u8 *buf;
    317	int err;
    318
    319	/* zero the stale part of the page if we did a short copy */
    320	if (!PageUptodate(page) && copied < len)
    321		zero_user(page, from + copied, len - copied);
    322
    323	buf = kmap(page);
    324	err = vboxsf_write(sf_handle->root, sf_handle->handle,
    325			   pos, &nwritten, buf + from);
    326	kunmap(page);
    327
    328	if (err) {
    329		nwritten = 0;
    330		goto out;
    331	}
    332
    333	/* mtime changed */
    334	VBOXSF_I(inode)->force_restat = 1;
    335
    336	if (!PageUptodate(page) && nwritten == PAGE_SIZE)
    337		SetPageUptodate(page);
    338
    339	pos += nwritten;
    340	if (pos > inode->i_size)
    341		i_size_write(inode, pos);
    342
    343out:
    344	unlock_page(page);
    345	put_page(page);
    346
    347	return nwritten;
    348}
    349
    350/*
    351 * Note simple_write_begin does not read the page from disk on partial writes
    352 * this is ok since vboxsf_write_end only writes the written parts of the
    353 * page and it does not call SetPageUptodate for partial writes.
    354 */
    355const struct address_space_operations vboxsf_reg_aops = {
    356	.read_folio = vboxsf_read_folio,
    357	.writepage = vboxsf_writepage,
    358	.dirty_folio = filemap_dirty_folio,
    359	.write_begin = simple_write_begin,
    360	.write_end = vboxsf_write_end,
    361};
    362
    363static const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode,
    364				   struct delayed_call *done)
    365{
    366	struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb);
    367	struct shfl_string *path;
    368	char *link;
    369	int err;
    370
    371	if (!dentry)
    372		return ERR_PTR(-ECHILD);
    373
    374	path = vboxsf_path_from_dentry(sbi, dentry);
    375	if (IS_ERR(path))
    376		return ERR_CAST(path);
    377
    378	link = kzalloc(PATH_MAX, GFP_KERNEL);
    379	if (!link) {
    380		__putname(path);
    381		return ERR_PTR(-ENOMEM);
    382	}
    383
    384	err = vboxsf_readlink(sbi->root, path, PATH_MAX, link);
    385	__putname(path);
    386	if (err) {
    387		kfree(link);
    388		return ERR_PTR(err);
    389	}
    390
    391	set_delayed_call(done, kfree_link, link);
    392	return link;
    393}
    394
    395const struct inode_operations vboxsf_lnk_iops = {
    396	.get_link = vboxsf_get_link
    397};