/* * Copyright 1991, Silicon Graphics, Inc. * All Rights Reserved. * * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; * the contents of this file may not be disclosed to third parties, copied or * duplicated in any form, in whole or in part, without the prior written * permission of Silicon Graphics, Inc. * * RESTRICTED RIGHTS LEGEND: * Use, duplication or disclosure by the Government is subject to restrictions * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data * and Computer Software clause at DFARS 252.227-7013, and/or in similar or * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - * rights reserved under the Copyright Laws of the United States. */ #include "mac.h" #include /* * kill_mac.c -- MAC read tests for Kill() system call. */ static int kill_mac1(struct macinfo_2 *parmsptr); static struct macinfo_2 kill_minfo[] = { /* case case c_flag expect Object Subject name number success errno MSEN MINT MSEN MINT UID */ "pos00", 0, 1, PASS, 0, MSL, MIE, MSA, MIE, SUPER, "pos01", 1, 1, PASS, 0, MSL, MIH, MSH, MIL, SUPER, "pos02", 2, 0, PASS, 0, MSL, MIE, MSL, MIE, TEST0, "neg00", 3, 0, FAIL, EPERM, MSL, MIE, MSH, MIE, TEST0, "neg01", 4, 0, FAIL, EPERM, MSH, MIL, MSL, MIH, TEST0, }; static char *kill_mdesc[] = { "SUSER, MS:S = O; MI:S = O", "SUSER, MS:S != O; MI:S != O", "Not SUSER, MS:S = O; MI:S = O", "Not SUSER, MS:S != O, MS HIGH; MI:S = O", "Not SUSER, MS:S = O; MI:S != O", }; int kill_mac(void) { short ncases = 5; /* number of total test cases */ int fail = 0; /* set when a test case fails */ int incomplete = 0; /* set when a test case is incomplete */ short i = 0; /* test case loop counter */ char str[MSGLEN]; /* used to write to logfiles */ char testname[SLEN]; /* used to write to logfiles */ strcpy(testname,"kill_mac"); /* * Write formatted info to raw log. */ RAWLOG_SETUP(testname, ncases); /* * Call function for each test case. */ for (i = 0; i < ncases; i++) { flush_raw_log(); switch (kill_mac1(&kill_minfo[i]) ) { /* * Write formatted result to raw log. */ case PASS: /* Passed */ RAWPASS(kill_minfo[i].casenum, kill_minfo[i].casename); break; case FAIL: /* Failed */ RAWFAIL(kill_minfo[i].casenum, kill_minfo[i].casename, kill_mdesc[i]); fail = 1; break; default: RAWINC(kill_minfo[i].casenum, kill_minfo[i].casename); incomplete = 1; break; /* Incomplete */ } flush_raw_log(); } /* * Return 0, 1, or 2 to calling function, which records * result in summary log. If ANY case failed or was * incomplete, the whole test is recorded as failed or * incomplete. Incomplete supercedes fail. */ if (incomplete) return(INCOMPLETE); if (fail) return(FAIL); return(PASS); } static int kill_mac1(struct macinfo_2 *parmsptr) { register char i; /* Wait loop index. */ char buf[4]; /* Used in pipe read/writes. */ char testname[SLEN]; /* used to write to logfiles */ char namestring[MSGLEN]; /* Used in error messages. */ int status[2], waitret[2]; /* For wait. */ int OtoS_fd[2]; /* O writes, S reads. */ int StoO_fd[2]; /* S writes, O reads. */ pid_t retval = 0; /* Return value of test call. */ pid_t forkval1 = 0; /* O's pid returned to parent */ pid_t forkval2 = 0; /* S's pid returned to parent */ mac_t lptr; /* MAC label pointer. */ strcpy(testname,"kill_mac"); strcpy (buf, "abc"); /* Stuff to write to pipe. */ sprintf(namestring, "%s, case %d, %s:\n ", testname, parmsptr->casenum, parmsptr->casename); /* * Make 2 pipes. */ if ( pipe(OtoS_fd) || pipe(StoO_fd) ) { w_error(SYSCALL, namestring, err[F_PIPE], errno); return(INCOMPLETE); } /* * Fork Object. */ if ( ( forkval1 = fork() ) == -1 ) { w_error(SYSCALL, namestring, err[F_FORK], errno); return(INCOMPLETE); } /* * This is the parent after forking Object. */ if (forkval1) { /* * Fork S. */ if ( ( forkval2 = fork() ) == -1 ) { w_error(SYSCALL, namestring, err[F_FORK], errno); return(INCOMPLETE); } } /* * This is the parent after forking Subject. */ if ( (forkval2) && (forkval1) ) { /* * Close all pipe fds. */ close(OtoS_fd[0]); close(OtoS_fd[1]); close(StoO_fd[0]); close(StoO_fd[1]); /* * Wait for children. For this test, it's OK if one * of the children exits due to a signal. If both * have been killed, or one returns 2, or any other * unexpected event occurs, return 2. Otherwise, return * 1 if one returns 1, otherwise 0 if one returns 0. */ for (i = 0; i < 2; i++ ) { if ((waitret[i] = wait(&status[i])) < 0 ) { w_error(SYSCALL, namestring, err[F_WAIT], errno); return(INCOMPLETE); } if (waitret[i] == forkval1) { /* * OK if object process was kiled */ if (WIFSIGNALED(status[i])) { break; } if (!WIFEXITED(status[i])) { w_error(GENERAL, namestring, err[C_NOTEXIT], 0); return(INCOMPLETE); } } if (waitret[i] == forkval2) { /* * Subject process should exit normally */ if (!WIFEXITED(status[i])) { w_error(GENERAL, namestring, err[C_NOTEXIT], 0); return(INCOMPLETE); } } if (WEXITSTATUS(status[i])) { return(WEXITSTATUS(status[i])); } } /* * If we got here, both exited with status 0 or * subject exited 0 and object process was killed. */ return(PASS); } /* * This is S, the Subject process. */ if ( (forkval1) && (!forkval2) ) { /* * Close pipe descriptors S does not use. */ close(OtoS_fd[1]); close(StoO_fd[0]); /* * Malloc a mac_label pointer */ lptr = mac_get_proc(); /* * Set S process label. */ lptr->ml_msen_type = parmsptr->S_msen; lptr->ml_mint_type = parmsptr->S_mint; if ( cap_setplabel(lptr) ) { w_error(SYSCALL, namestring, err[F_SETPLABEL], errno); exit(INCOMPLETE); } mac_free(lptr); /* * Set ruid and euid to test value and verify. */ if ( ( cap_setreuid(parmsptr->uid, parmsptr->uid) ) == -1 ) { w_error(SYSCALL, namestring, err[SETREUID_S], errno); exit(INCOMPLETE); } if ( (getuid() != parmsptr->uid)||(geteuid() != parmsptr->uid) ) { w_error(GENERAL, namestring, err[BADUIDS_S], 0); exit(INCOMPLETE); } /* * Read what O wrote to the pipe. */ if ( (read(OtoS_fd[0], buf, sizeof(buf))) != sizeof(buf)) { w_error(SYSCALL, namestring, err[PIPEREAD_S], errno); exit(INCOMPLETE); } /* * Here's the test: Call Kill with O's pid as * arg1. */ if (parmsptr->c_flag == 0) { retval = kill(forkval1, SIGINT); }else{ retval = cap_kill(forkval1, SIGINT); } /* * Write to the pipe so O can go away. */ if ( (write(StoO_fd[1], buf, sizeof(buf))) != (sizeof(buf)) ) { w_error(SYSCALL, namestring, err[PIPEWRITE_S], errno); exit(INCOMPLETE); } /* * For positive cases, retval should be 0. */ if (parmsptr->expect_success == PASS ) { if ( retval == -1 ){ w_error(SYSCALL, namestring, err[TESTCALL], errno); exit(FAIL); } if (retval != 0) { w_error(PRINTNUM, namestring, err[TEST_RETVAL], retval); exit(FAIL); } exit(PASS); } /* * For negative test cases, retval should be -1 and * errno should equal parmsptr->expect_errno. */ if ( ( retval = kill(forkval1, SIGINT) ) != -1 ){ w_error(PRINTNUM, namestring, err[TEST_RETVAL], retval); exit(FAIL); } if (errno != parmsptr->expect_errno) { w_error(SYSCALL, namestring, err[TEST_ERRNO], errno); exit(FAIL); } exit(PASS); } /* * This is O, the Object process. */ /* * Begin O code. Close pipe descriptors that O does not use. */ close(OtoS_fd[0]); close(StoO_fd[1]); /* * Malloc a mac_label pointer */ lptr = mac_get_proc(); /* * Set O process label. */ lptr->ml_msen_type = parmsptr->O_msen; lptr->ml_mint_type = parmsptr->O_mint; if ( cap_setplabel(lptr) ) { w_error(SYSCALL, namestring, err[F_SETPLABEL], errno); exit(INCOMPLETE); } mac_free(lptr); /* * Set Object ruid and euid to test value and verify. */ if ( ( cap_setreuid(parmsptr->uid, parmsptr->uid) ) == -1 ) { w_error(SYSCALL, namestring, err[SETREUID_S], errno); exit(INCOMPLETE); } if ( (getuid() != parmsptr->uid)||(geteuid() != parmsptr->uid) ) { w_error(GENERAL, namestring, err[BADUIDS_S], 0); exit(INCOMPLETE); } /* * Write to the pipe so S can proceed. */ if ( write(OtoS_fd[1], buf, sizeof(buf)) != (sizeof(buf)) ) { w_error(SYSCALL, namestring, err[PIPEWRITE_O], errno); exit(INCOMPLETE); } /* * Read what Subject wrote to the pipe, then exit. * On positive tests, this child should * be killed while waiting to read. * On negative tests, subject exits without * writing, so read will fail because * there's no writer to the pipe. */ read(StoO_fd[0], buf, sizeof(buf)); exit(PASS); return(PASS); /* * End O code. */ }