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

rlimits-per-userns.c (3325B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Author: Alexey Gladkov <gladkov.alexey@gmail.com>
      4 */
      5#define _GNU_SOURCE
      6#include <sys/types.h>
      7#include <sys/wait.h>
      8#include <sys/time.h>
      9#include <sys/resource.h>
     10#include <sys/prctl.h>
     11#include <sys/stat.h>
     12
     13#include <unistd.h>
     14#include <stdlib.h>
     15#include <stdio.h>
     16#include <string.h>
     17#include <sched.h>
     18#include <signal.h>
     19#include <limits.h>
     20#include <fcntl.h>
     21#include <errno.h>
     22#include <err.h>
     23
     24#define NR_CHILDS 2
     25
     26static char *service_prog;
     27static uid_t user   = 60000;
     28static uid_t group  = 60000;
     29
     30static void setrlimit_nproc(rlim_t n)
     31{
     32	pid_t pid = getpid();
     33	struct rlimit limit = {
     34		.rlim_cur = n,
     35		.rlim_max = n
     36	};
     37
     38	warnx("(pid=%d): Setting RLIMIT_NPROC=%ld", pid, n);
     39
     40	if (setrlimit(RLIMIT_NPROC, &limit) < 0)
     41		err(EXIT_FAILURE, "(pid=%d): setrlimit(RLIMIT_NPROC)", pid);
     42}
     43
     44static pid_t fork_child(void)
     45{
     46	pid_t pid = fork();
     47
     48	if (pid < 0)
     49		err(EXIT_FAILURE, "fork");
     50
     51	if (pid > 0)
     52		return pid;
     53
     54	pid = getpid();
     55
     56	warnx("(pid=%d): New process starting ...", pid);
     57
     58	if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
     59		err(EXIT_FAILURE, "(pid=%d): prctl(PR_SET_PDEATHSIG)", pid);
     60
     61	signal(SIGUSR1, SIG_DFL);
     62
     63	warnx("(pid=%d): Changing to uid=%d, gid=%d", pid, user, group);
     64
     65	if (setgid(group) < 0)
     66		err(EXIT_FAILURE, "(pid=%d): setgid(%d)", pid, group);
     67	if (setuid(user) < 0)
     68		err(EXIT_FAILURE, "(pid=%d): setuid(%d)", pid, user);
     69
     70	warnx("(pid=%d): Service running ...", pid);
     71
     72	warnx("(pid=%d): Unshare user namespace", pid);
     73	if (unshare(CLONE_NEWUSER) < 0)
     74		err(EXIT_FAILURE, "unshare(CLONE_NEWUSER)");
     75
     76	char *const argv[] = { "service", NULL };
     77	char *const envp[] = { "I_AM_SERVICE=1", NULL };
     78
     79	warnx("(pid=%d): Executing real service ...", pid);
     80
     81	execve(service_prog, argv, envp);
     82	err(EXIT_FAILURE, "(pid=%d): execve", pid);
     83}
     84
     85int main(int argc, char **argv)
     86{
     87	size_t i;
     88	pid_t child[NR_CHILDS];
     89	int wstatus[NR_CHILDS];
     90	int childs = NR_CHILDS;
     91	pid_t pid;
     92
     93	if (getenv("I_AM_SERVICE")) {
     94		pause();
     95		exit(EXIT_SUCCESS);
     96	}
     97
     98	service_prog = argv[0];
     99	pid = getpid();
    100
    101	warnx("(pid=%d) Starting testcase", pid);
    102
    103	/*
    104	 * This rlimit is not a problem for root because it can be exceeded.
    105	 */
    106	setrlimit_nproc(1);
    107
    108	for (i = 0; i < NR_CHILDS; i++) {
    109		child[i] = fork_child();
    110		wstatus[i] = 0;
    111		usleep(250000);
    112	}
    113
    114	while (1) {
    115		for (i = 0; i < NR_CHILDS; i++) {
    116			if (child[i] <= 0)
    117				continue;
    118
    119			errno = 0;
    120			pid_t ret = waitpid(child[i], &wstatus[i], WNOHANG);
    121
    122			if (!ret || (!WIFEXITED(wstatus[i]) && !WIFSIGNALED(wstatus[i])))
    123				continue;
    124
    125			if (ret < 0 && errno != ECHILD)
    126				warn("(pid=%d): waitpid(%d)", pid, child[i]);
    127
    128			child[i] *= -1;
    129			childs -= 1;
    130		}
    131
    132		if (!childs)
    133			break;
    134
    135		usleep(250000);
    136
    137		for (i = 0; i < NR_CHILDS; i++) {
    138			if (child[i] <= 0)
    139				continue;
    140			kill(child[i], SIGUSR1);
    141		}
    142	}
    143
    144	for (i = 0; i < NR_CHILDS; i++) {
    145		if (WIFEXITED(wstatus[i]))
    146			warnx("(pid=%d): pid %d exited, status=%d",
    147				pid, -child[i], WEXITSTATUS(wstatus[i]));
    148		else if (WIFSIGNALED(wstatus[i]))
    149			warnx("(pid=%d): pid %d killed by signal %d",
    150				pid, -child[i], WTERMSIG(wstatus[i]));
    151
    152		if (WIFSIGNALED(wstatus[i]) && WTERMSIG(wstatus[i]) == SIGUSR1)
    153			continue;
    154
    155		warnx("(pid=%d): Test failed", pid);
    156		exit(EXIT_FAILURE);
    157	}
    158
    159	warnx("(pid=%d): Test passed", pid);
    160	exit(EXIT_SUCCESS);
    161}