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

hv_fcopy.c (11793B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * An implementation of file copy service.
      4 *
      5 * Copyright (C) 2014, Microsoft, Inc.
      6 *
      7 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
      8 */
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <linux/nls.h>
     13#include <linux/workqueue.h>
     14#include <linux/hyperv.h>
     15#include <linux/sched.h>
     16#include <asm/hyperv-tlfs.h>
     17
     18#include "hyperv_vmbus.h"
     19#include "hv_utils_transport.h"
     20
     21#define WIN8_SRV_MAJOR		1
     22#define WIN8_SRV_MINOR		1
     23#define WIN8_SRV_VERSION	(WIN8_SRV_MAJOR << 16 | WIN8_SRV_MINOR)
     24
     25#define FCOPY_VER_COUNT 1
     26static const int fcopy_versions[] = {
     27	WIN8_SRV_VERSION
     28};
     29
     30#define FW_VER_COUNT 1
     31static const int fw_versions[] = {
     32	UTIL_FW_VERSION
     33};
     34
     35/*
     36 * Global state maintained for transaction that is being processed.
     37 * For a class of integration services, including the "file copy service",
     38 * the specified protocol is a "request/response" protocol which means that
     39 * there can only be single outstanding transaction from the host at any
     40 * given point in time. We use this to simplify memory management in this
     41 * driver - we cache and process only one message at a time.
     42 *
     43 * While the request/response protocol is guaranteed by the host, we further
     44 * ensure this by serializing packet processing in this driver - we do not
     45 * read additional packets from the VMBUs until the current packet is fully
     46 * handled.
     47 */
     48
     49static struct {
     50	int state;   /* hvutil_device_state */
     51	int recv_len; /* number of bytes received. */
     52	struct hv_fcopy_hdr  *fcopy_msg; /* current message */
     53	struct vmbus_channel *recv_channel; /* chn we got the request */
     54	u64 recv_req_id; /* request ID. */
     55} fcopy_transaction;
     56
     57static void fcopy_respond_to_host(int error);
     58static void fcopy_send_data(struct work_struct *dummy);
     59static void fcopy_timeout_func(struct work_struct *dummy);
     60static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
     61static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
     62static const char fcopy_devname[] = "vmbus/hv_fcopy";
     63static u8 *recv_buffer;
     64static struct hvutil_transport *hvt;
     65/*
     66 * This state maintains the version number registered by the daemon.
     67 */
     68static int dm_reg_value;
     69
     70static void fcopy_poll_wrapper(void *channel)
     71{
     72	/* Transaction is finished, reset the state here to avoid races. */
     73	fcopy_transaction.state = HVUTIL_READY;
     74	tasklet_schedule(&((struct vmbus_channel *)channel)->callback_event);
     75}
     76
     77static void fcopy_timeout_func(struct work_struct *dummy)
     78{
     79	/*
     80	 * If the timer fires, the user-mode component has not responded;
     81	 * process the pending transaction.
     82	 */
     83	fcopy_respond_to_host(HV_E_FAIL);
     84	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
     85}
     86
     87static void fcopy_register_done(void)
     88{
     89	pr_debug("FCP: userspace daemon registered\n");
     90	hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
     91}
     92
     93static int fcopy_handle_handshake(u32 version)
     94{
     95	u32 our_ver = FCOPY_CURRENT_VERSION;
     96
     97	switch (version) {
     98	case FCOPY_VERSION_0:
     99		/* Daemon doesn't expect us to reply */
    100		dm_reg_value = version;
    101		break;
    102	case FCOPY_VERSION_1:
    103		/* Daemon expects us to reply with our own version */
    104		if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
    105		    fcopy_register_done))
    106			return -EFAULT;
    107		dm_reg_value = version;
    108		break;
    109	default:
    110		/*
    111		 * For now we will fail the registration.
    112		 * If and when we have multiple versions to
    113		 * deal with, we will be backward compatible.
    114		 * We will add this code when needed.
    115		 */
    116		return -EINVAL;
    117	}
    118	pr_debug("FCP: userspace daemon ver. %d connected\n", version);
    119	return 0;
    120}
    121
    122static void fcopy_send_data(struct work_struct *dummy)
    123{
    124	struct hv_start_fcopy *smsg_out = NULL;
    125	int operation = fcopy_transaction.fcopy_msg->operation;
    126	struct hv_start_fcopy *smsg_in;
    127	void *out_src;
    128	int rc, out_len;
    129
    130	/*
    131	 * The  strings sent from the host are encoded in
    132	 * in utf16; convert it to utf8 strings.
    133	 * The host assures us that the utf16 strings will not exceed
    134	 * the max lengths specified. We will however, reserve room
    135	 * for the string terminating character - in the utf16s_utf8s()
    136	 * function we limit the size of the buffer where the converted
    137	 * string is placed to W_MAX_PATH -1 to guarantee
    138	 * that the strings can be properly terminated!
    139	 */
    140
    141	switch (operation) {
    142	case START_FILE_COPY:
    143		out_len = sizeof(struct hv_start_fcopy);
    144		smsg_out = kzalloc(sizeof(*smsg_out), GFP_KERNEL);
    145		if (!smsg_out)
    146			return;
    147
    148		smsg_out->hdr.operation = operation;
    149		smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
    150
    151		utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
    152				UTF16_LITTLE_ENDIAN,
    153				(__u8 *)&smsg_out->file_name, W_MAX_PATH - 1);
    154
    155		utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
    156				UTF16_LITTLE_ENDIAN,
    157				(__u8 *)&smsg_out->path_name, W_MAX_PATH - 1);
    158
    159		smsg_out->copy_flags = smsg_in->copy_flags;
    160		smsg_out->file_size = smsg_in->file_size;
    161		out_src = smsg_out;
    162		break;
    163
    164	case WRITE_TO_FILE:
    165		out_src = fcopy_transaction.fcopy_msg;
    166		out_len = sizeof(struct hv_do_fcopy);
    167		break;
    168	default:
    169		out_src = fcopy_transaction.fcopy_msg;
    170		out_len = fcopy_transaction.recv_len;
    171		break;
    172	}
    173
    174	fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
    175	rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
    176	if (rc) {
    177		pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
    178		if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
    179			fcopy_respond_to_host(HV_E_FAIL);
    180			fcopy_transaction.state = HVUTIL_READY;
    181		}
    182	}
    183	kfree(smsg_out);
    184}
    185
    186/*
    187 * Send a response back to the host.
    188 */
    189
    190static void
    191fcopy_respond_to_host(int error)
    192{
    193	struct icmsg_hdr *icmsghdr;
    194	u32 buf_len;
    195	struct vmbus_channel *channel;
    196	u64 req_id;
    197
    198	/*
    199	 * Copy the global state for completing the transaction. Note that
    200	 * only one transaction can be active at a time. This is guaranteed
    201	 * by the file copy protocol implemented by the host. Furthermore,
    202	 * the "transaction active" state we maintain ensures that there can
    203	 * only be one active transaction at a time.
    204	 */
    205
    206	buf_len = fcopy_transaction.recv_len;
    207	channel = fcopy_transaction.recv_channel;
    208	req_id = fcopy_transaction.recv_req_id;
    209
    210	icmsghdr = (struct icmsg_hdr *)
    211			&recv_buffer[sizeof(struct vmbuspipe_hdr)];
    212
    213	if (channel->onchannel_callback == NULL)
    214		/*
    215		 * We have raced with util driver being unloaded;
    216		 * silently return.
    217		 */
    218		return;
    219
    220	icmsghdr->status = error;
    221	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
    222	vmbus_sendpacket(channel, recv_buffer, buf_len, req_id,
    223				VM_PKT_DATA_INBAND, 0);
    224}
    225
    226void hv_fcopy_onchannelcallback(void *context)
    227{
    228	struct vmbus_channel *channel = context;
    229	u32 recvlen;
    230	u64 requestid;
    231	struct hv_fcopy_hdr *fcopy_msg;
    232	struct icmsg_hdr *icmsghdr;
    233	int fcopy_srv_version;
    234
    235	if (fcopy_transaction.state > HVUTIL_READY)
    236		return;
    237
    238	if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) {
    239		pr_err_ratelimited("Fcopy request received. Could not read into recv buf\n");
    240		return;
    241	}
    242
    243	if (!recvlen)
    244		return;
    245
    246	/* Ensure recvlen is big enough to read header data */
    247	if (recvlen < ICMSG_HDR) {
    248		pr_err_ratelimited("Fcopy request received. Packet length too small: %d\n",
    249				   recvlen);
    250		return;
    251	}
    252
    253	icmsghdr = (struct icmsg_hdr *)&recv_buffer[
    254			sizeof(struct vmbuspipe_hdr)];
    255
    256	if (icmsghdr->icmsgtype == ICMSGTYPE_NEGOTIATE) {
    257		if (vmbus_prep_negotiate_resp(icmsghdr,
    258				recv_buffer, recvlen,
    259				fw_versions, FW_VER_COUNT,
    260				fcopy_versions, FCOPY_VER_COUNT,
    261				NULL, &fcopy_srv_version)) {
    262
    263			pr_info("FCopy IC version %d.%d\n",
    264				fcopy_srv_version >> 16,
    265				fcopy_srv_version & 0xFFFF);
    266		}
    267	} else if (icmsghdr->icmsgtype == ICMSGTYPE_FCOPY) {
    268		/* Ensure recvlen is big enough to contain hv_fcopy_hdr */
    269		if (recvlen < ICMSG_HDR + sizeof(struct hv_fcopy_hdr)) {
    270			pr_err_ratelimited("Invalid Fcopy hdr. Packet length too small: %u\n",
    271					   recvlen);
    272			return;
    273		}
    274		fcopy_msg = (struct hv_fcopy_hdr *)&recv_buffer[ICMSG_HDR];
    275
    276		/*
    277		 * Stash away this global state for completing the
    278		 * transaction; note transactions are serialized.
    279		 */
    280
    281		fcopy_transaction.recv_len = recvlen;
    282		fcopy_transaction.recv_req_id = requestid;
    283		fcopy_transaction.fcopy_msg = fcopy_msg;
    284
    285		if (fcopy_transaction.state < HVUTIL_READY) {
    286			/* Userspace is not registered yet */
    287			fcopy_respond_to_host(HV_E_FAIL);
    288			return;
    289		}
    290		fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
    291
    292		/*
    293		 * Send the information to the user-level daemon.
    294		 */
    295		schedule_work(&fcopy_send_work);
    296		schedule_delayed_work(&fcopy_timeout_work,
    297				      HV_UTIL_TIMEOUT * HZ);
    298		return;
    299	} else {
    300		pr_err_ratelimited("Fcopy request received. Invalid msg type: %d\n",
    301				   icmsghdr->icmsgtype);
    302		return;
    303	}
    304	icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
    305	vmbus_sendpacket(channel, recv_buffer, recvlen, requestid,
    306			VM_PKT_DATA_INBAND, 0);
    307}
    308
    309/* Callback when data is received from userspace */
    310static int fcopy_on_msg(void *msg, int len)
    311{
    312	int *val = (int *)msg;
    313
    314	if (len != sizeof(int))
    315		return -EINVAL;
    316
    317	if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
    318		return fcopy_handle_handshake(*val);
    319
    320	if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
    321		return -EINVAL;
    322
    323	/*
    324	 * Complete the transaction by forwarding the result
    325	 * to the host. But first, cancel the timeout.
    326	 */
    327	if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
    328		fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
    329		fcopy_respond_to_host(*val);
    330		hv_poll_channel(fcopy_transaction.recv_channel,
    331				fcopy_poll_wrapper);
    332	}
    333
    334	return 0;
    335}
    336
    337static void fcopy_on_reset(void)
    338{
    339	/*
    340	 * The daemon has exited; reset the state.
    341	 */
    342	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
    343
    344	if (cancel_delayed_work_sync(&fcopy_timeout_work))
    345		fcopy_respond_to_host(HV_E_FAIL);
    346}
    347
    348int hv_fcopy_init(struct hv_util_service *srv)
    349{
    350	recv_buffer = srv->recv_buffer;
    351	fcopy_transaction.recv_channel = srv->channel;
    352	fcopy_transaction.recv_channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2;
    353
    354	/*
    355	 * When this driver loads, the user level daemon that
    356	 * processes the host requests may not yet be running.
    357	 * Defer processing channel callbacks until the daemon
    358	 * has registered.
    359	 */
    360	fcopy_transaction.state = HVUTIL_DEVICE_INIT;
    361
    362	hvt = hvutil_transport_init(fcopy_devname, 0, 0,
    363				    fcopy_on_msg, fcopy_on_reset);
    364	if (!hvt)
    365		return -EFAULT;
    366
    367	return 0;
    368}
    369
    370static void hv_fcopy_cancel_work(void)
    371{
    372	cancel_delayed_work_sync(&fcopy_timeout_work);
    373	cancel_work_sync(&fcopy_send_work);
    374}
    375
    376int hv_fcopy_pre_suspend(void)
    377{
    378	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
    379	struct hv_fcopy_hdr *fcopy_msg;
    380
    381	/*
    382	 * Fake a CANCEL_FCOPY message for the user space daemon in case the
    383	 * daemon is in the middle of copying some file. It doesn't matter if
    384	 * there is already a message pending to be delivered to the user
    385	 * space since we force fcopy_transaction.state to be HVUTIL_READY, so
    386	 * the user space daemon's write() will fail with EINVAL (see
    387	 * fcopy_on_msg()), and the daemon will reset the device by closing
    388	 * and re-opening it.
    389	 */
    390	fcopy_msg = kzalloc(sizeof(*fcopy_msg), GFP_KERNEL);
    391	if (!fcopy_msg)
    392		return -ENOMEM;
    393
    394	tasklet_disable(&channel->callback_event);
    395
    396	fcopy_msg->operation = CANCEL_FCOPY;
    397
    398	hv_fcopy_cancel_work();
    399
    400	/* We don't care about the return value. */
    401	hvutil_transport_send(hvt, fcopy_msg, sizeof(*fcopy_msg), NULL);
    402
    403	kfree(fcopy_msg);
    404
    405	fcopy_transaction.state = HVUTIL_READY;
    406
    407	/* tasklet_enable() will be called in hv_fcopy_pre_resume(). */
    408	return 0;
    409}
    410
    411int hv_fcopy_pre_resume(void)
    412{
    413	struct vmbus_channel *channel = fcopy_transaction.recv_channel;
    414
    415	tasklet_enable(&channel->callback_event);
    416
    417	return 0;
    418}
    419
    420void hv_fcopy_deinit(void)
    421{
    422	fcopy_transaction.state = HVUTIL_DEVICE_DYING;
    423
    424	hv_fcopy_cancel_work();
    425
    426	hvutil_transport_destroy(hvt);
    427}