1 |
/* |
2 |
* ccs_cond_test.c |
3 |
* |
4 |
* Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 |
* |
6 |
* Version: 2.4.0+ 2011/09/29 |
7 |
* |
8 |
* This program is free software; you can redistribute it and/or modify it |
9 |
* under the terms of the GNU General Public License v2 as published by the |
10 |
* Free Software Foundation. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, but WITHOUT |
13 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 |
* more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License along with |
18 |
* this program; if not, write to the Free Software Foundation, Inc., |
19 |
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
20 |
*/ |
21 |
#include "include.h" |
22 |
|
23 |
static void try_open(const char *policy, const char *file, const int mode, |
24 |
const char should_success) { |
25 |
FILE *fp; |
26 |
char buffer[8192]; |
27 |
int domain_found = 0; |
28 |
int policy_found = 0; |
29 |
int err = 0; |
30 |
memset(buffer, 0, sizeof(buffer)); |
31 |
set_profile(0, "file::open"); |
32 |
fp = fopen(proc_policy_domain_policy, "r+"); |
33 |
set_profile(3, "file::open"); |
34 |
printf("%s: ", policy); |
35 |
fflush(stdout); |
36 |
fprintf(domain_fp, "%s\n", policy); |
37 |
if (!fp) { |
38 |
printf("BUG: policy read failed\n"); |
39 |
return; |
40 |
} |
41 |
fprintf(fp, "select pid=%d\n", pid); |
42 |
while (fgets(buffer, sizeof(buffer) - 1, fp)) { |
43 |
char *cp = strchr(buffer, '\n'); |
44 |
if (cp) |
45 |
*cp = '\0'; |
46 |
if (!strncmp(buffer, "<kernel>", 8)) |
47 |
domain_found = !strcmp(self_domain, buffer); |
48 |
if (!domain_found) |
49 |
continue; |
50 |
/* printf("<%s>\n", buffer); */ |
51 |
if (!strcmp(buffer, policy)) { |
52 |
policy_found = 1; |
53 |
break; |
54 |
} |
55 |
} |
56 |
fclose(fp); |
57 |
if (!policy_found) { |
58 |
if (!strstr(policy, "read/write")) { |
59 |
printf("BUG: policy write failed\n"); |
60 |
return; |
61 |
} |
62 |
} |
63 |
{ |
64 |
int fd; |
65 |
errno = 0; |
66 |
fd = open(file, mode, 0); |
67 |
err = errno; |
68 |
if (fd != EOF) |
69 |
close(fd); |
70 |
} |
71 |
fprintf(domain_fp, "delete %s\n", policy); |
72 |
if (should_success) { |
73 |
if (!err) |
74 |
printf("OK\n"); |
75 |
else |
76 |
printf("BUG: failed (%d)\n", err); |
77 |
} else { |
78 |
if (err == EPERM) |
79 |
printf("OK: Permission denied.\n"); |
80 |
else |
81 |
printf("BUG: failed (%d)\n", err); |
82 |
} |
83 |
} |
84 |
|
85 |
static void stage_open_test(void) |
86 |
{ |
87 |
const pid_t pid = getppid(); |
88 |
int i; |
89 |
char buffer[128]; |
90 |
for (i = 0; i < 5; i++) { |
91 |
memset(buffer, 0, sizeof(buffer)); |
92 |
snprintf(buffer, sizeof(buffer) - 1, "/proc/%u/mounts", pid); |
93 |
try_open("file read /etc/fstab", "/etc/fstab", O_RDONLY, 1); |
94 |
try_open("file write /etc/fstab", "/etc/fstab", O_WRONLY, 1); |
95 |
try_open("file write /etc/fstab", "/etc/fstab", O_RDONLY, 0); |
96 |
try_open("file read /etc/fstab", "/etc/fstab", O_WRONLY, 0); |
97 |
try_open("file read/write /etc/fstab", "/etc/fstab", O_RDWR, |
98 |
1); |
99 |
try_open("file read/write /etc/fstab", "/etc/fstab", O_RDONLY, |
100 |
1); |
101 |
try_open("file read/write /etc/fstab", "/etc/fstab", O_WRONLY, |
102 |
1); |
103 |
try_open("file read /etc/fstab task.uid=0 task.euid=0", |
104 |
"/etc/fstab", O_RDONLY, 1); |
105 |
try_open("file read /etc/fstab " |
106 |
"task.uid=0 task.euid=0-4294967295", "/etc/fstab", |
107 |
O_RDONLY, 1); |
108 |
try_open("file read /etc/fstab " |
109 |
"task.uid=0 task.euid!=0-4294967295", "/etc/fstab", |
110 |
O_RDONLY, 0); |
111 |
try_open("file read /etc/fstab task.uid=0 task.euid!=0", |
112 |
"/etc/fstab", O_RDONLY, 0); |
113 |
try_open("file read /etc/fstab exec.argc=0", "/etc/fstab", |
114 |
O_RDONLY, 0); |
115 |
try_open("file read /etc/fstab exec.envc=0", "/etc/fstab", |
116 |
O_RDONLY, 0); |
117 |
try_open("file read /etc/fstab exec.argv[0]=\"\"", |
118 |
"/etc/fstab", O_RDONLY, 0); |
119 |
try_open("file read /etc/fstab exec.argv[0]!=\"\"", |
120 |
"/etc/fstab", O_RDONLY, 0); |
121 |
try_open("file read /etc/fstab exec.envp[\"HOME\"]=\"\"", |
122 |
"/etc/fstab", O_RDONLY, 0); |
123 |
try_open("file read /etc/fstab exec.envp[\"HOME\"]!=\"\"", |
124 |
"/etc/fstab", O_RDONLY, 0); |
125 |
try_open("file read /etc/fstab exec.envp[\"HOME\"]=NULL", |
126 |
"/etc/fstab", O_RDONLY, 0); |
127 |
try_open("file read /etc/fstab exec.envp[\"HOME\"]!=NULL", |
128 |
"/etc/fstab", O_RDONLY, 0); |
129 |
|
130 |
try_open("file read proc:/\\*/mounts", buffer, O_RDONLY, 1); |
131 |
try_open("file read proc:/\\@/mounts", buffer, O_RDONLY, 1); |
132 |
try_open("file read proc:/\\$/mounts", buffer, O_RDONLY, 1); |
133 |
try_open("file read proc:/\\X/mounts", buffer, O_RDONLY, 1); |
134 |
try_open("file read proc:/\\+/mounts", buffer, O_RDONLY, |
135 |
pid >= 0 && pid < 10); |
136 |
try_open("file read proc:/\\+\\+/mounts", buffer, O_RDONLY, |
137 |
pid >= 10 && pid < 100); |
138 |
try_open("file read proc:/\\+\\+\\+/mounts", buffer, O_RDONLY, |
139 |
pid >= 100 && pid < 1000); |
140 |
try_open("file read proc:/\\+\\+\\+\\+/mounts", buffer, |
141 |
O_RDONLY, pid >= 1000 && pid < 10000); |
142 |
try_open("file read proc:/\\+\\+\\+\\+\\+/mounts", buffer, |
143 |
O_RDONLY, pid >= 10000 && pid < 100000); |
144 |
try_open("file read proc:/\\+\\+\\+\\+\\+\\+/mounts", buffer, |
145 |
O_RDONLY, pid >= 100000 && pid < 1000000); |
146 |
|
147 |
try_open("file read proc:/\\x/mounts", buffer, O_RDONLY, |
148 |
pid < 10); |
149 |
try_open("file read proc:/\\x\\x/mounts", buffer, O_RDONLY, |
150 |
pid >= 10 && pid < 100); |
151 |
try_open("file read proc:/\\x\\x\\x/mounts", buffer, O_RDONLY, |
152 |
pid >= 100 && pid < 1000); |
153 |
try_open("file read proc:/\\x\\x\\x\\x/mounts", buffer, |
154 |
O_RDONLY, pid >= 1000 && pid < 10000); |
155 |
try_open("file read proc:/\\x\\x\\x\\x\\x/mounts", buffer, |
156 |
O_RDONLY, pid >= 10000 && pid < 100000); |
157 |
try_open("file read proc:/\\x\\x\\x\\x\\x\\x/mounts", buffer, |
158 |
O_RDONLY, pid >= 100000 && pid < 1000000); |
159 |
|
160 |
try_open("file read proc:/\\$\\*/mounts", buffer, O_RDONLY, 1); |
161 |
try_open("file read proc:/\\$\\@/mounts", buffer, O_RDONLY, 1); |
162 |
try_open("file read proc:/\\$\\*\\*/mounts", buffer, O_RDONLY, |
163 |
1); |
164 |
try_open("file read proc:/\\$\\@\\@/mounts", buffer, O_RDONLY, |
165 |
1); |
166 |
try_open("file read proc:/\\$\\*\\@/mounts", buffer, O_RDONLY, |
167 |
1); |
168 |
try_open("file read proc:/\\$\\@\\*/mounts", buffer, O_RDONLY, |
169 |
1); |
170 |
try_open("file read proc:/\\$\\*/mounts\\*", buffer, O_RDONLY, |
171 |
1); |
172 |
try_open("file read proc:/\\$\\@/mounts\\@", buffer, O_RDONLY, |
173 |
1); |
174 |
try_open("file read proc:/\\$\\*\\*/mounts\\*\\*", buffer, |
175 |
O_RDONLY, 1); |
176 |
try_open("file read proc:/\\$\\@\\@/mounts\\@\\@", buffer, |
177 |
O_RDONLY, 1); |
178 |
try_open("file read proc:/\\$\\*\\@/mounts\\*\\@", buffer, |
179 |
O_RDONLY, 1); |
180 |
try_open("file read proc:/\\$\\@\\*/mounts\\@\\*", buffer, |
181 |
O_RDONLY, 1); |
182 |
|
183 |
try_open("file read proc:/\\*\\$/mounts", buffer, O_RDONLY, 1); |
184 |
try_open("file read proc:/\\@\\$/mounts", buffer, O_RDONLY, 1); |
185 |
try_open("file read proc:/\\*\\*\\$/mounts", buffer, O_RDONLY, |
186 |
1); |
187 |
try_open("file read proc:/\\@\\@\\$/mounts", buffer, O_RDONLY, |
188 |
1); |
189 |
try_open("file read proc:/\\*\\@\\$/mounts", buffer, O_RDONLY, |
190 |
1); |
191 |
try_open("file read proc:/\\@\\*\\$/mounts", buffer, O_RDONLY, |
192 |
1); |
193 |
try_open("file read proc:/\\*\\$/\\*mounts", buffer, O_RDONLY, |
194 |
1); |
195 |
try_open("file read proc:/\\@\\$/\\@mounts", buffer, O_RDONLY, |
196 |
1); |
197 |
try_open("file read proc:/\\*\\*\\$/\\*\\*mounts", buffer, |
198 |
O_RDONLY, 1); |
199 |
try_open("file read proc:/\\@\\@\\$/\\@\\@mounts", buffer, |
200 |
O_RDONLY, 1); |
201 |
try_open("file read proc:/\\*\\@\\$/\\*\\@mounts", buffer, |
202 |
O_RDONLY, 1); |
203 |
try_open("file read proc:/\\@\\*\\$/\\@\\*mounts", buffer, |
204 |
O_RDONLY, 1); |
205 |
|
206 |
try_open("file read proc:/\\*\\$\\*/mounts", buffer, O_RDONLY, |
207 |
1); |
208 |
try_open("file read proc:/\\@\\$\\@/mounts", buffer, O_RDONLY, |
209 |
1); |
210 |
try_open("file read proc:/\\*\\*\\$\\*\\*/mounts", buffer, |
211 |
O_RDONLY, 1); |
212 |
try_open("file read proc:/\\@\\@\\$\\@\\@/mounts", buffer, |
213 |
O_RDONLY, 1); |
214 |
try_open("file read proc:/\\*\\@\\$\\*\\@/mounts", buffer, |
215 |
O_RDONLY, 1); |
216 |
try_open("file read proc:/\\@\\*\\$\\@\\*/mounts", buffer, |
217 |
O_RDONLY, 1); |
218 |
try_open("file read proc:/\\*\\$\\*/\\*mounts\\*", buffer, |
219 |
O_RDONLY, 1); |
220 |
try_open("file read proc:/\\@\\$\\@/\\@mounts\\@", buffer, |
221 |
O_RDONLY, 1); |
222 |
try_open("file read proc:/\\*\\*\\$\\*\\*/\\*\\*mounts\\*\\*", |
223 |
buffer, O_RDONLY, 1); |
224 |
try_open("file read proc:/\\@\\@\\$\\@\\@/\\@\\@mounts\\@\\@", |
225 |
buffer, O_RDONLY, 1); |
226 |
try_open("file read proc:/\\*\\@\\$\\*\\@/\\*\\@mounts\\*\\@", |
227 |
buffer, O_RDONLY, 1); |
228 |
try_open("file read proc:/\\@\\*\\$\\@\\*/\\@\\*mounts\\@\\*", |
229 |
buffer, O_RDONLY, 1); |
230 |
} |
231 |
} |
232 |
|
233 |
static int try_exec(void) |
234 |
{ |
235 |
int status = 0; |
236 |
int pipe_fd[2] = { EOF, EOF }; |
237 |
int ret_ignored = pipe(pipe_fd); |
238 |
switch (fork()) { |
239 |
case 0: |
240 |
errno = 0; |
241 |
execl("/bin/true", "true", NULL); |
242 |
/* Unreachable if execl() succeeded. */ |
243 |
status = errno; |
244 |
ret_ignored = write(pipe_fd[1], &status, sizeof(status)); |
245 |
_exit(0); |
246 |
case -1: |
247 |
fprintf(stderr, "fork() failed.\n"); |
248 |
break; |
249 |
default: |
250 |
close(pipe_fd[1]); |
251 |
ret_ignored = read(pipe_fd[0], &status, sizeof(status)); |
252 |
wait(NULL); |
253 |
close(pipe_fd[0]); |
254 |
} |
255 |
return status ? EOF : 0; |
256 |
} |
257 |
|
258 |
static void stage_cond_test(void) |
259 |
{ |
260 |
int fd; |
261 |
const char *policy; |
262 |
|
263 |
/* open read */ |
264 |
policy = "file read /etc/fstab task.uid=path1.uid"; |
265 |
write_domain_policy(policy, 0); |
266 |
fd = open("/etc/fstab", O_RDONLY); |
267 |
if (fd != EOF) |
268 |
close(fd); |
269 |
printf("%s : %s\n", policy, fd != EOF ? "OK" : "FAILED"); |
270 |
write_domain_policy(policy, 1); |
271 |
|
272 |
/* open read */ |
273 |
policy = "file read /etc/fstab task.uid!=path1.uid"; |
274 |
write_domain_policy(policy, 0); |
275 |
fd = open("/etc/fstab", O_RDONLY); |
276 |
if (fd != EOF) |
277 |
close(fd); |
278 |
printf("%s : %s\n", policy, fd == EOF ? "OK" : "FAILED"); |
279 |
write_domain_policy(policy, 1); |
280 |
|
281 |
/* open write */ |
282 |
policy = "file write /etc/fstab task.uid=path1.uid"; |
283 |
write_domain_policy(policy, 0); |
284 |
fd = open("/etc/fstab", O_WRONLY); |
285 |
if (fd != EOF) |
286 |
close(fd); |
287 |
printf("%s : %s\n", policy, fd != EOF ? "OK" : "FAILED"); |
288 |
write_domain_policy(policy, 1); |
289 |
|
290 |
/* open write */ |
291 |
policy = "file write /etc/fstab task.uid!=path1.uid"; |
292 |
write_domain_policy(policy, 0); |
293 |
fd = open("/etc/fstab", O_WRONLY); |
294 |
if (fd != EOF) |
295 |
close(fd); |
296 |
printf("%s : %s\n", policy, fd == EOF ? "OK" : "FAILED"); |
297 |
write_domain_policy(policy, 1); |
298 |
|
299 |
/* single path and single number */ |
300 |
policy = "file mkdir /tmp/testdir/ 0755 task.uid!=path1.parent.uid"; |
301 |
write_domain_policy(policy, 0); |
302 |
printf("%s : %s\n", policy, |
303 |
mkdir("/tmp/testdir", 0755) == EOF ? "OK" : "FAILED"); |
304 |
write_domain_policy(policy, 1); |
305 |
|
306 |
/* single path and single number */ |
307 |
policy = "file mkdir /tmp/testdir/ 0755 task.uid=path1.parent.uid"; |
308 |
write_domain_policy(policy, 0); |
309 |
printf("%s : %s\n", policy, |
310 |
mkdir("/tmp/testdir", 0755) == 0 ? "OK" : "FAILED"); |
311 |
write_domain_policy(policy, 1); |
312 |
|
313 |
/* single path */ |
314 |
policy = "file rmdir /tmp/testdir/ task.uid!=path1.uid"; |
315 |
write_domain_policy(policy, 0); |
316 |
printf("%s : %s\n", policy, |
317 |
rmdir("/tmp/testdir") == EOF ? "OK" : "FAILED"); |
318 |
write_domain_policy(policy, 1); |
319 |
|
320 |
/* single path */ |
321 |
policy = "file rmdir /tmp/testdir/ task.uid=path1.uid"; |
322 |
write_domain_policy(policy, 0); |
323 |
printf("%s : %s\n", policy, |
324 |
rmdir("/tmp/testdir") == 0 ? "OK" : "FAILED"); |
325 |
write_domain_policy(policy, 1); |
326 |
|
327 |
/* single path and three numbers */ |
328 |
policy = "file mkchar /tmp/char-1-3 0600 1 3 " |
329 |
"task.uid!=path1.parent.uid"; |
330 |
write_domain_policy(policy, 0); |
331 |
printf("%s : %s\n", policy, |
332 |
mknod("/tmp/char-1-3", S_IFCHR | 0600, MKDEV(1, 3)) == EOF ? |
333 |
"OK" : "FAILED"); |
334 |
write_domain_policy(policy, 1); |
335 |
|
336 |
/* single path and three numbers */ |
337 |
policy = "file mkchar /tmp/char-1-3 0600 1 3 " |
338 |
"task.uid=path1.parent.uid"; |
339 |
write_domain_policy(policy, 0); |
340 |
printf("%s : %s\n", policy, |
341 |
mknod("/tmp/char-1-3", S_IFCHR | 0600, MKDEV(1, 3)) == 0 ? |
342 |
"OK" : "FAILED"); |
343 |
write_domain_policy(policy, 1); |
344 |
|
345 |
/* two paths */ |
346 |
policy = "file rename /tmp/char-1-3 /tmp/char-1-3.new " |
347 |
"path1.parent.ino!=path2.parent.ino"; |
348 |
write_domain_policy(policy, 0); |
349 |
printf("%s : %s\n", policy, |
350 |
rename("/tmp/char-1-3", "/tmp/char-1-3.new") == EOF ? |
351 |
"OK" : "FAILED"); |
352 |
write_domain_policy(policy, 1); |
353 |
|
354 |
/* two paths */ |
355 |
policy = "file rename /tmp/char-1-3 /tmp/char-1-3.new " |
356 |
"path1.parent.ino=path2.parent.ino"; |
357 |
write_domain_policy(policy, 0); |
358 |
printf("%s : %s\n", policy, |
359 |
rename("/tmp/char-1-3", "/tmp/char-1-3.new") == 0 ? |
360 |
"OK" : "FAILED"); |
361 |
write_domain_policy(policy, 1); |
362 |
|
363 |
/* open execute */ |
364 |
policy = "file execute /bin/true task.uid!=path1.uid"; |
365 |
write_domain_policy(policy, 0); |
366 |
printf("%s : %s\n", policy, try_exec() == EOF ? "OK" : "FAILED"); |
367 |
write_domain_policy(policy, 1); |
368 |
|
369 |
/* open execute */ |
370 |
policy = "file execute /bin/true task.uid=path1.uid"; |
371 |
write_domain_policy(policy, 0); |
372 |
printf("%s : %s\n", policy, try_exec() == 0 ? "OK" : "FAILED"); |
373 |
write_domain_policy(policy, 1); |
374 |
|
375 |
/* open execute */ |
376 |
policy = "file execute /bin/true exec.realpath!=\"/bin/true\""; |
377 |
write_domain_policy(policy, 0); |
378 |
printf("%s : %s\n", policy, try_exec() == EOF ? "OK" : "FAILED"); |
379 |
write_domain_policy(policy, 1); |
380 |
|
381 |
/* open execute */ |
382 |
policy = "file execute /bin/true exec.realpath=\"/bin/true\""; |
383 |
write_domain_policy(policy, 0); |
384 |
printf("%s : %s\n", policy, try_exec() == 0 ? "OK" : "FAILED"); |
385 |
write_domain_policy(policy, 1); |
386 |
} |
387 |
|
388 |
int main(int argc, char *argv[]) |
389 |
{ |
390 |
ccs_test_init(); |
391 |
fprintf(domain_fp, "ignore_global\n"); |
392 |
fprintf(domain_fp, "file read/write %s\n", proc_policy_domain_policy); |
393 |
set_profile(3, "file::execute"); |
394 |
set_profile(3, "file::open"); |
395 |
set_profile(3, "file::create"); |
396 |
set_profile(3, "file::unlink"); |
397 |
set_profile(3, "file::mkdir"); |
398 |
set_profile(3, "file::rmdir"); |
399 |
set_profile(3, "file::mkfifo"); |
400 |
set_profile(3, "file::mksock"); |
401 |
set_profile(3, "file::truncate"); |
402 |
set_profile(3, "file::symlink"); |
403 |
set_profile(3, "file::mkblock"); |
404 |
set_profile(3, "file::mkchar"); |
405 |
set_profile(3, "file::link"); |
406 |
set_profile(3, "file::rename"); |
407 |
set_profile(3, "file::chmod"); |
408 |
set_profile(3, "file::chown"); |
409 |
set_profile(3, "file::chgrp"); |
410 |
set_profile(3, "file::ioctl"); |
411 |
set_profile(3, "file::chroot"); |
412 |
set_profile(3, "file::mount"); |
413 |
set_profile(3, "file::unmount"); |
414 |
set_profile(3, "file::pivot_root"); |
415 |
stage_open_test(); |
416 |
stage_cond_test(); |
417 |
set_profile(0, "file::execute"); |
418 |
set_profile(0, "file::open"); |
419 |
set_profile(0, "file::create"); |
420 |
set_profile(0, "file::unlink"); |
421 |
set_profile(0, "file::mkdir"); |
422 |
set_profile(0, "file::rmdir"); |
423 |
set_profile(0, "file::mkfifo"); |
424 |
set_profile(0, "file::mksock"); |
425 |
set_profile(0, "file::truncate"); |
426 |
set_profile(0, "file::symlink"); |
427 |
set_profile(0, "file::mkblock"); |
428 |
set_profile(0, "file::mkchar"); |
429 |
set_profile(0, "file::link"); |
430 |
set_profile(0, "file::rename"); |
431 |
set_profile(0, "file::chmod"); |
432 |
set_profile(0, "file::chown"); |
433 |
set_profile(0, "file::chgrp"); |
434 |
set_profile(0, "file::ioctl"); |
435 |
set_profile(0, "file::chroot"); |
436 |
set_profile(0, "file::mount"); |
437 |
set_profile(0, "file::unmount"); |
438 |
set_profile(0, "file::pivot_root"); |
439 |
clear_status(); |
440 |
if (0) /* To suppress "defined but not used" warnings. */ |
441 |
write_exception_policy("", 0); |
442 |
return 0; |
443 |
} |