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

vhci_sysfs.c (12450B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2003-2008 Takahiro Hirofuchi
      4 * Copyright (C) 2015-2016 Nobuo Iwata
      5 */
      6
      7#include <linux/kthread.h>
      8#include <linux/file.h>
      9#include <linux/net.h>
     10#include <linux/platform_device.h>
     11#include <linux/slab.h>
     12
     13/* Hardening for Spectre-v1 */
     14#include <linux/nospec.h>
     15
     16#include "usbip_common.h"
     17#include "vhci.h"
     18
     19/* TODO: refine locking ?*/
     20
     21/*
     22 * output example:
     23 * hub port sta spd dev       sockfd local_busid
     24 * hs  0000 004 000 00000000  000003 1-2.3
     25 * ................................................
     26 * ss  0008 004 000 00000000  000004 2-3.4
     27 * ................................................
     28 *
     29 * Output includes socket fd instead of socket pointer address to avoid
     30 * leaking kernel memory address in:
     31 *	/sys/devices/platform/vhci_hcd.0/status and in debug output.
     32 * The socket pointer address is not used at the moment and it was made
     33 * visible as a convenient way to find IP address from socket pointer
     34 * address by looking up /proc/net/{tcp,tcp6}. As this opens a security
     35 * hole, the change is made to use sockfd instead.
     36 *
     37 */
     38static void port_show_vhci(char **out, int hub, int port, struct vhci_device *vdev)
     39{
     40	if (hub == HUB_SPEED_HIGH)
     41		*out += sprintf(*out, "hs  %04u %03u ",
     42				      port, vdev->ud.status);
     43	else /* hub == HUB_SPEED_SUPER */
     44		*out += sprintf(*out, "ss  %04u %03u ",
     45				      port, vdev->ud.status);
     46
     47	if (vdev->ud.status == VDEV_ST_USED) {
     48		*out += sprintf(*out, "%03u %08x ",
     49				      vdev->speed, vdev->devid);
     50		*out += sprintf(*out, "%06u %s",
     51				      vdev->ud.sockfd,
     52				      dev_name(&vdev->udev->dev));
     53
     54	} else {
     55		*out += sprintf(*out, "000 00000000 ");
     56		*out += sprintf(*out, "000000 0-0");
     57	}
     58
     59	*out += sprintf(*out, "\n");
     60}
     61
     62/* Sysfs entry to show port status */
     63static ssize_t status_show_vhci(int pdev_nr, char *out)
     64{
     65	struct platform_device *pdev = vhcis[pdev_nr].pdev;
     66	struct vhci *vhci;
     67	struct usb_hcd *hcd;
     68	struct vhci_hcd *vhci_hcd;
     69	char *s = out;
     70	int i;
     71	unsigned long flags;
     72
     73	if (!pdev || !out) {
     74		usbip_dbg_vhci_sysfs("show status error\n");
     75		return 0;
     76	}
     77
     78	hcd = platform_get_drvdata(pdev);
     79	vhci_hcd = hcd_to_vhci_hcd(hcd);
     80	vhci = vhci_hcd->vhci;
     81
     82	spin_lock_irqsave(&vhci->lock, flags);
     83
     84	for (i = 0; i < VHCI_HC_PORTS; i++) {
     85		struct vhci_device *vdev = &vhci->vhci_hcd_hs->vdev[i];
     86
     87		spin_lock(&vdev->ud.lock);
     88		port_show_vhci(&out, HUB_SPEED_HIGH,
     89			       pdev_nr * VHCI_PORTS + i, vdev);
     90		spin_unlock(&vdev->ud.lock);
     91	}
     92
     93	for (i = 0; i < VHCI_HC_PORTS; i++) {
     94		struct vhci_device *vdev = &vhci->vhci_hcd_ss->vdev[i];
     95
     96		spin_lock(&vdev->ud.lock);
     97		port_show_vhci(&out, HUB_SPEED_SUPER,
     98			       pdev_nr * VHCI_PORTS + VHCI_HC_PORTS + i, vdev);
     99		spin_unlock(&vdev->ud.lock);
    100	}
    101
    102	spin_unlock_irqrestore(&vhci->lock, flags);
    103
    104	return out - s;
    105}
    106
    107static ssize_t status_show_not_ready(int pdev_nr, char *out)
    108{
    109	char *s = out;
    110	int i = 0;
    111
    112	for (i = 0; i < VHCI_HC_PORTS; i++) {
    113		out += sprintf(out, "hs  %04u %03u ",
    114				    (pdev_nr * VHCI_PORTS) + i,
    115				    VDEV_ST_NOTASSIGNED);
    116		out += sprintf(out, "000 00000000 0000000000000000 0-0");
    117		out += sprintf(out, "\n");
    118	}
    119
    120	for (i = 0; i < VHCI_HC_PORTS; i++) {
    121		out += sprintf(out, "ss  %04u %03u ",
    122				    (pdev_nr * VHCI_PORTS) + VHCI_HC_PORTS + i,
    123				    VDEV_ST_NOTASSIGNED);
    124		out += sprintf(out, "000 00000000 0000000000000000 0-0");
    125		out += sprintf(out, "\n");
    126	}
    127	return out - s;
    128}
    129
    130static int status_name_to_id(const char *name)
    131{
    132	char *c;
    133	long val;
    134	int ret;
    135
    136	c = strchr(name, '.');
    137	if (c == NULL)
    138		return 0;
    139
    140	ret = kstrtol(c+1, 10, &val);
    141	if (ret < 0)
    142		return ret;
    143
    144	return val;
    145}
    146
    147static ssize_t status_show(struct device *dev,
    148			   struct device_attribute *attr, char *out)
    149{
    150	char *s = out;
    151	int pdev_nr;
    152
    153	out += sprintf(out,
    154		       "hub port sta spd dev      sockfd local_busid\n");
    155
    156	pdev_nr = status_name_to_id(attr->attr.name);
    157	if (pdev_nr < 0)
    158		out += status_show_not_ready(pdev_nr, out);
    159	else
    160		out += status_show_vhci(pdev_nr, out);
    161
    162	return out - s;
    163}
    164
    165static ssize_t nports_show(struct device *dev, struct device_attribute *attr,
    166			   char *out)
    167{
    168	char *s = out;
    169
    170	/*
    171	 * Half the ports are for SPEED_HIGH and half for SPEED_SUPER,
    172	 * thus the * 2.
    173	 */
    174	out += sprintf(out, "%d\n", VHCI_PORTS * vhci_num_controllers);
    175	return out - s;
    176}
    177static DEVICE_ATTR_RO(nports);
    178
    179/* Sysfs entry to shutdown a virtual connection */
    180static int vhci_port_disconnect(struct vhci_hcd *vhci_hcd, __u32 rhport)
    181{
    182	struct vhci_device *vdev = &vhci_hcd->vdev[rhport];
    183	struct vhci *vhci = vhci_hcd->vhci;
    184	unsigned long flags;
    185
    186	usbip_dbg_vhci_sysfs("enter\n");
    187
    188	mutex_lock(&vdev->ud.sysfs_lock);
    189
    190	/* lock */
    191	spin_lock_irqsave(&vhci->lock, flags);
    192	spin_lock(&vdev->ud.lock);
    193
    194	if (vdev->ud.status == VDEV_ST_NULL) {
    195		pr_err("not connected %d\n", vdev->ud.status);
    196
    197		/* unlock */
    198		spin_unlock(&vdev->ud.lock);
    199		spin_unlock_irqrestore(&vhci->lock, flags);
    200		mutex_unlock(&vdev->ud.sysfs_lock);
    201
    202		return -EINVAL;
    203	}
    204
    205	/* unlock */
    206	spin_unlock(&vdev->ud.lock);
    207	spin_unlock_irqrestore(&vhci->lock, flags);
    208
    209	usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
    210
    211	mutex_unlock(&vdev->ud.sysfs_lock);
    212
    213	return 0;
    214}
    215
    216static int valid_port(__u32 *pdev_nr, __u32 *rhport)
    217{
    218	if (*pdev_nr >= vhci_num_controllers) {
    219		pr_err("pdev %u\n", *pdev_nr);
    220		return 0;
    221	}
    222	*pdev_nr = array_index_nospec(*pdev_nr, vhci_num_controllers);
    223
    224	if (*rhport >= VHCI_HC_PORTS) {
    225		pr_err("rhport %u\n", *rhport);
    226		return 0;
    227	}
    228	*rhport = array_index_nospec(*rhport, VHCI_HC_PORTS);
    229
    230	return 1;
    231}
    232
    233static ssize_t detach_store(struct device *dev, struct device_attribute *attr,
    234			    const char *buf, size_t count)
    235{
    236	__u32 port = 0, pdev_nr = 0, rhport = 0;
    237	struct usb_hcd *hcd;
    238	struct vhci_hcd *vhci_hcd;
    239	int ret;
    240
    241	if (kstrtoint(buf, 10, &port) < 0)
    242		return -EINVAL;
    243
    244	pdev_nr = port_to_pdev_nr(port);
    245	rhport = port_to_rhport(port);
    246
    247	if (!valid_port(&pdev_nr, &rhport))
    248		return -EINVAL;
    249
    250	hcd = platform_get_drvdata(vhcis[pdev_nr].pdev);
    251	if (hcd == NULL) {
    252		dev_err(dev, "port is not ready %u\n", port);
    253		return -EAGAIN;
    254	}
    255
    256	usbip_dbg_vhci_sysfs("rhport %d\n", rhport);
    257
    258	if ((port / VHCI_HC_PORTS) % 2)
    259		vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_ss;
    260	else
    261		vhci_hcd = hcd_to_vhci_hcd(hcd)->vhci->vhci_hcd_hs;
    262
    263	ret = vhci_port_disconnect(vhci_hcd, rhport);
    264	if (ret < 0)
    265		return -EINVAL;
    266
    267	usbip_dbg_vhci_sysfs("Leave\n");
    268
    269	return count;
    270}
    271static DEVICE_ATTR_WO(detach);
    272
    273static int valid_args(__u32 *pdev_nr, __u32 *rhport,
    274		      enum usb_device_speed speed)
    275{
    276	if (!valid_port(pdev_nr, rhport)) {
    277		return 0;
    278	}
    279
    280	switch (speed) {
    281	case USB_SPEED_LOW:
    282	case USB_SPEED_FULL:
    283	case USB_SPEED_HIGH:
    284	case USB_SPEED_WIRELESS:
    285	case USB_SPEED_SUPER:
    286		break;
    287	default:
    288		pr_err("Failed attach request for unsupported USB speed: %s\n",
    289			usb_speed_string(speed));
    290		return 0;
    291	}
    292
    293	return 1;
    294}
    295
    296/* Sysfs entry to establish a virtual connection */
    297/*
    298 * To start a new USB/IP attachment, a userland program needs to setup a TCP
    299 * connection and then write its socket descriptor with remote device
    300 * information into this sysfs file.
    301 *
    302 * A remote device is virtually attached to the root-hub port of @rhport with
    303 * @speed. @devid is embedded into a request to specify the remote device in a
    304 * server host.
    305 *
    306 * write() returns 0 on success, else negative errno.
    307 */
    308static ssize_t attach_store(struct device *dev, struct device_attribute *attr,
    309			    const char *buf, size_t count)
    310{
    311	struct socket *socket;
    312	int sockfd = 0;
    313	__u32 port = 0, pdev_nr = 0, rhport = 0, devid = 0, speed = 0;
    314	struct usb_hcd *hcd;
    315	struct vhci_hcd *vhci_hcd;
    316	struct vhci_device *vdev;
    317	struct vhci *vhci;
    318	int err;
    319	unsigned long flags;
    320	struct task_struct *tcp_rx = NULL;
    321	struct task_struct *tcp_tx = NULL;
    322
    323	/*
    324	 * @rhport: port number of vhci_hcd
    325	 * @sockfd: socket descriptor of an established TCP connection
    326	 * @devid: unique device identifier in a remote host
    327	 * @speed: usb device speed in a remote host
    328	 */
    329	if (sscanf(buf, "%u %u %u %u", &port, &sockfd, &devid, &speed) != 4)
    330		return -EINVAL;
    331	pdev_nr = port_to_pdev_nr(port);
    332	rhport = port_to_rhport(port);
    333
    334	usbip_dbg_vhci_sysfs("port(%u) pdev(%d) rhport(%u)\n",
    335			     port, pdev_nr, rhport);
    336	usbip_dbg_vhci_sysfs("sockfd(%u) devid(%u) speed(%u)\n",
    337			     sockfd, devid, speed);
    338
    339	/* check received parameters */
    340	if (!valid_args(&pdev_nr, &rhport, speed))
    341		return -EINVAL;
    342
    343	hcd = platform_get_drvdata(vhcis[pdev_nr].pdev);
    344	if (hcd == NULL) {
    345		dev_err(dev, "port %d is not ready\n", port);
    346		return -EAGAIN;
    347	}
    348
    349	vhci_hcd = hcd_to_vhci_hcd(hcd);
    350	vhci = vhci_hcd->vhci;
    351
    352	if (speed == USB_SPEED_SUPER)
    353		vdev = &vhci->vhci_hcd_ss->vdev[rhport];
    354	else
    355		vdev = &vhci->vhci_hcd_hs->vdev[rhport];
    356
    357	mutex_lock(&vdev->ud.sysfs_lock);
    358
    359	/* Extract socket from fd. */
    360	socket = sockfd_lookup(sockfd, &err);
    361	if (!socket) {
    362		dev_err(dev, "failed to lookup sock");
    363		err = -EINVAL;
    364		goto unlock_mutex;
    365	}
    366	if (socket->type != SOCK_STREAM) {
    367		dev_err(dev, "Expecting SOCK_STREAM - found %d",
    368			socket->type);
    369		sockfd_put(socket);
    370		err = -EINVAL;
    371		goto unlock_mutex;
    372	}
    373
    374	/* create threads before locking */
    375	tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx");
    376	if (IS_ERR(tcp_rx)) {
    377		sockfd_put(socket);
    378		err = -EINVAL;
    379		goto unlock_mutex;
    380	}
    381	tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx");
    382	if (IS_ERR(tcp_tx)) {
    383		kthread_stop(tcp_rx);
    384		sockfd_put(socket);
    385		err = -EINVAL;
    386		goto unlock_mutex;
    387	}
    388
    389	/* get task structs now */
    390	get_task_struct(tcp_rx);
    391	get_task_struct(tcp_tx);
    392
    393	/* now begin lock until setting vdev status set */
    394	spin_lock_irqsave(&vhci->lock, flags);
    395	spin_lock(&vdev->ud.lock);
    396
    397	if (vdev->ud.status != VDEV_ST_NULL) {
    398		/* end of the lock */
    399		spin_unlock(&vdev->ud.lock);
    400		spin_unlock_irqrestore(&vhci->lock, flags);
    401
    402		sockfd_put(socket);
    403		kthread_stop_put(tcp_rx);
    404		kthread_stop_put(tcp_tx);
    405
    406		dev_err(dev, "port %d already used\n", rhport);
    407		/*
    408		 * Will be retried from userspace
    409		 * if there's another free port.
    410		 */
    411		err = -EBUSY;
    412		goto unlock_mutex;
    413	}
    414
    415	dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n",
    416		 pdev_nr, rhport, sockfd);
    417	dev_info(dev, "devid(%u) speed(%u) speed_str(%s)\n",
    418		 devid, speed, usb_speed_string(speed));
    419
    420	vdev->devid         = devid;
    421	vdev->speed         = speed;
    422	vdev->ud.sockfd     = sockfd;
    423	vdev->ud.tcp_socket = socket;
    424	vdev->ud.tcp_rx     = tcp_rx;
    425	vdev->ud.tcp_tx     = tcp_tx;
    426	vdev->ud.status     = VDEV_ST_NOTASSIGNED;
    427	usbip_kcov_handle_init(&vdev->ud);
    428
    429	spin_unlock(&vdev->ud.lock);
    430	spin_unlock_irqrestore(&vhci->lock, flags);
    431	/* end the lock */
    432
    433	wake_up_process(vdev->ud.tcp_rx);
    434	wake_up_process(vdev->ud.tcp_tx);
    435
    436	rh_port_connect(vdev, speed);
    437
    438	dev_info(dev, "Device attached\n");
    439
    440	mutex_unlock(&vdev->ud.sysfs_lock);
    441
    442	return count;
    443
    444unlock_mutex:
    445	mutex_unlock(&vdev->ud.sysfs_lock);
    446	return err;
    447}
    448static DEVICE_ATTR_WO(attach);
    449
    450#define MAX_STATUS_NAME 16
    451
    452struct status_attr {
    453	struct device_attribute attr;
    454	char name[MAX_STATUS_NAME+1];
    455};
    456
    457static struct status_attr *status_attrs;
    458
    459static void set_status_attr(int id)
    460{
    461	struct status_attr *status;
    462
    463	status = status_attrs + id;
    464	if (id == 0)
    465		strcpy(status->name, "status");
    466	else
    467		snprintf(status->name, MAX_STATUS_NAME+1, "status.%d", id);
    468	status->attr.attr.name = status->name;
    469	status->attr.attr.mode = S_IRUGO;
    470	status->attr.show = status_show;
    471	sysfs_attr_init(&status->attr.attr);
    472}
    473
    474static int init_status_attrs(void)
    475{
    476	int id;
    477
    478	status_attrs = kcalloc(vhci_num_controllers, sizeof(struct status_attr),
    479			       GFP_KERNEL);
    480	if (status_attrs == NULL)
    481		return -ENOMEM;
    482
    483	for (id = 0; id < vhci_num_controllers; id++)
    484		set_status_attr(id);
    485
    486	return 0;
    487}
    488
    489static void finish_status_attrs(void)
    490{
    491	kfree(status_attrs);
    492}
    493
    494struct attribute_group vhci_attr_group = {
    495	.attrs = NULL,
    496};
    497
    498int vhci_init_attr_group(void)
    499{
    500	struct attribute **attrs;
    501	int ret, i;
    502
    503	attrs = kcalloc((vhci_num_controllers + 5), sizeof(struct attribute *),
    504			GFP_KERNEL);
    505	if (attrs == NULL)
    506		return -ENOMEM;
    507
    508	ret = init_status_attrs();
    509	if (ret) {
    510		kfree(attrs);
    511		return ret;
    512	}
    513	*attrs = &dev_attr_nports.attr;
    514	*(attrs + 1) = &dev_attr_detach.attr;
    515	*(attrs + 2) = &dev_attr_attach.attr;
    516	*(attrs + 3) = &dev_attr_usbip_debug.attr;
    517	for (i = 0; i < vhci_num_controllers; i++)
    518		*(attrs + i + 4) = &((status_attrs + i)->attr.attr);
    519	vhci_attr_group.attrs = attrs;
    520	return 0;
    521}
    522
    523void vhci_finish_attr_group(void)
    524{
    525	finish_status_attrs();
    526	kfree(vhci_attr_group.attrs);
    527}