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

xattr.c (7913B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* CacheFiles extended attribute management
      3 *
      4 * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/sched.h>
     10#include <linux/file.h>
     11#include <linux/fs.h>
     12#include <linux/fsnotify.h>
     13#include <linux/quotaops.h>
     14#include <linux/xattr.h>
     15#include <linux/slab.h>
     16#include "internal.h"
     17
     18#define CACHEFILES_COOKIE_TYPE_DATA 1
     19
     20struct cachefiles_xattr {
     21	__be64	object_size;	/* Actual size of the object */
     22	__be64	zero_point;	/* Size after which server has no data not written by us */
     23	__u8	type;		/* Type of object */
     24	__u8	content;	/* Content presence (enum cachefiles_content) */
     25	__u8	data[];		/* netfs coherency data */
     26} __packed;
     27
     28static const char cachefiles_xattr_cache[] =
     29	XATTR_USER_PREFIX "CacheFiles.cache";
     30
     31struct cachefiles_vol_xattr {
     32	__be32	reserved;	/* Reserved, should be 0 */
     33	__u8	data[];		/* netfs volume coherency data */
     34} __packed;
     35
     36/*
     37 * set the state xattr on a cache file
     38 */
     39int cachefiles_set_object_xattr(struct cachefiles_object *object)
     40{
     41	struct cachefiles_xattr *buf;
     42	struct dentry *dentry;
     43	struct file *file = object->file;
     44	unsigned int len = object->cookie->aux_len;
     45	int ret;
     46
     47	if (!file)
     48		return -ESTALE;
     49	dentry = file->f_path.dentry;
     50
     51	_enter("%x,#%d", object->debug_id, len);
     52
     53	buf = kmalloc(sizeof(struct cachefiles_xattr) + len, GFP_KERNEL);
     54	if (!buf)
     55		return -ENOMEM;
     56
     57	buf->object_size	= cpu_to_be64(object->cookie->object_size);
     58	buf->zero_point		= 0;
     59	buf->type		= CACHEFILES_COOKIE_TYPE_DATA;
     60	buf->content		= object->content_info;
     61	if (test_bit(FSCACHE_COOKIE_LOCAL_WRITE, &object->cookie->flags))
     62		buf->content	= CACHEFILES_CONTENT_DIRTY;
     63	if (len > 0)
     64		memcpy(buf->data, fscache_get_aux(object->cookie), len);
     65
     66	ret = cachefiles_inject_write_error();
     67	if (ret == 0)
     68		ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
     69				   buf, sizeof(struct cachefiles_xattr) + len, 0);
     70	if (ret < 0) {
     71		trace_cachefiles_vfs_error(object, file_inode(file), ret,
     72					   cachefiles_trace_setxattr_error);
     73		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
     74					   buf->content,
     75					   cachefiles_coherency_set_fail);
     76		if (ret != -ENOMEM)
     77			cachefiles_io_error_obj(
     78				object,
     79				"Failed to set xattr with error %d", ret);
     80	} else {
     81		trace_cachefiles_coherency(object, file_inode(file)->i_ino,
     82					   buf->content,
     83					   cachefiles_coherency_set_ok);
     84	}
     85
     86	kfree(buf);
     87	_leave(" = %d", ret);
     88	return ret;
     89}
     90
     91/*
     92 * check the consistency between the backing cache and the FS-Cache cookie
     93 */
     94int cachefiles_check_auxdata(struct cachefiles_object *object, struct file *file)
     95{
     96	struct cachefiles_xattr *buf;
     97	struct dentry *dentry = file->f_path.dentry;
     98	unsigned int len = object->cookie->aux_len, tlen;
     99	const void *p = fscache_get_aux(object->cookie);
    100	enum cachefiles_coherency_trace why;
    101	ssize_t xlen;
    102	int ret = -ESTALE;
    103
    104	tlen = sizeof(struct cachefiles_xattr) + len;
    105	buf = kmalloc(tlen, GFP_KERNEL);
    106	if (!buf)
    107		return -ENOMEM;
    108
    109	xlen = cachefiles_inject_read_error();
    110	if (xlen == 0)
    111		xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, buf, tlen);
    112	if (xlen != tlen) {
    113		if (xlen < 0)
    114			trace_cachefiles_vfs_error(object, file_inode(file), xlen,
    115						   cachefiles_trace_getxattr_error);
    116		if (xlen == -EIO)
    117			cachefiles_io_error_obj(
    118				object,
    119				"Failed to read aux with error %zd", xlen);
    120		why = cachefiles_coherency_check_xattr;
    121	} else if (buf->type != CACHEFILES_COOKIE_TYPE_DATA) {
    122		why = cachefiles_coherency_check_type;
    123	} else if (memcmp(buf->data, p, len) != 0) {
    124		why = cachefiles_coherency_check_aux;
    125	} else if (be64_to_cpu(buf->object_size) != object->cookie->object_size) {
    126		why = cachefiles_coherency_check_objsize;
    127	} else if (buf->content == CACHEFILES_CONTENT_DIRTY) {
    128		// TODO: Begin conflict resolution
    129		pr_warn("Dirty object in cache\n");
    130		why = cachefiles_coherency_check_dirty;
    131	} else {
    132		why = cachefiles_coherency_check_ok;
    133		ret = 0;
    134	}
    135
    136	trace_cachefiles_coherency(object, file_inode(file)->i_ino,
    137				   buf->content, why);
    138	kfree(buf);
    139	return ret;
    140}
    141
    142/*
    143 * remove the object's xattr to mark it stale
    144 */
    145int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
    146				   struct cachefiles_object *object,
    147				   struct dentry *dentry)
    148{
    149	int ret;
    150
    151	ret = cachefiles_inject_remove_error();
    152	if (ret == 0)
    153		ret = vfs_removexattr(&init_user_ns, dentry, cachefiles_xattr_cache);
    154	if (ret < 0) {
    155		trace_cachefiles_vfs_error(object, d_inode(dentry), ret,
    156					   cachefiles_trace_remxattr_error);
    157		if (ret == -ENOENT || ret == -ENODATA)
    158			ret = 0;
    159		else if (ret != -ENOMEM)
    160			cachefiles_io_error(cache,
    161					    "Can't remove xattr from %lu"
    162					    " (error %d)",
    163					    d_backing_inode(dentry)->i_ino, -ret);
    164	}
    165
    166	_leave(" = %d", ret);
    167	return ret;
    168}
    169
    170/*
    171 * Stick a marker on the cache object to indicate that it's dirty.
    172 */
    173void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
    174{
    175	const struct cred *saved_cred;
    176	struct cachefiles_object *object = cookie->cache_priv;
    177	struct cachefiles_cache *cache = object->volume->cache;
    178
    179	_enter("c=%08x", object->cookie->debug_id);
    180
    181	if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
    182		cachefiles_begin_secure(cache, &saved_cred);
    183		cachefiles_set_object_xattr(object);
    184		cachefiles_end_secure(cache, saved_cred);
    185	}
    186}
    187
    188/*
    189 * Set the state xattr on a volume directory.
    190 */
    191bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
    192{
    193	struct cachefiles_vol_xattr *buf;
    194	unsigned int len = volume->vcookie->coherency_len;
    195	const void *p = volume->vcookie->coherency;
    196	struct dentry *dentry = volume->dentry;
    197	int ret;
    198
    199	_enter("%x,#%d", volume->vcookie->debug_id, len);
    200
    201	len += sizeof(*buf);
    202	buf = kmalloc(len, GFP_KERNEL);
    203	if (!buf)
    204		return false;
    205	buf->reserved = cpu_to_be32(0);
    206	memcpy(buf->data, p, volume->vcookie->coherency_len);
    207
    208	ret = cachefiles_inject_write_error();
    209	if (ret == 0)
    210		ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
    211				   buf, len, 0);
    212	if (ret < 0) {
    213		trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
    214					   cachefiles_trace_setxattr_error);
    215		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
    216					       cachefiles_coherency_vol_set_fail);
    217		if (ret != -ENOMEM)
    218			cachefiles_io_error(
    219				volume->cache, "Failed to set xattr with error %d", ret);
    220	} else {
    221		trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
    222					       cachefiles_coherency_vol_set_ok);
    223	}
    224
    225	kfree(buf);
    226	_leave(" = %d", ret);
    227	return ret == 0;
    228}
    229
    230/*
    231 * Check the consistency between the backing cache and the volume cookie.
    232 */
    233int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
    234{
    235	struct cachefiles_vol_xattr *buf;
    236	struct dentry *dentry = volume->dentry;
    237	unsigned int len = volume->vcookie->coherency_len;
    238	const void *p = volume->vcookie->coherency;
    239	enum cachefiles_coherency_trace why;
    240	ssize_t xlen;
    241	int ret = -ESTALE;
    242
    243	_enter("");
    244
    245	len += sizeof(*buf);
    246	buf = kmalloc(len, GFP_KERNEL);
    247	if (!buf)
    248		return -ENOMEM;
    249
    250	xlen = cachefiles_inject_read_error();
    251	if (xlen == 0)
    252		xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, buf, len);
    253	if (xlen != len) {
    254		if (xlen < 0) {
    255			trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
    256						   cachefiles_trace_getxattr_error);
    257			if (xlen == -EIO)
    258				cachefiles_io_error(
    259					volume->cache,
    260					"Failed to read xattr with error %zd", xlen);
    261		}
    262		why = cachefiles_coherency_vol_check_xattr;
    263	} else if (buf->reserved != cpu_to_be32(0)) {
    264		why = cachefiles_coherency_vol_check_resv;
    265	} else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {
    266		why = cachefiles_coherency_vol_check_cmp;
    267	} else {
    268		why = cachefiles_coherency_vol_check_ok;
    269		ret = 0;
    270	}
    271
    272	trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
    273	kfree(buf);
    274	_leave(" = %d", ret);
    275	return ret;
    276}