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