1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Author: Alexey Gladkov <gladkov.alexey@gmail.com>
9 #include <sys/resource.h>
10 #include <sys/prctl.h>
26 static char *service_prog
;
27 static uid_t user
= 60000;
28 static uid_t group
= 60000;
30 static void setrlimit_nproc(rlim_t n
)
33 struct rlimit limit
= {
38 warnx("(pid=%d): Setting RLIMIT_NPROC=%ld", pid
, n
);
40 if (setrlimit(RLIMIT_NPROC
, &limit
) < 0)
41 err(EXIT_FAILURE
, "(pid=%d): setrlimit(RLIMIT_NPROC)", pid
);
44 static pid_t
fork_child(void)
49 err(EXIT_FAILURE
, "fork");
56 warnx("(pid=%d): New process starting ...", pid
);
58 if (prctl(PR_SET_PDEATHSIG
, SIGKILL
) < 0)
59 err(EXIT_FAILURE
, "(pid=%d): prctl(PR_SET_PDEATHSIG)", pid
);
61 signal(SIGUSR1
, SIG_DFL
);
63 warnx("(pid=%d): Changing to uid=%d, gid=%d", pid
, user
, group
);
65 if (setgid(group
) < 0)
66 err(EXIT_FAILURE
, "(pid=%d): setgid(%d)", pid
, group
);
68 err(EXIT_FAILURE
, "(pid=%d): setuid(%d)", pid
, user
);
70 warnx("(pid=%d): Service running ...", pid
);
72 warnx("(pid=%d): Unshare user namespace", pid
);
73 if (unshare(CLONE_NEWUSER
) < 0)
74 err(EXIT_FAILURE
, "unshare(CLONE_NEWUSER)");
76 char *const argv
[] = { "service", NULL
};
77 char *const envp
[] = { "I_AM_SERVICE=1", NULL
};
79 warnx("(pid=%d): Executing real service ...", pid
);
81 execve(service_prog
, argv
, envp
);
82 err(EXIT_FAILURE
, "(pid=%d): execve", pid
);
85 int main(int argc
, char **argv
)
88 pid_t child
[NR_CHILDS
];
89 int wstatus
[NR_CHILDS
];
90 int childs
= NR_CHILDS
;
93 if (getenv("I_AM_SERVICE")) {
98 service_prog
= argv
[0];
101 warnx("(pid=%d) Starting testcase", pid
);
104 * This rlimit is not a problem for root because it can be exceeded.
108 for (i
= 0; i
< NR_CHILDS
; i
++) {
109 child
[i
] = fork_child();
115 for (i
= 0; i
< NR_CHILDS
; i
++) {
120 pid_t ret
= waitpid(child
[i
], &wstatus
[i
], WNOHANG
);
122 if (!ret
|| (!WIFEXITED(wstatus
[i
]) && !WIFSIGNALED(wstatus
[i
])))
125 if (ret
< 0 && errno
!= ECHILD
)
126 warn("(pid=%d): waitpid(%d)", pid
, child
[i
]);
137 for (i
= 0; i
< NR_CHILDS
; i
++) {
140 kill(child
[i
], SIGUSR1
);
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
]));
152 if (WIFSIGNALED(wstatus
[i
]) && WTERMSIG(wstatus
[i
]) == SIGUSR1
)
155 warnx("(pid=%d): Test failed", pid
);
159 warnx("(pid=%d): Test passed", pid
);