aboutsummaryrefslogtreecommitdiffstats
path: root/src/mkchild.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mkchild.c')
-rw-r--r--src/mkchild.c711
1 files changed, 0 insertions, 711 deletions
diff --git a/src/mkchild.c b/src/mkchild.c
deleted file mode 100644
index 805105f..0000000
--- a/src/mkchild.c
+++ /dev/null
@@ -1,711 +0,0 @@
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "config2.h"
-#include "common.h"
-#include "sctcore.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <errno.h>
-#include <grp.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-
-#include <pthread.h>
-#include <semaphore.h>
-
-#ifdef HAVE_CONF_CAP
-#include <sys/prctl.h>
-#include <sys/capability.h>
-#endif
-
-#define abort_makechild(val) \
- do { \
- sctjudge_makechild_cleanup(&mcopt, chrdir_oldmode, execdestname); \
- toreturn->mc_exitcode = (val); \
- pthread_exit((void*)toreturn); \
- }while(0)
-
-#define SCTCHILD_OPEN_INPUT 0
-#define SCTCHILD_DUP2_INPUT 1
-#define SCTCHILD_OPEN_OUTPUT 2
-#define SCTCHILD_DUP2_OUTPUT 3
-#define SCTCHILD_OPEN_STDERR 4
-#define SCTCHILD_DUP2_STDERR 5
-#define SCTCHILD_CLOSE_OTHERFD 6
-#define SCTCHILD_SETRLIMIT_VM 7
-#define SCTCHILD_SETRLIMIT_FSIZE 8
-#define SCTCHILD_SETRLIMIT_OPENFILE 9
-#define SCTCHILD_SETRLIMIT_PROC 10
-#define SCTCHILD_CHROOT 11
-#define SCTCHILD_SETUID 12
-#define SCTCHILD_SETGID 13
-#define SCTCHILD_SETGROUPS 14
-#define SCTCHILD_CAPSET 15
-#define SCTCHILD_EXEC 16
-#define SCTCHILD_MSGMAX 17 /* 訊息代碼的最大值 */
-#define SCTCHILD_WRITE_SUCCMSG(reason) \
- do{ \
- childmsg[0] = (reason); \
- childmsg[1] = 0; \
- write(childpipe[1], (void*)childmsg, sizeof(int)*2); \
- }while(0)
-#define SCTCHILD_WRITE_FAILMSG(reason) \
- do{ \
- childmsg[0] = (reason); \
- childmsg[1] = errno; \
- write(childpipe[1], (void*)childmsg, sizeof(int)*2); \
- }while(0)
-
-pid_t pidchild;
-pthread_mutex_t pidmutex, tkill_mx, tdisplay_mx, judge_tle_mx;
-pthread_t tkill, tdisplay;
-char tkill_yes = 0, tdisplay_yes = 0, judge_tle = 0;
-sem_t mcthr, tlethr, dispthr;
-
-static const char* childmsg_text[SCTCHILD_MSGMAX] = {
- "開啟輸入檔案",
- "重新導向標準輸入",
- "開啟輸出檔案",
- "重新導向標準輸出",
- "開啟用於導向標準錯誤的檔案",
- "重新導向標準錯誤",
- "關閉所有不使用的檔案",
- "設定記憶體限制",
- "設定輸出限制",
- "設定禁止開啟其他檔案",
- "設定禁止產生新程序",
- "執行 chroot",
- "修改 real 和 effective UID",
- "修改 real 和 effective GID",
- "修改 supplementary GIDs",
- "丟棄所有 Linux capabilities",
- "執行受測程式"
-};
-
-static void sctjudge_makechild_cleanup_p1(void){
- pthread_mutex_lock(&tkill_mx);
- if(tkill_yes){
- tkill_yes = 0;
- pthread_mutex_unlock(&tkill_mx);
- sem_post(&tlethr);
- }else{
- pthread_mutex_unlock(&tkill_mx);
- }
-
- pthread_mutex_lock(&tdisplay_mx);
- if(tdisplay_yes){
- tdisplay_yes = 0;
- pthread_mutex_unlock(&tdisplay_mx);
- sem_post(&dispthr);
- }else{
- pthread_mutex_unlock(&tdisplay_mx);
- }
-
-}
-
-static void sctjudge_makechild_cleanup_p2(mcopt, oldperm, copiedexe)
- const struct makechildopt* mcopt;
- const mode_t oldperm;
- char* copiedexe;
-{
- if(oldperm != -1 && mcopt->chrootdir != NULL){
- if(mcopt->flags & SCTMC_VERBOSE){
- printf("恢復 %s 的權限\n", mcopt->chrootdir);
- }
- chmod(mcopt->chrootdir, oldperm);
- }
- if(copiedexe != NULL && mcopt->chrootdir != NULL &&
- !(mcopt->flags & SCTMC_NOCOPY)){
- if(mcopt->flags & SCTMC_VERBOSE){
- printf("移除 %s......\n", copiedexe);
- }
- unlink(copiedexe);
- free(copiedexe);
- }
-}
-
-static void sctjudge_makechild_cleanup(mcopt, oldperm, copiedexe)
- const struct makechildopt* mcopt;
- const mode_t oldperm;
- char* copiedexe;
-{
- sctjudge_makechild_cleanup_p1();
- sctjudge_makechild_cleanup_p2(mcopt, oldperm, copiedexe);
-}
-
-static int copyfilebyname(const char* src, const char* destdir
- , char** srcsn, char** destfn){
- /* strerror 並不 thread safe,因此必須確定只有一個 thread 會用到 */
- /* 為了確保安全,要求目的地目錄必須是空的 */
- DIR* dirp;
- if((dirp=opendir(destdir)) == NULL){
- fprintf(stderr, "無法開啟目錄 %s:%s\n", destdir, strerror(errno));
- return -1;
- }
- struct dirent* entryp;
- while((entryp=readdir(dirp)) != NULL){
- if(entryp->d_name[0] != '.' ||
- (entryp->d_name[1] != '.' && entryp->d_name[1] != '\0')){
- fprintf(stderr, "拒絕複製檔案:目錄 %s 不是空的\n", destdir);
- return -1;
- }
- }
- int fd, fd2;
- if((fd=open(src, O_RDONLY)) < 0){
- fprintf(stderr, "無法讀取檔案 %s:%s\n", src, strerror(errno));
- return -1;
- }
- const int bufsize = 4096;
- void* buf = malloc(bufsize);
- char* srcshortname;
- char* tmp;
- if((tmp=strrchr(src, '/')) == NULL){
- srcshortname = (char*)src;
- }else{
- srcshortname = tmp + 1;
- }
- *srcsn = srcshortname;
- char* destfilename = (char*)
- malloc(strlen(srcshortname) + strlen(destdir) + 1);
- sprintf(destfilename, "%s/%s", destdir, srcshortname);
- *destfn = destfilename;
- /* 新檔案權限是 0755,umask 亂弄的我可不管 */
- if((fd2=open(destfilename, O_CREAT | O_WRONLY | O_EXCL,
- S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) < 0){
- fprintf(stderr, "無法建立檔案 %s:%s\n",
- destfilename, strerror(errno));
- free(buf);
- return -1;
- }
- int readcount;
- while((readcount = read(fd, buf, bufsize)) > 0){
- write(fd2, buf, readcount);
- }
- close(fd);
- close(fd2);
- free(buf);
- return 0;
-}
-
-static void sctjudge_list_settings(const struct makechildopt* mcopt){
- printf("\t受測程式可執行檔名稱:%s", mcopt->executable);
- if(mcopt->flags & SCTMC_NOCOPY && mcopt->chrootdir != NULL){
- printf(" (相對於 %s)\n"
- "\t受測程式執行時的根目錄:%s\n"
- "\t執行前複製檔案:否\n"
- , mcopt->chrootdir, mcopt->chrootdir);
- }else{
- putchar('\n');
- if(mcopt->chrootdir != NULL){
- printf("\t受測程式執行時的根目錄:%s\n"
- "\t執行前複製檔案:是\n"
- , mcopt->chrootdir);
- }else{
- puts("\t受測程式執行時的根目錄:/\n"
- "\t執行前複製檔案:否");
- }
- }
- printf("\t輸入檔案:%s\n"
- "\t輸出檔案:%s"
- , mcopt->inputfile, mcopt->outputfile);
- if(mcopt->flags & SCTMC_REDIR_STDERR){
- puts(" (重新導向標準輸出和標準錯誤)");
- }else{
- puts(" (重新導向標準輸出)");
- }
- printf("\t執行時間限制:%d 毫秒\n", mcopt->exectime);
- fputs("\t記憶體使用量限制:", stdout);
- if(mcopt->memlimit > 0){
- printf("%d 位元組\n", mcopt->memlimit);
- }else{
- puts("無限制");
- }
- fputs("\t輸出限制:", stdout);
- if(mcopt->outlimit > 0){
- printf("%d 位元組\n", mcopt->outlimit);
- }else{
- puts("無限制");
- }
- if(mcopt->flags & SCTMC_SETUID){
- printf("\t設定受測程式執行時的 UID 為 %u\n", mcopt->uid);
- }else{
- puts("\t執行受測程式時維持原有的 real UID 和 effective UID");
- }
- if(mcopt->flags & SCTMC_SETGID){
- printf("\t設定受測程式執行時的 GID 為 %u\n", mcopt->gid);
- }else{
- puts("\t執行受測程式時維持原有的 real GID、effective GID "
- "和 supplementary GID");
- }
-}
-
-static int read_size(int fd, void* buf, size_t count){
- /* 一定要讀到 count 位元組的資料才會回傳,所以只要回傳 < count
- * 就表示已經讀到 EOF 了 */
- char* bufp = (char*)buf;
- size_t curcount = 0;
- int rval;
- do{
- rval = read(fd, bufp, count - curcount);
- if(rval < 0){
- return rval;
- }else if(rval == 0){
- return curcount;
- }else{
- bufp += rval;
- curcount += rval;
- }
- }while(curcount < count);
- return count;
-}
-
-void* sctjudge_makechild(void* arg){
- /* 首先等所有 thread 都啟動完成再開始動作 */
- sem_wait(&mcthr);
-
- /* 宣告變數囉! */
- int i;
-
- /* 函式參數與回傳值,Judge 結果就當作回傳值 */
- struct makechildopt mcopt = *(struct makechildopt*)arg;
- struct makechildrval* toreturn =
- (struct makechildrval*)malloc(sizeof(struct makechildrval));
- memset(toreturn, 0, sizeof(struct makechildrval));
-
- /* 可執行檔名稱儲存區 */
- char* execshortname = NULL; /* 可以說就是 basename,chroot+copy 才會用 */
- char* execdestname = NULL; /* 複製出來的暫時執行檔,chroot+copy 才會用 */
- /* 這幾個變數用來儲存 Judge 結果,如果沒有啟用 verbose
- * 且一切正常,那這些是唯一會輸出的東西了,目的是輸出容
- * 易被其他程式分析 */
-
- /* 要 chroot 的目錄的相關資訊 */
- struct stat chrdirinfo; /* 取得原始的 mode 用的 */
- mode_t chrdir_oldmode = -1; /* 這樣我們才能在結束時 chmod 回去 */
-
- /* 子程序的 PID,因為不會變,所以複製一份下來就不用去全域變數拿的 */
- pid_t pidcopy;
-
- /* 和子程序溝通用的 */
- int childpipe[2];
- int childmsg[2]; /* 每個訊息的大小都是 sizeof(int)*2
- [0]=發生事情的名稱 [1]=errno */
- int readsize = sizeof(int) * 2;
-
- /* 計時用的 */
- struct timespec execstart, execfinish;
-
- /* 子程序結束狀態 */
- int childexitstat;
- char childterminated = 0;
-
- /* 子程序才用的到的變數 */
- int fdinput, fdoutput, fderr, childressize;
- const int fdtablesize = getdtablesize();
- struct rlimit childres;
-
- /* 變數宣告完了 */
-
- if(mcopt.flags & SCTMC_VERBOSE){
- puts("列出設定值:");
- sctjudge_list_settings(&mcopt);
- fflush(stdout);
- }
- if(mcopt.flags & SCTMC_DRYRUN){
- abort_makechild(SCTMCRVAL_SUCCESS);
- }
-
- /* 我們要開始做正事了 */
- /* 由此開始,我是唯一會用到 strerror() 的 thread
- * 所以說應該沒有問題 */
- if(mcopt.chrootdir != NULL && !(mcopt.flags & SCTMC_NOCOPY)){
- /* 必須要複製可執行檔 */
- if(mcopt.flags & SCTMC_VERBOSE){
- puts("開始複製可執行檔......");
- }
- if(copyfilebyname(mcopt.executable, mcopt.chrootdir, &execshortname
- , &execdestname) < 0){
- abort_makechild(SCTMCRVAL_PREPARE);
- }
- }
- /* 再來是 chroot 的問題,避免受測程式亂開目錄之類的,
- * 所以把權限設成 0555,不過如果沒有變更 uid 和 gid ,
- * 受測程式還是可以 chmod 回來 */
- if(mcopt.chrootdir != NULL){
- if(mcopt.flags & SCTMC_VERBOSE){
- puts("取得用於 chroot 的目錄相關資訊");
- }
- if(stat(mcopt.chrootdir, &chrdirinfo) < 0){
- fprintf(stderr, "無法取得目錄 %s 的相關資訊:%s\n",
- mcopt.chrootdir, strerror(errno));
- abort_makechild(SCTMCRVAL_PREPARE);
- }else{
- if((chrdirinfo.st_mode & S_IFMT) == S_IFDIR){
- chrdir_oldmode = chrdirinfo.st_mode &
- (S_ISUID |S_ISGID |S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
- }else{
- fprintf(stderr, "%s 並不是目錄\n", mcopt.chrootdir);
- abort_makechild(SCTMCRVAL_PREPARE);
- }
- }
- if(mcopt.flags & SCTMC_VERBOSE){
- puts("嘗試變更此目錄的權限");
- }
- if(chmod(mcopt.chrootdir,
- S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0){
- fprintf(stderr, "無法變更目錄 %s 的權限\n", mcopt.chrootdir);
- abort_makechild(SCTMCRVAL_PREPARE);
- }
- }
-
- fflush(stdout);
-#ifndef HAVE_CONF_CAP
- enable_setuid();
-#endif
- /* 建立用來和 chlid process 溝通的 pipe */
- pipe(childpipe);
- pthread_mutex_lock(&pidmutex);
-#ifdef HAVE_WORKING_FORK
- pidchild = fork();
-#else
-#error "This program requires a working fork function."
-#endif
- if(pidchild < 0){
-#ifndef HAVE_CONF_CAP
- disable_setuid();
-#endif
- pthread_mutex_unlock(&pidmutex);
- fprintf(stderr, "子程序建立失敗:%s\n", strerror(errno));
- abort_makechild(SCTMCRVAL_FORK);
- }
- else if(pidchild > 0){
- /* 我們原本的 thread */
- /* 從這裡開始,我們需要 setuid 來 kill 子程序,
- * 所以說不要執行 disable_setuid() */
- pidcopy = pidchild;
- pthread_mutex_unlock(&pidmutex);
- close(childpipe[1]);
- /* 從 pipe 接收 child process 狀態,每次固定要讀 sizeof(int)*2 */
- while(read_size(childpipe[0], (void*)childmsg, readsize) == readsize){
- if(childmsg[0] < 0 || childmsg[0] >= SCTCHILD_MSGMAX){
- /* 會發生嗎?除非被亂七八糟 ptrace 吧
- * 這時候先砍掉子程序再說 */
- kill(pidcopy, SIGKILL);
- close(childpipe[0]);
- abort_makechild(SCTMCRVAL_INVALID);
- }else{
- if(childmsg[1]){
- fprintf(stderr, "子程序[%d]發生錯誤:%s:%s\n",
- pidcopy, childmsg_text[childmsg[0]],
- strerror(childmsg[1]));
- kill(pidcopy, SIGKILL);
- close(childpipe[0]);
- abort_makechild(SCTMCRVAL_CHILDFAIL);
- }else{
- if(mcopt.flags & SCTMC_VERBOSE){
- printf("子程序[%d]:%s\n", pidcopy,
- childmsg_text[childmsg[0]]);
- }
- }
- }
- }
- clock_gettime(CLOCK_REALTIME, &execstart);
- close(childpipe[0]);
-
- /* 現在我們確定受測程式已經在執行了,所以需要記錄一下時間
- * 通知其他 thread */
- sem_post(&tlethr);
- sem_post(&dispthr);
-
- /* 開始要 wait 了,莫名其妙 stop 的程式我最多只會送
- * 5 次 SIGCONT 給你(避免進入無限迴圈)
- * 這種奇怪的程式就等著 SLE 吧 */
- for(i=0; i<=5; i++){
- wait4(pidcopy, &childexitstat, WUNTRACED, &toreturn->judge_rusage);
- if(WIFSTOPPED(childexitstat) && i!=5){
- if(mcopt.flags & SCTMC_VERBOSE){
- printf("\n子程序因訊號 %d 而暫停,自動傳送 SIGCONT "
- "(第 %d 次)\n",
- WSTOPSIG(childexitstat), i+1);
- }
- kill(pidcopy, SIGCONT);
- }else{
- if(WIFSIGNALED(childexitstat)){
- clock_gettime(CLOCK_REALTIME, &execfinish);
- childterminated = 1;
- toreturn->judge_signal = WTERMSIG(childexitstat);
- if(toreturn->judge_signal == SIGXFSZ){
- toreturn->judge_result = SCTRES_OLE;
- }else{
- toreturn->judge_result = SCTRES_RE;
- }
- toreturn->judge_exitcode = WEXITSTATUS(childexitstat);
- break;
- }
- if(WIFEXITED(childexitstat)){
- clock_gettime(CLOCK_REALTIME, &execfinish);
- childterminated = 1;
- toreturn->judge_result = SCTRES_OK;
- toreturn->judge_exitcode = WEXITSTATUS(childexitstat);
- break;
- }
- }
- }
- if(!childterminated){
- kill(pidcopy, SIGKILL);
- wait4(pidcopy, &childexitstat, WUNTRACED, &toreturn->judge_rusage);
- toreturn->judge_result = SCTRES_SLE;
- toreturn->judge_exitcode = WEXITSTATUS(childexitstat);
- clock_gettime(CLOCK_REALTIME, &execfinish);
- }
- pthread_mutex_lock(&judge_tle_mx);
- if(judge_tle && toreturn->judge_result == SCTRES_RE){
- toreturn->judge_result = SCTRES_TLE;
- }
- pthread_mutex_unlock(&judge_tle_mx);
- difftimespec(&execstart, &execfinish, &toreturn->judge_time);
- if(break_flag){
- toreturn->judge_result = SCTRES_AB;
- }
- sctjudge_makechild_cleanup_p1();
- if(mcopt.flags & SCTMC_VERBOSE){
- /* XXX 有更好的方法洗掉文字嗎? */
- fputs("\r \r"
- , stdout);
- }
- }else{
- /* 子程序
- * 由此開始要很小心,因為我們是在 thread 裡面 fork (?) */
- close(childpipe[0]);
- /* close-on-exec 用來關閉這個暫時的資料傳輸通道 */
- fcntl(childpipe[1], F_SETFD, fcntl(childpipe[1],F_GETFD) | FD_CLOEXEC);
-
- /* 設為獨立的 process group,不過失敗就算了,這不重要 */
- setpgid(getpid(), getpid());
-
- /* 重設所有 signal handler
- * XXX 我猜 signal 最大值是 32,還有其他更好的寫法嗎? */
- for(i=1; i<=32; i++){
- signal(i, SIG_DFL);
- }
-
-#ifndef HAVE_CONF_CAP
- disable_setuid();
-#endif
-
- fdinput = open(mcopt.inputfile, O_RDONLY);
- if(fdinput < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_OPEN_INPUT);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_OPEN_INPUT);
- }
- if(dup2(fdinput, STDIN_FILENO) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_DUP2_INPUT);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_DUP2_INPUT);
- }
-
- /* 注意:開啟輸出檔會直接覆寫現存檔案! */
- fdoutput = open(mcopt.outputfile, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR);
- if(fdoutput < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_OPEN_OUTPUT);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_OPEN_OUTPUT);
- }
- if(dup2(fdoutput, STDOUT_FILENO) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_DUP2_OUTPUT);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_DUP2_OUTPUT);
- }
-
-#ifndef HAVE_CONF_CAP
- enable_setuid();
-#endif
- fchown(fdoutput, procrealuid, -1);
-
- /* 再來就是 stderr 了 */
- if(mcopt.flags & SCTMC_REDIR_STDERR){
- if(dup2(fdoutput, STDERR_FILENO) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_DUP2_STDERR);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_DUP2_STDERR);
- }
- }else{
- fderr = open(WITH_NULL, O_RDONLY);
- if(fderr < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_OPEN_STDERR);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_OPEN_STDERR);
- }
- if(dup2(fderr, STDERR_FILENO) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_DUP2_STDERR);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_DUP2_STDERR);
- }
- }
-
- /* 很暴力地把所有不該留著的 fd 關掉 */
- for(i=3; i<fdtablesize; i++){
- if(i != childpipe[1]){
- close(i);
- }
- }
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_CLOSE_OTHERFD);
-
- /* 有人要求我要 chroot 嗎? */
- if(mcopt.chrootdir != NULL){
- if(chroot(mcopt.chrootdir) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_CHROOT);
- exit(1);
- }else{
- chdir("/");
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_CHROOT);
- }
- }
-
-
-#ifdef HAVE_CONF_CAP
- /* 確保修改身份的時候 capabilities 仍然留著
- * 等一下再自己把 capabilities 丟掉 */
- prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
-#endif
-
- /* 我要 setgid 嗎? */
- if(mcopt.flags & SCTMC_SETGID){
- if(setregid(mcopt.gid, mcopt.gid) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETGID);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETGID);
- }
- if(setgroups(1, &mcopt.gid) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETGROUPS);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETGROUPS);
- }
- }
-
- /* 我要 setuid 嗎? */
- if(mcopt.flags & SCTMC_SETUID){
- if(setreuid(mcopt.uid, mcopt.uid) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETUID);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETUID);
- }
- }
-#ifndef HAVE_CONF_CAP
- else{
- /* 確保 setuid 可執行檔所造成的 effective UID 改變不會傳給子程序 */
- setuid(procrealuid);
- }
-#endif
-
- /* 開始設定資源限制 */
- if(mcopt.memlimit > 0){
- childressize = mcopt.memlimit;
- childres.rlim_cur = childressize;
- childres.rlim_max = childressize;
- if(setrlimit(RLIMIT_AS, &childres) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETRLIMIT_VM);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETRLIMIT_VM);
- }
- }
-
- if(mcopt.outlimit > 0){
- childressize = mcopt.outlimit;
- childres.rlim_cur = childressize;
- childres.rlim_max = childressize;
- if(setrlimit(RLIMIT_FSIZE, &childres) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETRLIMIT_FSIZE);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETRLIMIT_FSIZE);
- }
- }
-
- /* 從現在開始,不准再開檔案了 */
- childres.rlim_cur = 0;
- childres.rlim_max = 0;
- if(setrlimit(
-#ifdef RLIMIT_NOFILE
- RLIMIT_NOFILE
-#else
- RLIMIT_OFILE
-#endif
- , &childres) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETRLIMIT_OPENFILE);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETRLIMIT_OPENFILE);
- }
-
- /* 從現在開始,不可以再產生新程序了 */
- if(setrlimit(RLIMIT_NPROC, &childres) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_SETRLIMIT_PROC);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_SETRLIMIT_PROC);
- }
-
-
- /* 非 Linux 系統就到此結束了,可以 exec 了 */
-
-#ifdef HAVE_CONF_CAP
- /* 正在丟掉 capabilities */
- cap_t nocap = cap_init();
- cap_clear_flag(nocap, CAP_EFFECTIVE);
- cap_clear_flag(nocap, CAP_INHERITABLE);
- cap_clear_flag(nocap, CAP_PERMITTED);
- if(cap_set_proc(nocap) < 0){
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_CAPSET);
- exit(1);
- }else{
- SCTCHILD_WRITE_SUCCMSG(SCTCHILD_CAPSET);
- }
- /* 需要 drop bound 嗎?再考慮看看 */
-#endif
-
- if(mcopt.chrootdir == NULL){
- execl(mcopt.executable, mcopt.executable, NULL);
- }else{
- if(mcopt.flags & SCTMC_NOCOPY){
- execl(mcopt.executable, mcopt.executable, NULL);
- }else{
- execl(execshortname, execshortname, NULL);
- }
- }
-
- SCTCHILD_WRITE_FAILMSG(SCTCHILD_EXEC);
- exit(2);
- }
- /* Judge 完成,準備離開 */
- fflush(stdout);
- sctjudge_makechild_cleanup_p2(&mcopt, chrdir_oldmode, execdestname);
- fflush(stdout);
- (toreturn->mc_exitcode) = SCTMCRVAL_SUCCESS;
- return (void*)toreturn;
-}