オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /trunk/1.7.x/ccs-tools/ccstools/usr_sbin/ccs-checkpolicy.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3707 - (show annotations) (download) (as text)
Tue Jun 1 05:21:48 2010 UTC (14 years ago) by kumaneko
File MIME type: text/x-csrc
File size: 28488 byte(s)
Allow wildcard for execute permission and domainname
1 /*
2 * ccs-checkpolicy.c
3 *
4 * TOMOYO Linux's utilities.
5 *
6 * Copyright (C) 2005-2010 NTT DATA CORPORATION
7 *
8 * Version: 1.7.2+ 2010/04/06
9 *
10 */
11 #include "ccstools.h"
12
13 #define CCS_KEYWORD_AGGREGATOR "aggregator "
14 #define CCS_KEYWORD_ALLOW_CAPABILITY "allow_capability "
15 #define CCS_KEYWORD_ALLOW_CHGRP "allow_chgrp "
16 #define CCS_KEYWORD_ALLOW_CHMOD "allow_chmod "
17 #define CCS_KEYWORD_ALLOW_CHOWN "allow_chown "
18 #define CCS_KEYWORD_ALLOW_CHROOT "allow_chroot "
19 #define CCS_KEYWORD_ALLOW_ENV "allow_env "
20 #define CCS_KEYWORD_ALLOW_IOCTL "allow_ioctl "
21 #define CCS_KEYWORD_ALLOW_MOUNT "allow_mount "
22 #define CCS_KEYWORD_ALLOW_NETWORK "allow_network "
23 #define CCS_KEYWORD_ALLOW_PIVOT_ROOT "allow_pivot_root "
24 #define CCS_KEYWORD_ALLOW_SIGNAL "allow_signal "
25 #define CCS_KEYWORD_ALLOW_UNMOUNT "allow_unmount "
26 #define CCS_KEYWORD_DENY_AUTOBIND "deny_autobind "
27 #define CCS_KEYWORD_DENY_REWRITE "deny_rewrite "
28 #define CCS_KEYWORD_FILE_PATTERN "file_pattern "
29 #define CCS_KEYWORD_MAC_FOR_CAPABILITY "MAC_FOR_CAPABILITY::"
30 #define CCS_KEYWORD_SELECT "select "
31
32 #define CCS_MAX_PATHNAME_LEN 4000
33
34 enum ccs_policy_type {
35 CCS_POLICY_TYPE_UNKNOWN,
36 CCS_POLICY_TYPE_DOMAIN_POLICY,
37 CCS_POLICY_TYPE_EXCEPTION_POLICY,
38 };
39
40 enum ccs_socket_operation_type {
41 CCS_NETWORK_ACL_UDP_BIND,
42 CCS_NETWORK_ACL_UDP_CONNECT,
43 CCS_NETWORK_ACL_TCP_BIND,
44 CCS_NETWORK_ACL_TCP_LISTEN,
45 CCS_NETWORK_ACL_TCP_CONNECT,
46 CCS_NETWORK_ACL_TCP_ACCEPT,
47 CCS_NETWORK_ACL_RAW_BIND,
48 CCS_NETWORK_ACL_RAW_CONNECT
49 };
50
51 #define CCS_VALUE_TYPE_DECIMAL 1
52 #define CCS_VALUE_TYPE_OCTAL 2
53 #define CCS_VALUE_TYPE_HEXADECIMAL 3
54
55 static int ccs_parse_ulong(unsigned long *result, char **str)
56 {
57 const char *cp = *str;
58 char *ep;
59 int base = 10;
60 if (*cp == '0') {
61 char c = *(cp + 1);
62 if (c == 'x' || c == 'X') {
63 base = 16;
64 cp += 2;
65 } else if (c >= '0' && c <= '7') {
66 base = 8;
67 cp++;
68 }
69 }
70 *result = strtoul(cp, &ep, base);
71 if (cp == ep)
72 return 0;
73 *str = ep;
74 return base == 16 ? CCS_VALUE_TYPE_HEXADECIMAL :
75 (base == 8 ? CCS_VALUE_TYPE_OCTAL : CCS_VALUE_TYPE_DECIMAL);
76 }
77
78 static char *ccs_find_condition_part(char *data)
79 {
80 char *cp = strstr(data, " if ");
81 if (!cp)
82 cp = strstr(data, " ; set ");
83 if (cp)
84 *cp++ = '\0';
85 return cp;
86 }
87
88 static unsigned int ccs_line = 0;
89 static unsigned int ccs_errors = 0;
90 static unsigned int ccs_warnings = 0;
91
92 static _Bool ccs_check_condition(char *condition)
93 {
94 enum ccs_conditions_index {
95 CCS_TASK_UID, /* current_uid() */
96 CCS_TASK_EUID, /* current_euid() */
97 CCS_TASK_SUID, /* current_suid() */
98 CCS_TASK_FSUID, /* current_fsuid() */
99 CCS_TASK_GID, /* current_gid() */
100 CCS_TASK_EGID, /* current_egid() */
101 CCS_TASK_SGID, /* current_sgid() */
102 CCS_TASK_FSGID, /* current_fsgid() */
103 CCS_TASK_PID, /* sys_getpid() */
104 CCS_TASK_PPID, /* sys_getppid() */
105 CCS_EXEC_ARGC, /* "struct linux_binprm *"->argc */
106 CCS_EXEC_ENVC, /* "struct linux_binprm *"->envc */
107 CCS_TASK_STATE_0, /* (u8) (current->ccs_flags >> 24) */
108 CCS_TASK_STATE_1, /* (u8) (current->ccs_flags >> 16) */
109 CCS_TASK_STATE_2, /* (u8) (task->ccs_flags >> 8) */
110 CCS_TYPE_IS_SOCKET, /* S_IFSOCK */
111 CCS_TYPE_IS_SYMLINK, /* S_IFLNK */
112 CCS_TYPE_IS_FILE, /* S_IFREG */
113 CCS_TYPE_IS_BLOCK_DEV, /* S_IFBLK */
114 CCS_TYPE_IS_DIRECTORY, /* S_IFDIR */
115 CCS_TYPE_IS_CHAR_DEV, /* S_IFCHR */
116 CCS_TYPE_IS_FIFO, /* S_IFIFO */
117 CCS_MODE_SETUID, /* S_ISUID */
118 CCS_MODE_SETGID, /* S_ISGID */
119 CCS_MODE_STICKY, /* S_ISVTX */
120 CCS_MODE_OWNER_READ, /* S_IRUSR */
121 CCS_MODE_OWNER_WRITE, /* S_IWUSR */
122 CCS_MODE_OWNER_EXECUTE, /* S_IXUSR */
123 CCS_MODE_GROUP_READ, /* S_IRGRP */
124 CCS_MODE_GROUP_WRITE, /* S_IWGRP */
125 CCS_MODE_GROUP_EXECUTE, /* S_IXGRP */
126 CCS_MODE_OTHERS_READ, /* S_IROTH */
127 CCS_MODE_OTHERS_WRITE, /* S_IWOTH */
128 CCS_MODE_OTHERS_EXECUTE, /* S_IXOTH */
129 CCS_TASK_TYPE, /* ((u8) task->ccs_flags) &
130 CCS_TASK_IS_EXECUTE_HANDLER */
131 CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
132 CCS_EXEC_REALPATH,
133 CCS_SYMLINK_TARGET,
134 CCS_PATH1_UID,
135 CCS_PATH1_GID,
136 CCS_PATH1_INO,
137 CCS_PATH1_MAJOR,
138 CCS_PATH1_MINOR,
139 CCS_PATH1_PERM,
140 CCS_PATH1_TYPE,
141 CCS_PATH1_DEV_MAJOR,
142 CCS_PATH1_DEV_MINOR,
143 CCS_PATH2_UID,
144 CCS_PATH2_GID,
145 CCS_PATH2_INO,
146 CCS_PATH2_MAJOR,
147 CCS_PATH2_MINOR,
148 CCS_PATH2_PERM,
149 CCS_PATH2_TYPE,
150 CCS_PATH2_DEV_MAJOR,
151 CCS_PATH2_DEV_MINOR,
152 CCS_PATH1_PARENT_UID,
153 CCS_PATH1_PARENT_GID,
154 CCS_PATH1_PARENT_INO,
155 CCS_PATH1_PARENT_PERM,
156 CCS_PATH2_PARENT_UID,
157 CCS_PATH2_PARENT_GID,
158 CCS_PATH2_PARENT_INO,
159 CCS_PATH2_PARENT_PERM,
160 CCS_MAX_CONDITION_KEYWORD,
161 CCS_NUMBER_UNION,
162 CCS_NAME_UNION,
163 CCS_ARGV_ENTRY,
164 CCS_ENVP_ENTRY
165 };
166 static const char *ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
167 [CCS_TASK_UID] = "task.uid",
168 [CCS_TASK_EUID] = "task.euid",
169 [CCS_TASK_SUID] = "task.suid",
170 [CCS_TASK_FSUID] = "task.fsuid",
171 [CCS_TASK_GID] = "task.gid",
172 [CCS_TASK_EGID] = "task.egid",
173 [CCS_TASK_SGID] = "task.sgid",
174 [CCS_TASK_FSGID] = "task.fsgid",
175 [CCS_TASK_PID] = "task.pid",
176 [CCS_TASK_PPID] = "task.ppid",
177 [CCS_EXEC_ARGC] = "exec.argc",
178 [CCS_EXEC_ENVC] = "exec.envc",
179 [CCS_TASK_STATE_0] = "task.state[0]",
180 [CCS_TASK_STATE_1] = "task.state[1]",
181 [CCS_TASK_STATE_2] = "task.state[2]",
182 [CCS_TYPE_IS_SOCKET] = "socket",
183 [CCS_TYPE_IS_SYMLINK] = "symlink",
184 [CCS_TYPE_IS_FILE] = "file",
185 [CCS_TYPE_IS_BLOCK_DEV] = "block",
186 [CCS_TYPE_IS_DIRECTORY] = "directory",
187 [CCS_TYPE_IS_CHAR_DEV] = "char",
188 [CCS_TYPE_IS_FIFO] = "fifo",
189 [CCS_MODE_SETUID] = "setuid",
190 [CCS_MODE_SETGID] = "setgid",
191 [CCS_MODE_STICKY] = "sticky",
192 [CCS_MODE_OWNER_READ] = "owner_read",
193 [CCS_MODE_OWNER_WRITE] = "owner_write",
194 [CCS_MODE_OWNER_EXECUTE] = "owner_execute",
195 [CCS_MODE_GROUP_READ] = "group_read",
196 [CCS_MODE_GROUP_WRITE] = "group_write",
197 [CCS_MODE_GROUP_EXECUTE] = "group_execute",
198 [CCS_MODE_OTHERS_READ] = "others_read",
199 [CCS_MODE_OTHERS_WRITE] = "others_write",
200 [CCS_MODE_OTHERS_EXECUTE] = "others_execute",
201 [CCS_TASK_TYPE] = "task.type",
202 [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
203 [CCS_EXEC_REALPATH] = "exec.realpath",
204 [CCS_SYMLINK_TARGET] = "symlink.target",
205 [CCS_PATH1_UID] = "path1.uid",
206 [CCS_PATH1_GID] = "path1.gid",
207 [CCS_PATH1_INO] = "path1.ino",
208 [CCS_PATH1_MAJOR] = "path1.major",
209 [CCS_PATH1_MINOR] = "path1.minor",
210 [CCS_PATH1_PERM] = "path1.perm",
211 [CCS_PATH1_TYPE] = "path1.type",
212 [CCS_PATH1_DEV_MAJOR] = "path1.dev_major",
213 [CCS_PATH1_DEV_MINOR] = "path1.dev_minor",
214 [CCS_PATH2_UID] = "path2.uid",
215 [CCS_PATH2_GID] = "path2.gid",
216 [CCS_PATH2_INO] = "path2.ino",
217 [CCS_PATH2_MAJOR] = "path2.major",
218 [CCS_PATH2_MINOR] = "path2.minor",
219 [CCS_PATH2_PERM] = "path2.perm",
220 [CCS_PATH2_TYPE] = "path2.type",
221 [CCS_PATH2_DEV_MAJOR] = "path2.dev_major",
222 [CCS_PATH2_DEV_MINOR] = "path2.dev_minor",
223 [CCS_PATH1_PARENT_UID] = "path1.parent.uid",
224 [CCS_PATH1_PARENT_GID] = "path1.parent.gid",
225 [CCS_PATH1_PARENT_INO] = "path1.parent.ino",
226 [CCS_PATH1_PARENT_PERM] = "path1.parent.perm",
227 [CCS_PATH2_PARENT_UID] = "path2.parent.uid",
228 [CCS_PATH2_PARENT_GID] = "path2.parent.gid",
229 [CCS_PATH2_PARENT_INO] = "path2.parent.ino",
230 [CCS_PATH2_PARENT_PERM] = "path2.parent.perm",
231 };
232 char *const start = condition;
233 char *pos = condition;
234 u8 left;
235 u8 right;
236 int i;
237 unsigned long left_min = 0;
238 unsigned long left_max = 0;
239 unsigned long right_min = 0;
240 unsigned long right_max = 0;
241 u8 post_state[4] = { 0, 0, 0, 0 };
242 condition = strstr(condition, "; set ");
243 if (condition) {
244 *condition = '\0';
245 condition += 6;
246 while (true) {
247 while (*condition == ' ')
248 condition++;
249 if (!*condition)
250 break;
251 pos = condition;
252 if (!strncmp(condition, "task.state[0]=", 14))
253 i = 0;
254 else if (!strncmp(condition, "task.state[1]=", 14))
255 i = 1;
256 else if (!strncmp(condition, "task.state[2]=", 14))
257 i = 2;
258 else
259 goto out;
260 condition += 14;
261 if (post_state[3] & (1 << i))
262 goto out;
263 post_state[3] |= 1 << i;
264 if (!ccs_parse_ulong(&right_min, &condition) ||
265 right_min > 255)
266 goto out;
267 post_state[i] = (u8) right_min;
268 }
269 }
270 condition = start;
271 if (*condition && condition[strlen(condition) - 1] == ' ')
272 condition[strlen(condition) - 1] = '\0';
273 if (!*condition)
274 return true;
275 if (strncmp(condition, "if ", 3))
276 goto out;
277 condition += 3;
278
279 pos = condition;
280 while (pos) {
281 char *eq;
282 char *next = strchr(pos, ' ');
283 int r_len;
284 if (next)
285 *next++ = '\0';
286 if (!ccs_correct_word(pos))
287 goto out;
288 eq = strchr(pos, '=');
289 if (!eq)
290 goto out;
291 *eq = '\0';
292 if (eq > pos && *(eq - 1) == '!')
293 *(eq - 1) = '\0';
294 r_len = strlen(eq + 1);
295 if (!strncmp(pos, "exec.argv[", 10)) {
296 pos += 10;
297 if (!ccs_parse_ulong(&left_min, &pos) || strcmp(pos, "]"))
298 goto out;
299 pos = eq + 1;
300 if (r_len < 2)
301 goto out;
302 if (pos[0] == '"' && pos[r_len - 1] == '"')
303 goto next;
304 goto out;
305 } else if (!strncmp(pos, "exec.envp[\"", 11)) {
306 if (strcmp(pos + strlen(pos) - 2, "\"]"))
307 goto out;
308 pos = eq + 1;
309 if (!strcmp(pos, "NULL"))
310 goto next;
311 if (r_len < 2)
312 goto out;
313 if (pos[0] == '"' && pos[r_len - 1] == '"')
314 goto next;
315 goto out;
316 }
317 for (left = 0; left < CCS_MAX_CONDITION_KEYWORD; left++) {
318 const char *keyword = ccs_condition_keyword[left];
319 if (strcmp(pos, keyword))
320 continue;
321 break;
322 }
323 if (left == CCS_MAX_CONDITION_KEYWORD) {
324 if (!ccs_parse_ulong(&left_min, &pos))
325 goto out;
326 if (pos[0] == '-') {
327 pos++;
328 if (!ccs_parse_ulong(&left_max, &pos) || pos[0] ||
329 left_min > left_max)
330 goto out;
331 } else if (pos[0])
332 goto out;
333 }
334 pos = eq + 1;
335 if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
336 if (r_len < 2)
337 goto out;
338 if (pos[0] == '@')
339 goto next;
340 if (pos[0] == '"' && pos[r_len - 1] == '"')
341 goto next;
342 goto out;
343 }
344 for (right = 0; right < CCS_MAX_CONDITION_KEYWORD; right++) {
345 const char *keyword = ccs_condition_keyword[right];
346 if (strcmp(pos, keyword))
347 continue;
348 break;
349 }
350 if (right < CCS_MAX_CONDITION_KEYWORD)
351 goto next;
352 if (pos[0] == '@' && pos[1])
353 goto next;
354 if (!ccs_parse_ulong(&right_min, &pos))
355 goto out;
356 if (pos[0] == '-') {
357 pos++;
358 if (!ccs_parse_ulong(&right_max, &pos) || pos[0] ||
359 right_min > right_max)
360 goto out;
361 } else if (pos[0])
362 goto out;
363 next:
364 pos = next;
365 }
366 return true;
367 out:
368 printf("%u: ERROR: '%s' is an illegal condition.\n", ccs_line, pos);
369 ccs_errors++;
370 return false;
371 }
372
373 static void ccs_check_capability_policy(char *data)
374 {
375 static const char *capability_keywords[] = {
376 "inet_tcp_create", "inet_tcp_listen", "inet_tcp_connect",
377 "use_inet_udp", "use_inet_ip", "use_route", "use_packet",
378 "SYS_MOUNT", "SYS_UMOUNT", "SYS_REBOOT", "SYS_CHROOT",
379 "SYS_KILL", "SYS_VHANGUP", "SYS_TIME", "SYS_NICE",
380 "SYS_SETHOSTNAME", "use_kernel_module", "create_fifo",
381 "create_block_dev", "create_char_dev", "create_unix_socket",
382 "SYS_LINK", "SYS_SYMLINK", "SYS_RENAME", "SYS_UNLINK",
383 "SYS_CHMOD", "SYS_CHOWN", "SYS_IOCTL", "SYS_KEXEC_LOAD",
384 "SYS_PIVOT_ROOT", "SYS_PTRACE", "conceal_mount", NULL
385 };
386 int i;
387 for (i = 0; capability_keywords[i]; i++) {
388 if (!strcmp(data, capability_keywords[i]))
389 return;
390 }
391 printf("%u: ERROR: '%s' is a bad capability name.\n", ccs_line, data);
392 ccs_errors++;
393 }
394
395 static void ccs_check_signal_policy(char *data)
396 {
397 int sig;
398 char *cp;
399 cp = strchr(data, ' ');
400 if (!cp) {
401 printf("%u: ERROR: Too few parameters.\n", ccs_line);
402 ccs_errors++;
403 return;
404 }
405 *cp++ = '\0';
406 if (sscanf(data, "%d", &sig) != 1) {
407 printf("%u: ERROR: '%s' is a bad signal number.\n", ccs_line, data);
408 ccs_errors++;
409 }
410 if (!ccs_correct_domain(cp)) {
411 printf("%u: ERROR: '%s' is a bad domainname.\n", ccs_line, cp);
412 ccs_errors++;
413 }
414 }
415
416 static void ccs_check_env_policy(char *data)
417 {
418 if (!ccs_correct_word(data)) {
419 printf("%u: ERROR: '%s' is a bad variable name.\n", ccs_line, data);
420 ccs_errors++;
421 }
422 }
423
424 static void ccs_check_network_policy(char *data)
425 {
426 int sock_type;
427 int operation;
428 u16 min_address[8];
429 u16 max_address[8];
430 unsigned int min_port;
431 unsigned int max_port;
432 int count;
433 char *cp1 = NULL;
434 char *cp2 = NULL;
435 cp1 = strchr(data, ' ');
436 if (!cp1)
437 goto out;
438 cp1++;
439 if (!strncmp(data, "TCP ", 4))
440 sock_type = SOCK_STREAM;
441 else if (!strncmp(data, "UDP ", 4))
442 sock_type = SOCK_DGRAM;
443 else if (!strncmp(data, "RAW ", 4))
444 sock_type = SOCK_RAW;
445 else
446 goto out;
447 cp2 = strchr(cp1, ' ');
448 if (!cp2)
449 goto out;
450 cp2++;
451 if (!strncmp(cp1, "bind ", 5)) {
452 operation = (sock_type == SOCK_STREAM) ? CCS_NETWORK_ACL_TCP_BIND :
453 (sock_type == SOCK_DGRAM) ? CCS_NETWORK_ACL_UDP_BIND :
454 CCS_NETWORK_ACL_RAW_BIND;
455 } else if (!strncmp(cp1, "connect ", 8)) {
456 operation = (sock_type == SOCK_STREAM) ?
457 CCS_NETWORK_ACL_TCP_CONNECT : (sock_type == SOCK_DGRAM) ?
458 CCS_NETWORK_ACL_UDP_CONNECT : CCS_NETWORK_ACL_RAW_CONNECT;
459 } else if (sock_type == SOCK_STREAM && !strncmp(cp1, "listen ", 7)) {
460 operation = CCS_NETWORK_ACL_TCP_LISTEN;
461 } else if (sock_type == SOCK_STREAM && !strncmp(cp1, "accept ", 7)) {
462 operation = CCS_NETWORK_ACL_TCP_ACCEPT;
463 } else {
464 goto out;
465 }
466 cp1 = strchr(cp2, ' ');
467 if (!cp1)
468 goto out;
469 cp1++;
470 count = sscanf(cp2, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx-"
471 "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
472 &min_address[0], &min_address[1], &min_address[2],
473 &min_address[3], &min_address[4], &min_address[5],
474 &min_address[6], &min_address[7], &max_address[0],
475 &max_address[1], &max_address[2], &max_address[3],
476 &max_address[4], &max_address[5], &max_address[6],
477 &max_address[7]);
478 if (count == 8 || count == 16) {
479 int i;
480 for (i = 0; i < 8; i++) {
481 min_address[i] = htons(min_address[i]);
482 max_address[i] = htons(max_address[i]);
483 }
484 if (count == 8)
485 memmove(max_address, min_address, sizeof(min_address));
486 goto next;
487 }
488 count = sscanf(cp2, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
489 &min_address[0], &min_address[1], &min_address[2],
490 &min_address[3], &max_address[0], &max_address[1],
491 &max_address[2], &max_address[3]);
492 if (count == 4 || count == 8) {
493 u32 ip = htonl((((u8) min_address[0]) << 24) +
494 (((u8) min_address[1]) << 16) +
495 (((u8) min_address[2]) << 8) +
496 (u8) min_address[3]);
497 memmove(min_address, &ip, sizeof(ip));
498 if (count == 8)
499 ip = htonl((((u8) max_address[0]) << 24) +
500 (((u8) max_address[1]) << 16) +
501 (((u8) max_address[2]) << 8) +
502 (u8) max_address[3]);
503 memmove(max_address, &ip, sizeof(ip));
504 goto next;
505 }
506 if (*cp2 != '@') /* Don't reject address_group. */
507 goto out;
508 next:
509 if (strchr(cp1, ' '))
510 goto out;
511 count = sscanf(cp1, "%u-%u", &min_port, &max_port);
512 if (count == 1 || count == 2) {
513 if (count == 1)
514 max_port = min_port;
515 if (min_port <= max_port && max_port < 65536)
516 return;
517 }
518 out:
519 printf("%u: ERROR: Bad network address.\n", ccs_line);
520 ccs_errors++;
521 }
522
523 static void ccs_check_file_policy(char *data)
524 {
525 static const struct {
526 const char * const keyword;
527 const int paths;
528 } acl_type_array[] = {
529 { "execute", 1 },
530 { "transit", 1 },
531 { "read/write", 1 },
532 { "read", 1 },
533 { "write", 1 },
534 { "create", 2 },
535 { "unlink", 1 },
536 { "mkdir", 2 },
537 { "rmdir", 1 },
538 { "mkfifo", 2 },
539 { "mksock", 2 },
540 { "mkblock", 4 },
541 { "mkchar", 4 },
542 { "truncate", 1 },
543 { "symlink", 1 },
544 { "link", 2 },
545 { "rename", 2 },
546 { "rewrite", 1 },
547 { "chmod", 2 },
548 { "chown", 2 },
549 { "chgrp", 2 },
550 { "ioctl", 2 },
551 { "mount", 4 },
552 { "unmount", 1 },
553 { "chroot", 1 },
554 { "pivot_root", 2 },
555 { NULL, 0 }
556 };
557 char *filename = strchr(data, ' ');
558 char *cp;
559 int type;
560 if (!filename) {
561 printf("%u: ERROR: Unknown command '%s'\n", ccs_line, data);
562 ccs_errors++;
563 return;
564 }
565 *filename++ = '\0';
566 if (strncmp(data, "allow_", 6))
567 goto out;
568 data += 6;
569 for (type = 0; acl_type_array[type].keyword; type++) {
570 if (strcmp(data, acl_type_array[type].keyword))
571 continue;
572 if (acl_type_array[type].paths == 4) {
573 cp = strrchr(filename, ' ');
574 if (!cp) {
575 printf("%u: ERROR: Too few arguments.\n",
576 ccs_line);
577 break;
578 }
579 if (!ccs_correct_word(cp + 1)) {
580 printf("%u: ERROR: '%s' is a bad argument\n",
581 ccs_line, cp + 1);
582 break;
583 }
584 *cp = '\0';
585 cp = strrchr(filename, ' ');
586 if (!cp) {
587 printf("%u: ERROR: Too few arguments.\n",
588 ccs_line);
589 break;
590 }
591 if (!ccs_correct_word(cp + 1)) {
592 printf("%u: ERROR: '%s' is a bad argument.\n",
593 ccs_line, cp + 1);
594 break;
595 }
596 *cp = '\0';
597 }
598 if (acl_type_array[type].paths >= 2) {
599 cp = strrchr(filename, ' ');
600 if (!cp) {
601 printf("%u: ERROR: Too few arguments.\n",
602 ccs_line);
603 break;
604 }
605 if (!ccs_correct_word(cp + 1)) {
606 printf("%u: ERROR: '%s' is a bad argument.\n",
607 ccs_line, cp + 1);
608 break;
609 }
610 *cp = '\0';
611 }
612 if (!ccs_correct_word(filename)) {
613 printf("%u: ERROR: '%s' is a bad argument.\n", ccs_line,
614 filename);
615 break;
616 }
617 return;
618 }
619 if (!acl_type_array[type].keyword)
620 goto out;
621 ccs_errors++;
622 return;
623 out:
624 printf("%u: ERROR: Invalid permission '%s %s'\n", ccs_line, data, filename);
625 ccs_errors++;
626 }
627
628 static void ccs_check_reserved_port_policy(char *data)
629 {
630 unsigned int from;
631 unsigned int to;
632 if (strchr(data, ' '))
633 goto out;
634 if (sscanf(data, "%u-%u", &from, &to) == 2) {
635 if (from <= to && to < 65536)
636 return;
637 } else if (sscanf(data, "%u", &from) == 1) {
638 if (from < 65536)
639 return;
640 } else {
641 printf("%u: ERROR: Too few parameters.\n", ccs_line);
642 ccs_errors++;
643 return;
644 }
645 out:
646 printf("%u: ERROR: '%s' is a bad port number.\n", ccs_line, data);
647 ccs_errors++;
648 }
649
650 static void ccs_check_domain_initializer_entry(const char *domainname,
651 const char *program)
652 {
653 if (!ccs_correct_path(program)) {
654 printf("%u: ERROR: '%s' is a bad pathname.\n", ccs_line, program);
655 ccs_errors++;
656 }
657 if (domainname && !ccs_correct_path(domainname) &&
658 !ccs_correct_domain(domainname)) {
659 printf("%u: ERROR: '%s' is a bad domainname.\n",
660 ccs_line, domainname);
661 ccs_errors++;
662 }
663 }
664
665 static void ccs_check_domain_initializer_policy(char *data)
666 {
667 char *cp = strstr(data, " from ");
668 if (cp) {
669 *cp = '\0';
670 ccs_check_domain_initializer_entry(cp + 6, data);
671 } else {
672 ccs_check_domain_initializer_entry(NULL, data);
673 }
674 }
675
676 static void ccs_check_domain_keeper_entry(const char *domainname,
677 const char *program)
678 {
679 if (!ccs_correct_path(domainname) && !ccs_correct_domain(domainname)) {
680 printf("%u: ERROR: '%s' is a bad domainname.\n",
681 ccs_line, domainname);
682 ccs_errors++;
683 }
684 if (program && !ccs_correct_path(program)) {
685 printf("%u: ERROR: '%s' is a bad pathname.\n", ccs_line, program);
686 ccs_errors++;
687 }
688 }
689
690 static void ccs_check_domain_keeper_policy(char *data)
691 {
692 char *cp = strstr(data, " from ");
693 if (cp) {
694 *cp = '\0';
695 ccs_check_domain_keeper_entry(cp + 6, data);
696 } else {
697 ccs_check_domain_keeper_entry(data, NULL);
698 }
699 }
700
701 static void ccs_check_path_group_policy(char *data)
702 {
703 char *cp = strchr(data, ' ');
704 if (!cp) {
705 printf("%u: ERROR: Too few parameters.\n", ccs_line);
706 ccs_errors++;
707 return;
708 }
709 *cp++ = '\0';
710 if (!ccs_correct_word(data)) {
711 printf("%u: ERROR: '%s' is a bad group name.\n", ccs_line, data);
712 ccs_errors++;
713 }
714 if (!ccs_correct_word(cp)) {
715 printf("%u: ERROR: '%s' is a bad pathname.\n", ccs_line, cp);
716 ccs_errors++;
717 }
718 }
719
720 static void ccs_check_number_group_policy(char *data)
721 {
722 char *cp = strchr(data, ' ');
723 unsigned long v;
724 if (!cp) {
725 printf("%u: ERROR: Too few parameters.\n", ccs_line);
726 ccs_errors++;
727 return;
728 }
729 *cp++ = '\0';
730 if (!ccs_correct_word(data)) {
731 printf("%u: ERROR: '%s' is a bad group name.\n", ccs_line, data);
732 ccs_errors++;
733 }
734 data = cp;
735 cp = strchr(data, '-');
736 if (cp)
737 *cp = '\0';
738 if (!ccs_parse_ulong(&v, &data) || *data) {
739 printf("%u: ERROR: '%s' is a bad number.\n", ccs_line, data);
740 ccs_errors++;
741 }
742 if (cp && !ccs_parse_ulong(&v, &cp)) {
743 printf("%u: ERROR: '%s' is a bad number.\n", ccs_line, cp);
744 ccs_errors++;
745 }
746 }
747
748 static void ccs_check_address_group_policy(char *data)
749 {
750 char *cp = strchr(data, ' ');
751 u16 min_address[8];
752 u16 max_address[8];
753 int count;
754 if (!cp) {
755 printf("%u: ERROR: Too few parameters.\n", ccs_line);
756 ccs_errors++;
757 return;
758 }
759 *cp++ = '\0';
760 if (!ccs_correct_word(data)) {
761 printf("%u: ERROR: '%s' is a bad group name.\n", ccs_line, data);
762 ccs_errors++;
763 }
764 count = sscanf(cp, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx-"
765 "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
766 &min_address[0], &min_address[1], &min_address[2],
767 &min_address[3], &min_address[4], &min_address[5],
768 &min_address[6], &min_address[7], &max_address[0],
769 &max_address[1], &max_address[2], &max_address[3],
770 &max_address[4], &max_address[5], &max_address[6],
771 &max_address[7]);
772 if (count == 8 || count == 16)
773 return;
774 count = sscanf(cp, "%hu.%hu.%hu.%hu-%hu.%hu.%hu.%hu",
775 &min_address[0], &min_address[1], &min_address[2],
776 &min_address[3], &max_address[0], &max_address[1],
777 &max_address[2], &max_address[3]);
778 if (count == 4 || count == 8)
779 return;
780 printf("%u: ERROR: '%s' is a bad address.\n", ccs_line, cp);
781 ccs_errors++;
782 }
783
784 static void ccs_check_domain_policy(char *policy)
785 {
786 static int domain = EOF;
787 _Bool is_delete = false;
788 _Bool is_select = false;
789 if (ccs_str_starts(policy, CCS_KEYWORD_DELETE))
790 is_delete = true;
791 else if (ccs_str_starts(policy, CCS_KEYWORD_SELECT))
792 is_select = true;
793 if (!strncmp(policy, "<kernel>", 8)) {
794 if (!ccs_correct_domain(policy) ||
795 strlen(policy) >= CCS_MAX_PATHNAME_LEN) {
796 printf("%u: ERROR: '%s' is a bad domainname.\n",
797 ccs_line, policy);
798 ccs_errors++;
799 } else {
800 if (is_delete)
801 domain = EOF;
802 else
803 domain = 0;
804 }
805 } else if (is_select) {
806 printf("%u: ERROR: Command 'select' is valid for selecting "
807 "domains only.\n", ccs_line);
808 ccs_errors++;
809 } else if (domain == EOF) {
810 printf("%u: WARNING: '%s' is unprocessed because domain is not "
811 "selected.\n", ccs_line, policy);
812 ccs_warnings++;
813 } else if (ccs_str_starts(policy, CCS_KEYWORD_USE_PROFILE)) {
814 unsigned int profile;
815 if (sscanf(policy, "%u", &profile) != 1 ||
816 profile >= 256) {
817 printf("%u: ERROR: '%s' is a bad profile.\n",
818 ccs_line, policy);
819 ccs_errors++;
820 }
821 } else if (!strcmp(policy, "ignore_global_allow_read")) {
822 /* Nothing to do. */
823 } else if (!strcmp(policy, "ignore_global_allow_env")) {
824 /* Nothing to do. */
825 } else if (ccs_str_starts(policy, "execute_handler ") ||
826 ccs_str_starts(policy, "denied_execute_handler")) {
827 if (!ccs_correct_path(policy)) {
828 printf("%u: ERROR: '%s' is a bad pathname.\n",
829 ccs_line, policy);
830 ccs_errors++;
831 }
832 } else if (!strcmp(policy, "transition_failed")) {
833 /* Nothing to do. */
834 } else if (!strcmp(policy, "quota_exceeded")) {
835 /* Nothing to do. */
836 } else {
837 char *cp = ccs_find_condition_part(policy);
838 if (cp && !ccs_check_condition(cp))
839 return;
840 if (ccs_str_starts(policy, CCS_KEYWORD_ALLOW_CAPABILITY))
841 ccs_check_capability_policy(policy);
842 else if (ccs_str_starts(policy, CCS_KEYWORD_ALLOW_NETWORK))
843 ccs_check_network_policy(policy);
844 else if (ccs_str_starts(policy, CCS_KEYWORD_ALLOW_SIGNAL))
845 ccs_check_signal_policy(policy);
846 else if (ccs_str_starts(policy, CCS_KEYWORD_ALLOW_ENV))
847 ccs_check_env_policy(policy);
848 else
849 ccs_check_file_policy(policy);
850 }
851 }
852
853 static void ccs_check_exception_policy(char *policy)
854 {
855 ccs_str_starts(policy, CCS_KEYWORD_DELETE);
856 if (ccs_str_starts(policy, CCS_KEYWORD_ALLOW_READ)) {
857 if (!ccs_correct_path(policy)) {
858 printf("%u: ERROR: '%s' is a bad pathname.\n",
859 ccs_line, policy);
860 ccs_errors++;
861 }
862 } else if (ccs_str_starts(policy, CCS_KEYWORD_INITIALIZE_DOMAIN)) {
863 ccs_check_domain_initializer_policy(policy);
864 } else if (ccs_str_starts(policy, CCS_KEYWORD_NO_INITIALIZE_DOMAIN)) {
865 ccs_check_domain_initializer_policy(policy);
866 } else if (ccs_str_starts(policy, CCS_KEYWORD_KEEP_DOMAIN)) {
867 ccs_check_domain_keeper_policy(policy);
868 } else if (ccs_str_starts(policy, CCS_KEYWORD_NO_KEEP_DOMAIN)) {
869 ccs_check_domain_keeper_policy(policy);
870 } else if (ccs_str_starts(policy, CCS_KEYWORD_PATH_GROUP)) {
871 ccs_check_path_group_policy(policy);
872 } else if (ccs_str_starts(policy, CCS_KEYWORD_NUMBER_GROUP)) {
873 ccs_check_number_group_policy(policy);
874 } else if (ccs_str_starts(policy, CCS_KEYWORD_ADDRESS_GROUP)) {
875 ccs_check_address_group_policy(policy);
876 } else if (ccs_str_starts(policy, CCS_KEYWORD_AGGREGATOR)) {
877 char *cp = strchr(policy, ' ');
878 if (!cp) {
879 printf("%u: ERROR: Too few parameters.\n", ccs_line);
880 ccs_errors++;
881 } else {
882 *cp++ = '\0';
883 if (!ccs_correct_path(policy)) {
884 printf("%u: ERROR: '%s' is a bad pattern.\n",
885 ccs_line, policy);
886 ccs_errors++;
887 }
888 if (!ccs_correct_path(cp)) {
889 printf("%u: ERROR: '%s' is a bad pathname.\n",
890 ccs_line, cp);
891 ccs_errors++;
892 }
893 }
894 } else if (ccs_str_starts(policy, CCS_KEYWORD_FILE_PATTERN)) {
895 if (!ccs_correct_word(policy)) {
896 printf("%u: ERROR: '%s' is a bad pattern.\n",
897 ccs_line, policy);
898 ccs_errors++;
899 }
900 } else if (ccs_str_starts(policy, CCS_KEYWORD_DENY_REWRITE)) {
901 if (!ccs_correct_word(policy)) {
902 printf("%u: ERROR: '%s' is a bad pattern.\n",
903 ccs_line, policy);
904 ccs_errors++;
905 }
906 } else if (ccs_str_starts(policy, CCS_KEYWORD_ALLOW_ENV)) {
907 if (!ccs_correct_word(policy)) {
908 printf("%u: ERROR: '%s' is a bad variable name.\n",
909 ccs_line, policy);
910 ccs_errors++;
911 }
912 } else if (ccs_str_starts(policy, CCS_KEYWORD_DENY_AUTOBIND)) {
913 ccs_check_reserved_port_policy(policy);
914 } else {
915 printf("%u: ERROR: Unknown command '%s'.\n",
916 ccs_line, policy);
917 ccs_errors++;
918 }
919 }
920
921 int main(int argc, char *argv[])
922 {
923 char *policy = NULL;
924 int policy_type = CCS_POLICY_TYPE_UNKNOWN;
925 if (argc > 1) {
926 switch (argv[1][0]) {
927 case 'e':
928 policy_type = CCS_POLICY_TYPE_EXCEPTION_POLICY;
929 break;
930 case 'd':
931 policy_type = CCS_POLICY_TYPE_DOMAIN_POLICY;
932 break;
933 }
934 }
935 if (policy_type == CCS_POLICY_TYPE_UNKNOWN) {
936 fprintf(stderr, "%s e|d < policy_to_check\n", argv[0]);
937 return 0;
938 }
939 while (true) {
940 _Bool badchar_warned = false;
941 int pos = 0;
942 ccs_line++;
943 while (true) {
944 static int max_policy_len = 0;
945 int c = getchar();
946 if (c == EOF)
947 goto out;
948 if (pos == max_policy_len) {
949 char *cp;
950 max_policy_len += 4096;
951 cp = realloc(policy, max_policy_len);
952 if (!cp)
953 ccs_out_of_memory();
954 policy = cp;
955 }
956 policy[pos++] = (char) c;
957 if (c == '\n') {
958 policy[--pos] = '\0';
959 break;
960 }
961 if (badchar_warned ||
962 c == '\t' || (c >= ' ' && c < 127))
963 continue;
964 printf("%u: WARNING: Line contains illegal "
965 "character (\\%03o).\n", ccs_line, c);
966 ccs_warnings++;
967 badchar_warned = true;
968 }
969 ccs_normalize_line(policy);
970 if (!policy[0] || policy[0] == '#')
971 continue;
972 switch (policy_type) {
973 case CCS_POLICY_TYPE_DOMAIN_POLICY:
974 ccs_check_domain_policy(policy);
975 break;
976 case CCS_POLICY_TYPE_EXCEPTION_POLICY:
977 ccs_check_exception_policy(policy);
978 break;
979 }
980 }
981 out:
982 free(policy);
983 policy = NULL;
984 ccs_line--;
985 printf("Total: %u Line%s %u Error%s %u Warning%s\n",
986 ccs_line, ccs_line > 1 ? "s" : "", ccs_errors, ccs_errors > 1 ? "s" : "",
987 ccs_warnings, ccs_warnings > 1 ? "s" : "");
988 return ccs_errors ? 2 : (ccs_warnings ? 1 : 0);
989 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26