#include #include #include #include int max_error = 5; #include "common.h" int subtest = -1; void test_self(void); void test_setnone(void); void test_setuid(void); void test_setgid(void); void test_effugid(void); int execute(const char *prog, const char *arg); int execute(const char *prog, const char *arg) { pid_t childpid; int status; char cmd[30]; snprintf(cmd, sizeof(cmd), "./%s", prog); childpid = fork(); if (childpid == (pid_t) -1) { return(-2); } else if (childpid == 0) { if (execl(cmd, prog, arg, NULL) == -1) { exit(-2); } return(-2); /* Never reached */ } else { wait(&status); } return(WEXITSTATUS(status)); } void test_setgid(void) { /* Execve a new process that has setgid bits set */ subtest = 3; /* When we exec a new process which has setgid set, that process should * be tainted. */ system("chmod 2755 setgid"); if (execute("setgid", "0000") != 1) e(2); /* When we exec a new process which has setgid set, but unsets that bit * before calling issetugid() should still be tainted */ system("chmod 2755 setgid"); if (execute("setgid", "0755") != 1) e(3); /* When we exec a new process which has setgid set, and then also sets * setuid before calling issetugid() should still be tainted */ system("chmod 2755 setgid"); if (execute("setgid", "06755") != 1) e(4); /* When we exec a new process that has setgid set, and which upon * execution forks, the forked child should also be tainted */ system("chmod 2755 setgidfork"); if (execute("setgidfork", "0000") != 1) e(5); } void test_setuid(void) { /* Execve a new process that has setuid bits set */ subtest = 4; /* When we exec a new process which has setuid set, that process should * be tainted. */ system("chmod 4755 setuid"); if (execute("setuid", "0000") != 1) e(1); /* When we exec a new process which has setuid set, but unsets that bit * before calling issetugid() should still be tainted */ system("chmod 4755 setuid"); if (execute("setuid", "0755") != 1) e(2); /* When we exec a new process which has setuid set, and then also sets * setgid before calling issetugid() should still be tainted */ system("chmod 4755 setuid"); if (execute("setuid", "06755") != 1) e(3); /* When we exec a new process that has setgid set, and which upon * execution forks, the forked child should also be tainted */ system("chmod 4755 setuidfork"); if (execute("setuidfork", "0000") != 1) e(4); } static void test_setugid(void) { /* Execve a new process that has setuid and setgid bits set */ subtest = 5; /* When we exec a new process which has setugid set, that * process should be tainted. */ system("chmod 6755 setugid"); if (execute("setugid", "0000") != 1) e(1); /* When we exec a new process which has setugid set, but unsets those bits * before calling issetugid() should still be tainted */ system("chmod 6755 setugid"); if (execute("setugid", "0755") != 1) e(2); /* When we exec a new process that has setugid set, and which upon * execution forks, the forked child should also be tainted */ system("chmod 6755 setugidfork"); if (execute("setugidfork", "0000") != 1) e(4); } void test_effugid(void) { /* Test taint status with different effective uid and gid */ pid_t childpid; int status; subtest = 6; /* Start with effective uid */ childpid = fork(); if (childpid == (pid_t) -1) e(1); else if (childpid == 0) { /* We're the child */ /* We should be tainted */ if (issetugid() != 1) e(2); /* Now execute a program without set{u,g}id; should not be tainted */ system("chmod 755 nobits"); if (execute("nobits", "0000") != 0) e(3); /* Change effective uid into current+42 and try nobits again. This time * it should be tainted */ if (seteuid(geteuid() + 42) != 0) e(4); if (execute("nobits", "0000") != 1) e(5); exit(EXIT_SUCCESS); } else { /* We're the parent, wait for the child to finish */ wait(&status); } /* Now test effective gid */ childpid = fork(); if (childpid == (pid_t) -1) e(1); else if (childpid == 0) { /* We're the child */ /* We should be tainted */ if (issetugid() != 1) e(2); /* Now execute a program without set{u,g}id; should not be tainted */ system("chmod 755 nobits"); if (execute("nobits", "0000") != 0) e(3); /* Change effective gid into current+42 and try nobits again. This time * it should be tainted */ if (seteuid(getegid() + 42) != 0) e(4); if (execute("nobits", "0000") != 1) e(5); exit(EXIT_SUCCESS); } else { /* We're the parent, wait for the child to finish */ wait(&status); } } void test_setnone(void) { /* Execve a new process that does not have setuid or setgid bits set */ subtest = 2; /* When we exec a new process which doesn't have set{u,g}id set, that * process should not be tainted */ system("chmod 755 nobits"); if (execute("nobits", "0000") != 0) e(2); /* When we exec a new process which doesn't have set{u,g}id set, but * sets them after execution, the process should still not be tainted */ system("chmod 755 nobits"); if (execute("nobits", "02755") != 0) e(4); system("chmod 755 nobits"); if (execute("nobits", "04755") != 0) e(3); system("chmod 755 nobits"); if (execute("nobits", "06755") != 0) e(5); /* When we exec a new process that doesn't have setugid set, and which upon * execution forks, the forked child should not be tainted either */ system("chmod 755 nobitsfork"); if (execute("nobitsfork", "0000") != 0) e(6); } void test_self(void) { /* We're supposed to be setuid. Verify. */ int status; pid_t childpid; subtest = 1; if (issetugid() != 1) e(1); childpid = fork(); if (childpid == -1) e(2); else if (childpid == 0) { /* We're the child and should inherit the tainted status of the parent */ if (issetugid() != 1) e(3); /* Let's change to the bin user */ if (setuid((uid_t) 2) != 0) e(4); if (getuid() != (uid_t) 2) e(5); /* At this point, taint status should not have changed. */ if (issetugid() != 1) e(6); exit(EXIT_SUCCESS); } else { /* We're the parent. Wait for the child to finish */ wait(&status); } } static void switch_to_su(void) { subtest = 0; if (setuid(0) != 0) e(1); } int main(int argc, char **argv) { start(60); system("cp ../t60a nobits"); system("cp ../t60a setgid"); system("cp ../t60a setuid"); system("cp ../t60a setugid"); system("cp ../t60b nobitsfork"); system("cp ../t60b setuidfork"); system("cp ../t60b setgidfork"); system("cp ../t60b setugidfork"); switch_to_su(); /* We have to be root to perform this test */ test_self(); test_setnone(); test_setuid(); test_setgid(); test_setugid(); test_effugid(); quit(); return(-1); /* Never reached */ }