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