/** * Launches a program and wait for it to finish. * * If uid is not UID_MASTER, the standard input and output will be redirected * to /dev/null. * * If uid is UID_MASTER and the program exits with non-zero status (or an error * occurs during the setup of the child process), the vm will be shut down. * * The umask also depends on uid. For UID_MASTER, files will be private by * default. For other users, files will be public by default. * * @param cmd the command to execute (will be modified) * @param uid the user id that will execute the program */ static void launch(char *cmd, uid_t uid) { char *argv[CONTROL_MAXARGS+1]; pid_t pid; int status; splitargs(cmd, argv); pid = fork(); if(pid < 0) { // Error die("fork", NULL); } else if(pid > 0) { // Parent wait(&status); if(uid == UID_MASTER && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) shutdown(); } else { // Child childcheck("close /task/control", fclose(fcontrol)); if(uid == UID_MASTER) { childcheck("set gid", setgid(0)); childcheck("set uid", setuid(uid)); // Make new files private to master by default umask(077); } else { childcheck("set gid", setgid(2)); childcheck("set uid", setuid(uid)); // Make new files public by default umask(000); // Deny access to input and output if(freopen("/dev/null", "r", stdin) == NULL || freopen("/dev/null", "w", stdout) == NULL || freopen("/dev/null", "w", stderr) == NULL) childcheck("reopen std streams", 1); } execve(argv[0], argv, ENVIRONMENT); childcheck("execve", 1); // if we arrive here, there was an error launching cmd. } }
char * mother_getlimitinfo(void) { const char *function = "mother_getlimitinfo()"; static char buf[2048]; const int fds_per_proc = 2; /* two pipes */ const char *limiter, *prefix = "max clients calculation will not be done"; struct rlimit maxfd, maxproc; char maxprocstr[64], maxfdstr[64]; unsigned long negc_proc, negc_fd, reqc_proc, reqc_fd, ioc_proc, ioc_fd, negc_limit, reqc_limit, ioc_limit, proc_free, proc_used, procs, fds_free; if (getrlimit(RLIMIT_NOFILE, &maxfd) != 0) { swarn("%s: getrlimit(RLIMIT_NOFILE) failed", function); return ""; } #ifdef RLIMIT_NPROC if (getrlimit(RLIMIT_NPROC, &maxproc) != 0) { swarn("%s: %s: getrlimit(RLIMIT_NPROC) failed", function, prefix); return ""; } #else /* !RLIMIT_NPROC */ if ((maxproc.rlim_cur = (rlim_t)sysconf(_SC_CHILD_MAX)) == (rlim_t)-1) { swarn("%s: %s: sysconf(_SC_CHILD_MAX) failed", function, prefix); return ""; } maxproc.rlim_max = maxproc.rlim_cur; #endif /* !RLIMIT_NPROC */ if (maxfd.rlim_cur == RLIM_INFINITY && maxproc.rlim_cur == RLIM_INFINITY) return "no applicable environment resource limits configured"; proc_used = sockscf.option.serverc + childcheck(-PROC_NEGOTIATE) / SOCKD_NEGOTIATEMAX + childcheck(-PROC_REQUEST) / SOCKD_REQUESTMAX + childcheck(-PROC_IO) / SOCKD_IOMAX; proc_free = maxproc.rlim_cur - proc_used; if (maxproc.rlim_cur == RLIM_INFINITY) snprintf(maxprocstr, sizeof(maxprocstr), "no limit"); else snprintf(maxprocstr, sizeof(maxprocstr), "%lu (%lu free)", (unsigned long)maxproc.rlim_cur, proc_free); fds_free = freedescriptors(NULL, NULL) - FDPASS_MAX; if (maxfd.rlim_cur == RLIM_INFINITY) snprintf(maxfdstr, sizeof(maxfdstr), "no limit"); else snprintf(maxfdstr, sizeof(maxfdstr), "%lu (%lu free)", (unsigned long)maxfd.rlim_cur, fds_free); /* * Calculate the max number of new clients we can handle based on both * the process resource limit and the fd limit. */ /* * Process-based limit, disregarding any other limits. * Each process can handle SOCKD_{NEGOTIATE,REQUEST,IO}MAX clients. * We can create a max number of proc_free additional processes, so * the number of additional clients we can handle is the number * of additional clients multiplied by the number of clients each * process can handle. */ negc_proc = proc_free * SOCKD_NEGOTIATEMAX; reqc_proc = proc_free * SOCKD_REQUESTMAX; ioc_proc = proc_free * SOCKD_IOMAX; /* * FD-based limit, disregarding any other limits. * With the fds we have, we can create a given number of additional * processes (procs). * Each process needs fds_per_proc, and an additional * SOCKD_{NEGOTIATE,REQUEST,IO}MAX * <number of fds per client in this * phase> fds to handle the max number of clients, meaning we can handle * the following number of additional clients: */ procs = fds_free / fds_per_proc; negc_fd = MIN(((fds_free - fds_per_proc) / 1), SOCKD_NEGOTIATEMAX) * procs; reqc_fd = MIN(((fds_free - fds_per_proc) / FDPASS_MAX), SOCKD_REQUESTMAX) * procs; ioc_fd = MIN(((fds_free - fds_per_proc) / FDPASS_MAX), SOCKD_IOMAX) * procs; /* * Different process-types could be limited by different things, but * ignore that here. */ if (negc_proc < negc_fd || reqc_proc < reqc_fd || ioc_proc < ioc_fd) { limiter = "process"; negc_limit = negc_proc; reqc_limit = reqc_proc; ioc_limit = ioc_proc; } else { limiter = "open file"; negc_limit = negc_fd; reqc_limit = reqc_fd; ioc_limit = ioc_fd; } snprintf(buf, sizeof(buf), "max limits: processes: %s, files: %s, " "%s-slots: %lu, %s-slots: %lu, %s-slots: %lu " "(max clients limited by %s limit)", maxprocstr, maxfdstr, childtype2string(PROC_NEGOTIATE), negc_limit, childtype2string(PROC_REQUEST), reqc_limit, childtype2string(PROC_IO), ioc_limit, limiter); return buf; }