Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Author: Alexey Gladkov <gladkov.alexey@gmail.com>
0004  */
0005 #define _GNU_SOURCE
0006 #include <sys/types.h>
0007 #include <sys/wait.h>
0008 #include <sys/time.h>
0009 #include <sys/resource.h>
0010 #include <sys/prctl.h>
0011 #include <sys/stat.h>
0012 
0013 #include <unistd.h>
0014 #include <stdlib.h>
0015 #include <stdio.h>
0016 #include <string.h>
0017 #include <sched.h>
0018 #include <signal.h>
0019 #include <limits.h>
0020 #include <fcntl.h>
0021 #include <errno.h>
0022 #include <err.h>
0023 
0024 #define NR_CHILDS 2
0025 
0026 static char *service_prog;
0027 static uid_t user   = 60000;
0028 static uid_t group  = 60000;
0029 
0030 static void setrlimit_nproc(rlim_t n)
0031 {
0032     pid_t pid = getpid();
0033     struct rlimit limit = {
0034         .rlim_cur = n,
0035         .rlim_max = n
0036     };
0037 
0038     warnx("(pid=%d): Setting RLIMIT_NPROC=%ld", pid, n);
0039 
0040     if (setrlimit(RLIMIT_NPROC, &limit) < 0)
0041         err(EXIT_FAILURE, "(pid=%d): setrlimit(RLIMIT_NPROC)", pid);
0042 }
0043 
0044 static pid_t fork_child(void)
0045 {
0046     pid_t pid = fork();
0047 
0048     if (pid < 0)
0049         err(EXIT_FAILURE, "fork");
0050 
0051     if (pid > 0)
0052         return pid;
0053 
0054     pid = getpid();
0055 
0056     warnx("(pid=%d): New process starting ...", pid);
0057 
0058     if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
0059         err(EXIT_FAILURE, "(pid=%d): prctl(PR_SET_PDEATHSIG)", pid);
0060 
0061     signal(SIGUSR1, SIG_DFL);
0062 
0063     warnx("(pid=%d): Changing to uid=%d, gid=%d", pid, user, group);
0064 
0065     if (setgid(group) < 0)
0066         err(EXIT_FAILURE, "(pid=%d): setgid(%d)", pid, group);
0067     if (setuid(user) < 0)
0068         err(EXIT_FAILURE, "(pid=%d): setuid(%d)", pid, user);
0069 
0070     warnx("(pid=%d): Service running ...", pid);
0071 
0072     warnx("(pid=%d): Unshare user namespace", pid);
0073     if (unshare(CLONE_NEWUSER) < 0)
0074         err(EXIT_FAILURE, "unshare(CLONE_NEWUSER)");
0075 
0076     char *const argv[] = { "service", NULL };
0077     char *const envp[] = { "I_AM_SERVICE=1", NULL };
0078 
0079     warnx("(pid=%d): Executing real service ...", pid);
0080 
0081     execve(service_prog, argv, envp);
0082     err(EXIT_FAILURE, "(pid=%d): execve", pid);
0083 }
0084 
0085 int main(int argc, char **argv)
0086 {
0087     size_t i;
0088     pid_t child[NR_CHILDS];
0089     int wstatus[NR_CHILDS];
0090     int childs = NR_CHILDS;
0091     pid_t pid;
0092 
0093     if (getenv("I_AM_SERVICE")) {
0094         pause();
0095         exit(EXIT_SUCCESS);
0096     }
0097 
0098     service_prog = argv[0];
0099     pid = getpid();
0100 
0101     warnx("(pid=%d) Starting testcase", pid);
0102 
0103     /*
0104      * This rlimit is not a problem for root because it can be exceeded.
0105      */
0106     setrlimit_nproc(1);
0107 
0108     for (i = 0; i < NR_CHILDS; i++) {
0109         child[i] = fork_child();
0110         wstatus[i] = 0;
0111         usleep(250000);
0112     }
0113 
0114     while (1) {
0115         for (i = 0; i < NR_CHILDS; i++) {
0116             if (child[i] <= 0)
0117                 continue;
0118 
0119             errno = 0;
0120             pid_t ret = waitpid(child[i], &wstatus[i], WNOHANG);
0121 
0122             if (!ret || (!WIFEXITED(wstatus[i]) && !WIFSIGNALED(wstatus[i])))
0123                 continue;
0124 
0125             if (ret < 0 && errno != ECHILD)
0126                 warn("(pid=%d): waitpid(%d)", pid, child[i]);
0127 
0128             child[i] *= -1;
0129             childs -= 1;
0130         }
0131 
0132         if (!childs)
0133             break;
0134 
0135         usleep(250000);
0136 
0137         for (i = 0; i < NR_CHILDS; i++) {
0138             if (child[i] <= 0)
0139                 continue;
0140             kill(child[i], SIGUSR1);
0141         }
0142     }
0143 
0144     for (i = 0; i < NR_CHILDS; i++) {
0145         if (WIFEXITED(wstatus[i]))
0146             warnx("(pid=%d): pid %d exited, status=%d",
0147                 pid, -child[i], WEXITSTATUS(wstatus[i]));
0148         else if (WIFSIGNALED(wstatus[i]))
0149             warnx("(pid=%d): pid %d killed by signal %d",
0150                 pid, -child[i], WTERMSIG(wstatus[i]));
0151 
0152         if (WIFSIGNALED(wstatus[i]) && WTERMSIG(wstatus[i]) == SIGUSR1)
0153             continue;
0154 
0155         warnx("(pid=%d): Test failed", pid);
0156         exit(EXIT_FAILURE);
0157     }
0158 
0159     warnx("(pid=%d): Test passed", pid);
0160     exit(EXIT_SUCCESS);
0161 }