 5977114c42
			
		
	
	
		5977114c42
		
	
	
	
	
		
			
			. make common.o link with the tests instead of being #included as common.c . fix warnings about missing prototypes by declaring functions static . reduces some duplicated code Change-Id: Ic2a765d7f5886add5863190efec3fdd2d2ea2137
		
			
				
	
	
		
			267 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <sys/types.h>
 | |
| #include <sys/wait.h>
 | |
| #include <stdio.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| 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 */
 | |
| }
 |