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

port_user.c (4170B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com)
      4 */
      5
      6#include <stdio.h>
      7#include <stdlib.h>
      8#include <string.h>
      9#include <errno.h>
     10#include <termios.h>
     11#include <unistd.h>
     12#include <netinet/in.h>
     13#include "chan_user.h"
     14#include <os.h>
     15#include "port.h"
     16#include <um_malloc.h>
     17
     18struct port_chan {
     19	int raw;
     20	struct termios tt;
     21	void *kernel_data;
     22	char dev[sizeof("32768\0")];
     23};
     24
     25static void *port_init(char *str, int device, const struct chan_opts *opts)
     26{
     27	struct port_chan *data;
     28	void *kern_data;
     29	char *end;
     30	int port;
     31
     32	if (*str != ':') {
     33		printk(UM_KERN_ERR "port_init : channel type 'port' must "
     34		       "specify a port number\n");
     35		return NULL;
     36	}
     37	str++;
     38	port = strtoul(str, &end, 0);
     39	if ((*end != '\0') || (end == str)) {
     40		printk(UM_KERN_ERR "port_init : couldn't parse port '%s'\n",
     41		       str);
     42		return NULL;
     43	}
     44
     45	kern_data = port_data(port);
     46	if (kern_data == NULL)
     47		return NULL;
     48
     49	data = uml_kmalloc(sizeof(*data), UM_GFP_KERNEL);
     50	if (data == NULL)
     51		goto err;
     52
     53	*data = ((struct port_chan) { .raw  		= opts->raw,
     54				      .kernel_data 	= kern_data });
     55	sprintf(data->dev, "%d", port);
     56
     57	return data;
     58 err:
     59	port_kern_free(kern_data);
     60	return NULL;
     61}
     62
     63static void port_free(void *d)
     64{
     65	struct port_chan *data = d;
     66
     67	port_kern_free(data->kernel_data);
     68	kfree(data);
     69}
     70
     71static int port_open(int input, int output, int primary, void *d,
     72		     char **dev_out)
     73{
     74	struct port_chan *data = d;
     75	int fd, err;
     76
     77	fd = port_wait(data->kernel_data);
     78	if ((fd >= 0) && data->raw) {
     79		CATCH_EINTR(err = tcgetattr(fd, &data->tt));
     80		if (err)
     81			return err;
     82
     83		err = raw(fd);
     84		if (err)
     85			return err;
     86	}
     87	*dev_out = data->dev;
     88	return fd;
     89}
     90
     91static void port_close(int fd, void *d)
     92{
     93	struct port_chan *data = d;
     94
     95	port_remove_dev(data->kernel_data);
     96	os_close_file(fd);
     97}
     98
     99const struct chan_ops port_ops = {
    100	.type		= "port",
    101	.init		= port_init,
    102	.open		= port_open,
    103	.close		= port_close,
    104	.read	        = generic_read,
    105	.write		= generic_write,
    106	.console_write	= generic_console_write,
    107	.window_size	= generic_window_size,
    108	.free		= port_free,
    109	.winch		= 1,
    110};
    111
    112int port_listen_fd(int port)
    113{
    114	struct sockaddr_in addr;
    115	int fd, err, arg;
    116
    117	fd = socket(PF_INET, SOCK_STREAM, 0);
    118	if (fd == -1)
    119		return -errno;
    120
    121	arg = 1;
    122	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0) {
    123		err = -errno;
    124		goto out;
    125	}
    126
    127	addr.sin_family = AF_INET;
    128	addr.sin_port = htons(port);
    129	addr.sin_addr.s_addr = htonl(INADDR_ANY);
    130	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    131		err = -errno;
    132		goto out;
    133	}
    134
    135	if (listen(fd, 1) < 0) {
    136		err = -errno;
    137		goto out;
    138	}
    139
    140	err = os_set_fd_block(fd, 0);
    141	if (err < 0)
    142		goto out;
    143
    144	return fd;
    145 out:
    146	close(fd);
    147	return err;
    148}
    149
    150struct port_pre_exec_data {
    151	int sock_fd;
    152	int pipe_fd;
    153};
    154
    155static void port_pre_exec(void *arg)
    156{
    157	struct port_pre_exec_data *data = arg;
    158
    159	dup2(data->sock_fd, 0);
    160	dup2(data->sock_fd, 1);
    161	dup2(data->sock_fd, 2);
    162	close(data->sock_fd);
    163	dup2(data->pipe_fd, 3);
    164	shutdown(3, SHUT_RD);
    165	close(data->pipe_fd);
    166}
    167
    168int port_connection(int fd, int *socket, int *pid_out)
    169{
    170	int new, err;
    171	char *env;
    172	char *argv[] = { "in.telnetd", "-L",
    173			 OS_LIB_PATH "/uml/port-helper", NULL };
    174	struct port_pre_exec_data data;
    175
    176	if ((env = getenv("UML_PORT_HELPER")))
    177		argv[2] = env;
    178
    179	new = accept(fd, NULL, 0);
    180	if (new < 0)
    181		return -errno;
    182
    183	err = os_access(argv[2], X_OK);
    184	if (err < 0) {
    185		printk(UM_KERN_ERR "port_connection : error accessing port-helper "
    186		       "executable at %s: %s\n", argv[2], strerror(-err));
    187		if (env == NULL)
    188			printk(UM_KERN_ERR "Set UML_PORT_HELPER environment "
    189				"variable to path to uml-utilities port-helper "
    190				"binary\n");
    191		goto out_close;
    192	}
    193
    194	err = os_pipe(socket, 0, 0);
    195	if (err < 0)
    196		goto out_close;
    197
    198	data = ((struct port_pre_exec_data)
    199		{ .sock_fd  		= new,
    200		  .pipe_fd 		= socket[1] });
    201
    202	err = run_helper(port_pre_exec, &data, argv);
    203	if (err < 0)
    204		goto out_shutdown;
    205
    206	*pid_out = err;
    207	return new;
    208
    209 out_shutdown:
    210	shutdown(socket[0], SHUT_RDWR);
    211	close(socket[0]);
    212	shutdown(socket[1], SHUT_RDWR);
    213	close(socket[1]);
    214 out_close:
    215	close(new);
    216	return err;
    217}