Implement issetugid syscall
Implement issetugid syscall and provide a test. This gets rid of the scary "Unsecure. Implement me" warning during compilation.
This commit is contained in:
@@ -16,10 +16,10 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
||||
test30 test31 test32 test34 test35 test36 test37 test38 \
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
|
||||
test42 test45 test47 test49 test50 test51 test52 test53 \
|
||||
test54 test56 test58
|
||||
test54 test56 test58 t60a t60b
|
||||
|
||||
BIGOBJ= test20 test24
|
||||
ROOTOBJ= test11 test33 test43 test44 test46
|
||||
ROOTOBJ= test11 test33 test43 test44 test46 test60
|
||||
GCCOBJ= test45-gcc test48 test49-gcc test55
|
||||
GCCFPUOBJ= test51-gcc test52-gcc
|
||||
OTHEROBJ= test57 test59
|
||||
@@ -53,7 +53,9 @@ depend: .gitignore
|
||||
clean:
|
||||
$(MAKE) -C select clean
|
||||
-rm -rf *.o *.s *.bak test? test?? test??-gcc t10a t11a t11b \
|
||||
t40a t40b t40c t40d t40e t40f t43 DIR*
|
||||
t40a t40b t40c t40d t40e t40f t43 \
|
||||
t60a t60b \
|
||||
DIR*
|
||||
|
||||
test1: test1.c
|
||||
test2: test2.c
|
||||
@@ -128,3 +130,6 @@ test57: test57.c test57loop.S
|
||||
test58: test58.c
|
||||
test59: test59.c
|
||||
$(CC) $(CFLAGS) -o $@ $@.c -lmthread
|
||||
test60: test60.c
|
||||
t60a: t60a.c
|
||||
t60b: t60b.c
|
||||
|
||||
1
test/run
1
test/run
@@ -15,6 +15,7 @@ tests=" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||
41 42 43 44 45 45-gcc 46 47 48 49 49-gcc 50 \
|
||||
51 51-gcc 52 52-gcc 53 54 55 56 57 58 59\
|
||||
60 \
|
||||
sh1.sh sh2.sh"
|
||||
tests_no=`expr 0`
|
||||
|
||||
|
||||
18
test/t60a.c
Normal file
18
test/t60a.c
Normal file
@@ -0,0 +1,18 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Return our tainted state to the parent */
|
||||
int newmode;
|
||||
char cmd[30];
|
||||
|
||||
if (argc < 2) return(-2);
|
||||
if ((newmode = atoi(argv[1])) > 0) {
|
||||
snprintf(cmd, sizeof(cmd), "chmod %o %s", newmode, argv[0]);
|
||||
system(cmd);
|
||||
}
|
||||
|
||||
return(issetugid());
|
||||
}
|
||||
23
test/t60b.c
Normal file
23
test/t60b.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Return the tainted state of our child to our parent */
|
||||
pid_t childpid;
|
||||
int status;
|
||||
|
||||
childpid = fork();
|
||||
if (childpid == (pid_t) -1) exit(-2);
|
||||
else if (childpid == 0) {
|
||||
exit(issetugid());
|
||||
} else {
|
||||
wait(&status);
|
||||
}
|
||||
|
||||
return(WEXITSTATUS(status));
|
||||
}
|
||||
|
||||
265
test/test60.c
Normal file
265
test/test60.c
Normal file
@@ -0,0 +1,265 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_ERROR 5
|
||||
#include "common.c"
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
Reference in New Issue
Block a user