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

helper.c (3938B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
      4 */
      5
      6#include <stdlib.h>
      7#include <string.h>
      8#include <unistd.h>
      9#include <errno.h>
     10#include <sched.h>
     11#include <linux/limits.h>
     12#include <sys/socket.h>
     13#include <sys/wait.h>
     14#include <kern_util.h>
     15#include <os.h>
     16#include <um_malloc.h>
     17
     18struct helper_data {
     19	void (*pre_exec)(void*);
     20	void *pre_data;
     21	char **argv;
     22	int fd;
     23	char *buf;
     24};
     25
     26static int helper_child(void *arg)
     27{
     28	struct helper_data *data = arg;
     29	char **argv = data->argv;
     30	int err, ret;
     31
     32	if (data->pre_exec != NULL)
     33		(*data->pre_exec)(data->pre_data);
     34	err = execvp_noalloc(data->buf, argv[0], argv);
     35
     36	/* If the exec succeeds, we don't get here */
     37	CATCH_EINTR(ret = write(data->fd, &err, sizeof(err)));
     38
     39	return 0;
     40}
     41
     42/* Returns either the pid of the child process we run or -E* on failure. */
     43int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
     44{
     45	struct helper_data data;
     46	unsigned long stack, sp;
     47	int pid, fds[2], ret, n;
     48
     49	stack = alloc_stack(0, __cant_sleep());
     50	if (stack == 0)
     51		return -ENOMEM;
     52
     53	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
     54	if (ret < 0) {
     55		ret = -errno;
     56		printk(UM_KERN_ERR "run_helper : pipe failed, errno = %d\n",
     57		       errno);
     58		goto out_free;
     59	}
     60
     61	ret = os_set_exec_close(fds[1]);
     62	if (ret < 0) {
     63		printk(UM_KERN_ERR "run_helper : setting FD_CLOEXEC failed, "
     64		       "ret = %d\n", -ret);
     65		goto out_close;
     66	}
     67
     68	sp = stack + UM_KERN_PAGE_SIZE;
     69	data.pre_exec = pre_exec;
     70	data.pre_data = pre_data;
     71	data.argv = argv;
     72	data.fd = fds[1];
     73	data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
     74					uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
     75	pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
     76	if (pid < 0) {
     77		ret = -errno;
     78		printk(UM_KERN_ERR "run_helper : clone failed, errno = %d\n",
     79		       errno);
     80		goto out_free2;
     81	}
     82
     83	close(fds[1]);
     84	fds[1] = -1;
     85
     86	/*
     87	 * Read the errno value from the child, if the exec failed, or get 0 if
     88	 * the exec succeeded because the pipe fd was set as close-on-exec.
     89	 */
     90	n = read(fds[0], &ret, sizeof(ret));
     91	if (n == 0) {
     92		ret = pid;
     93	} else {
     94		if (n < 0) {
     95			n = -errno;
     96			printk(UM_KERN_ERR "run_helper : read on pipe failed, "
     97			       "ret = %d\n", -n);
     98			ret = n;
     99		}
    100		CATCH_EINTR(waitpid(pid, NULL, __WALL));
    101	}
    102
    103	if (ret < 0)
    104		printk(UM_KERN_ERR "run_helper : failed to exec %s on host: %s\n",
    105		       argv[0], strerror(-ret));
    106
    107out_free2:
    108	kfree(data.buf);
    109out_close:
    110	if (fds[1] != -1)
    111		close(fds[1]);
    112	close(fds[0]);
    113out_free:
    114	free_stack(stack, 0);
    115	return ret;
    116}
    117
    118int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
    119		      unsigned long *stack_out)
    120{
    121	unsigned long stack, sp;
    122	int pid, status, err;
    123
    124	stack = alloc_stack(0, __cant_sleep());
    125	if (stack == 0)
    126		return -ENOMEM;
    127
    128	sp = stack + UM_KERN_PAGE_SIZE;
    129	pid = clone(proc, (void *) sp, flags, arg);
    130	if (pid < 0) {
    131		err = -errno;
    132		printk(UM_KERN_ERR "run_helper_thread : clone failed, "
    133		       "errno = %d\n", errno);
    134		return err;
    135	}
    136	if (stack_out == NULL) {
    137		CATCH_EINTR(pid = waitpid(pid, &status, __WALL));
    138		if (pid < 0) {
    139			err = -errno;
    140			printk(UM_KERN_ERR "run_helper_thread - wait failed, "
    141			       "errno = %d\n", errno);
    142			pid = err;
    143		}
    144		if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
    145			printk(UM_KERN_ERR "run_helper_thread - thread "
    146			       "returned status 0x%x\n", status);
    147		free_stack(stack, 0);
    148	} else
    149		*stack_out = stack;
    150	return pid;
    151}
    152
    153int helper_wait(int pid)
    154{
    155	int ret, status;
    156	int wflags = __WALL;
    157
    158	CATCH_EINTR(ret = waitpid(pid, &status, wflags));
    159	if (ret < 0) {
    160		printk(UM_KERN_ERR "helper_wait : waitpid process %d failed, "
    161		       "errno = %d\n", pid, errno);
    162		return -errno;
    163	} else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
    164		printk(UM_KERN_ERR "helper_wait : process %d exited with "
    165		       "status 0x%x\n", pid, status);
    166		return -ECHILD;
    167	} else
    168		return 0;
    169}