brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 26dc949 Raw
162 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Author: Alexey Gladkov <gladkov.alexey@gmail.com>4 */5#define _GNU_SOURCE6#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 225 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 = n36	};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}162