diff options
Diffstat (limited to 'src/jailtest/noexec.c')
-rw-r--r-- | src/jailtest/noexec.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/src/jailtest/noexec.c b/src/jailtest/noexec.c new file mode 100644 index 000000000..d2f85514a --- /dev/null +++ b/src/jailtest/noexec.c | |||
@@ -0,0 +1,94 @@ | |||
1 | #include "jailtest.h" | ||
2 | #include <sys/wait.h> | ||
3 | #include <sys/stat.h> | ||
4 | #include <fcntl.h> | ||
5 | |||
6 | static unsigned char *execfile = NULL; | ||
7 | static int execfile_len = 0; | ||
8 | |||
9 | void noexec_setup(void) { | ||
10 | // grab a copy of myself | ||
11 | char *self = realpath("/proc/self/exe", NULL); | ||
12 | if (self) { | ||
13 | struct stat s; | ||
14 | if (access(self, X_OK) == 0 && stat(self, &s) == 0) { | ||
15 | assert(s.st_size); | ||
16 | execfile = malloc(s.st_size); | ||
17 | |||
18 | int fd = open(self, O_RDONLY); | ||
19 | if (fd == -1) | ||
20 | errExit("open"); | ||
21 | int len = 0; | ||
22 | do { | ||
23 | int rv = read(fd, execfile + len, s.st_size - len); | ||
24 | if (rv == -1) | ||
25 | errExit("read"); | ||
26 | if (rv == 0) { | ||
27 | // something went wrong! | ||
28 | free(execfile); | ||
29 | execfile = NULL; | ||
30 | printf("Warning: I cannot grab a copy of myself, skipping noexec test...\n"); | ||
31 | break; | ||
32 | } | ||
33 | len += rv; | ||
34 | } | ||
35 | while (len < s.st_size); | ||
36 | execfile_len = s.st_size; | ||
37 | close(fd); | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | |||
43 | void noexec_test(const char *path) { | ||
44 | assert(user_uid); | ||
45 | |||
46 | // I am root in sandbox mount namespace | ||
47 | if (!execfile) | ||
48 | return; | ||
49 | |||
50 | char *fname; | ||
51 | if (asprintf(&fname, "%s/jailtest-noexec-%d", path, getpid()) == -1) | ||
52 | errExit("asprintf"); | ||
53 | |||
54 | pid_t child = fork(); | ||
55 | if (child == -1) | ||
56 | errExit("fork"); | ||
57 | |||
58 | if (child == 0) { // child | ||
59 | // drop privileges | ||
60 | if (setgid(user_gid) != 0) | ||
61 | errExit("setgid"); | ||
62 | if (setuid(user_uid) != 0) | ||
63 | errExit("setuid"); | ||
64 | int fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0700); | ||
65 | if (fd == -1) { | ||
66 | printf(" I cannot create files in %s, skipping noexec...\n", path); | ||
67 | exit(1); | ||
68 | } | ||
69 | |||
70 | int len = 0; | ||
71 | while (len < execfile_len) { | ||
72 | int rv = write(fd, execfile + len, execfile_len - len); | ||
73 | if (rv == -1 || rv == 0) { | ||
74 | printf(" I cannot create files in %s, skipping noexec....\n", path); | ||
75 | exit(1); | ||
76 | } | ||
77 | len += rv; | ||
78 | } | ||
79 | fchmod(fd, 0700); | ||
80 | close(fd); | ||
81 | |||
82 | char *arg; | ||
83 | if (asprintf(&arg, "--hello=%s", path) == -1) | ||
84 | errExit("asprintf"); | ||
85 | int rv = execl(fname, fname, arg, NULL); | ||
86 | (void) rv; // if we get here execl failed | ||
87 | exit(0); | ||
88 | } | ||
89 | |||
90 | int status; | ||
91 | wait(&status); | ||
92 | int rv = unlink(fname); | ||
93 | (void) rv; | ||
94 | } \ No newline at end of file | ||