File Index
Files and directories
Sign in
FILE

rlimits-per-userns.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/rlimits/rlimits-per-userns.c C
  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}
~/ Read-only file preview.