diff options
Diffstat (limited to 'security/tomoyo/condition.c')
-rw-r--r-- | security/tomoyo/condition.c | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c new file mode 100644 index 000000000000..8a05f71eaf67 --- /dev/null +++ b/security/tomoyo/condition.c | |||
@@ -0,0 +1,1035 @@ | |||
1 | /* | ||
2 | * security/tomoyo/condition.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION | ||
5 | */ | ||
6 | |||
7 | #include "common.h" | ||
8 | #include <linux/slab.h> | ||
9 | |||
10 | /* List of "struct tomoyo_condition". */ | ||
11 | LIST_HEAD(tomoyo_condition_list); | ||
12 | |||
13 | /** | ||
14 | * tomoyo_argv - Check argv[] in "struct linux_binbrm". | ||
15 | * | ||
16 | * @index: Index number of @arg_ptr. | ||
17 | * @arg_ptr: Contents of argv[@index]. | ||
18 | * @argc: Length of @argv. | ||
19 | * @argv: Pointer to "struct tomoyo_argv". | ||
20 | * @checked: Set to true if @argv[@index] was found. | ||
21 | * | ||
22 | * Returns true on success, false otherwise. | ||
23 | */ | ||
24 | static bool tomoyo_argv(const unsigned int index, const char *arg_ptr, | ||
25 | const int argc, const struct tomoyo_argv *argv, | ||
26 | u8 *checked) | ||
27 | { | ||
28 | int i; | ||
29 | struct tomoyo_path_info arg; | ||
30 | arg.name = arg_ptr; | ||
31 | for (i = 0; i < argc; argv++, checked++, i++) { | ||
32 | bool result; | ||
33 | if (index != argv->index) | ||
34 | continue; | ||
35 | *checked = 1; | ||
36 | tomoyo_fill_path_info(&arg); | ||
37 | result = tomoyo_path_matches_pattern(&arg, argv->value); | ||
38 | if (argv->is_not) | ||
39 | result = !result; | ||
40 | if (!result) | ||
41 | return false; | ||
42 | } | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * tomoyo_envp - Check envp[] in "struct linux_binbrm". | ||
48 | * | ||
49 | * @env_name: The name of environment variable. | ||
50 | * @env_value: The value of environment variable. | ||
51 | * @envc: Length of @envp. | ||
52 | * @envp: Pointer to "struct tomoyo_envp". | ||
53 | * @checked: Set to true if @envp[@env_name] was found. | ||
54 | * | ||
55 | * Returns true on success, false otherwise. | ||
56 | */ | ||
57 | static bool tomoyo_envp(const char *env_name, const char *env_value, | ||
58 | const int envc, const struct tomoyo_envp *envp, | ||
59 | u8 *checked) | ||
60 | { | ||
61 | int i; | ||
62 | struct tomoyo_path_info name; | ||
63 | struct tomoyo_path_info value; | ||
64 | name.name = env_name; | ||
65 | tomoyo_fill_path_info(&name); | ||
66 | value.name = env_value; | ||
67 | tomoyo_fill_path_info(&value); | ||
68 | for (i = 0; i < envc; envp++, checked++, i++) { | ||
69 | bool result; | ||
70 | if (!tomoyo_path_matches_pattern(&name, envp->name)) | ||
71 | continue; | ||
72 | *checked = 1; | ||
73 | if (envp->value) { | ||
74 | result = tomoyo_path_matches_pattern(&value, | ||
75 | envp->value); | ||
76 | if (envp->is_not) | ||
77 | result = !result; | ||
78 | } else { | ||
79 | result = true; | ||
80 | if (!envp->is_not) | ||
81 | result = !result; | ||
82 | } | ||
83 | if (!result) | ||
84 | return false; | ||
85 | } | ||
86 | return true; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * tomoyo_scan_bprm - Scan "struct linux_binprm". | ||
91 | * | ||
92 | * @ee: Pointer to "struct tomoyo_execve". | ||
93 | * @argc: Length of @argc. | ||
94 | * @argv: Pointer to "struct tomoyo_argv". | ||
95 | * @envc: Length of @envp. | ||
96 | * @envp: Poiner to "struct tomoyo_envp". | ||
97 | * | ||
98 | * Returns true on success, false otherwise. | ||
99 | */ | ||
100 | static bool tomoyo_scan_bprm(struct tomoyo_execve *ee, | ||
101 | const u16 argc, const struct tomoyo_argv *argv, | ||
102 | const u16 envc, const struct tomoyo_envp *envp) | ||
103 | { | ||
104 | struct linux_binprm *bprm = ee->bprm; | ||
105 | struct tomoyo_page_dump *dump = &ee->dump; | ||
106 | char *arg_ptr = ee->tmp; | ||
107 | int arg_len = 0; | ||
108 | unsigned long pos = bprm->p; | ||
109 | int offset = pos % PAGE_SIZE; | ||
110 | int argv_count = bprm->argc; | ||
111 | int envp_count = bprm->envc; | ||
112 | bool result = true; | ||
113 | u8 local_checked[32]; | ||
114 | u8 *checked; | ||
115 | if (argc + envc <= sizeof(local_checked)) { | ||
116 | checked = local_checked; | ||
117 | memset(local_checked, 0, sizeof(local_checked)); | ||
118 | } else { | ||
119 | checked = kzalloc(argc + envc, GFP_NOFS); | ||
120 | if (!checked) | ||
121 | return false; | ||
122 | } | ||
123 | while (argv_count || envp_count) { | ||
124 | if (!tomoyo_dump_page(bprm, pos, dump)) { | ||
125 | result = false; | ||
126 | goto out; | ||
127 | } | ||
128 | pos += PAGE_SIZE - offset; | ||
129 | while (offset < PAGE_SIZE) { | ||
130 | /* Read. */ | ||
131 | const char *kaddr = dump->data; | ||
132 | const unsigned char c = kaddr[offset++]; | ||
133 | if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) { | ||
134 | if (c == '\\') { | ||
135 | arg_ptr[arg_len++] = '\\'; | ||
136 | arg_ptr[arg_len++] = '\\'; | ||
137 | } else if (c > ' ' && c < 127) { | ||
138 | arg_ptr[arg_len++] = c; | ||
139 | } else { | ||
140 | arg_ptr[arg_len++] = '\\'; | ||
141 | arg_ptr[arg_len++] = (c >> 6) + '0'; | ||
142 | arg_ptr[arg_len++] = | ||
143 | ((c >> 3) & 7) + '0'; | ||
144 | arg_ptr[arg_len++] = (c & 7) + '0'; | ||
145 | } | ||
146 | } else { | ||
147 | arg_ptr[arg_len] = '\0'; | ||
148 | } | ||
149 | if (c) | ||
150 | continue; | ||
151 | /* Check. */ | ||
152 | if (argv_count) { | ||
153 | if (!tomoyo_argv(bprm->argc - argv_count, | ||
154 | arg_ptr, argc, argv, | ||
155 | checked)) { | ||
156 | result = false; | ||
157 | break; | ||
158 | } | ||
159 | argv_count--; | ||
160 | } else if (envp_count) { | ||
161 | char *cp = strchr(arg_ptr, '='); | ||
162 | if (cp) { | ||
163 | *cp = '\0'; | ||
164 | if (!tomoyo_envp(arg_ptr, cp + 1, | ||
165 | envc, envp, | ||
166 | checked + argc)) { | ||
167 | result = false; | ||
168 | break; | ||
169 | } | ||
170 | } | ||
171 | envp_count--; | ||
172 | } else { | ||
173 | break; | ||
174 | } | ||
175 | arg_len = 0; | ||
176 | } | ||
177 | offset = 0; | ||
178 | if (!result) | ||
179 | break; | ||
180 | } | ||
181 | out: | ||
182 | if (result) { | ||
183 | int i; | ||
184 | /* Check not-yet-checked entries. */ | ||
185 | for (i = 0; i < argc; i++) { | ||
186 | if (checked[i]) | ||
187 | continue; | ||
188 | /* | ||
189 | * Return true only if all unchecked indexes in | ||
190 | * bprm->argv[] are not matched. | ||
191 | */ | ||
192 | if (argv[i].is_not) | ||
193 | continue; | ||
194 | result = false; | ||
195 | break; | ||
196 | } | ||
197 | for (i = 0; i < envc; envp++, i++) { | ||
198 | if (checked[argc + i]) | ||
199 | continue; | ||
200 | /* | ||
201 | * Return true only if all unchecked environ variables | ||
202 | * in bprm->envp[] are either undefined or not matched. | ||
203 | */ | ||
204 | if ((!envp->value && !envp->is_not) || | ||
205 | (envp->value && envp->is_not)) | ||
206 | continue; | ||
207 | result = false; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | if (checked != local_checked) | ||
212 | kfree(checked); | ||
213 | return result; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". | ||
218 | * | ||
219 | * @file: Pointer to "struct file". | ||
220 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
221 | * @match: True if "exec.realpath=", false if "exec.realpath!=". | ||
222 | * | ||
223 | * Returns true on success, false otherwise. | ||
224 | */ | ||
225 | static bool tomoyo_scan_exec_realpath(struct file *file, | ||
226 | const struct tomoyo_name_union *ptr, | ||
227 | const bool match) | ||
228 | { | ||
229 | bool result; | ||
230 | struct tomoyo_path_info exe; | ||
231 | if (!file) | ||
232 | return false; | ||
233 | exe.name = tomoyo_realpath_from_path(&file->f_path); | ||
234 | if (!exe.name) | ||
235 | return false; | ||
236 | tomoyo_fill_path_info(&exe); | ||
237 | result = tomoyo_compare_name_union(&exe, ptr); | ||
238 | kfree(exe.name); | ||
239 | return result == match; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * tomoyo_get_dqword - tomoyo_get_name() for a quoted string. | ||
244 | * | ||
245 | * @start: String to save. | ||
246 | * | ||
247 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | ||
248 | */ | ||
249 | static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) | ||
250 | { | ||
251 | char *cp = start + strlen(start) - 1; | ||
252 | if (cp == start || *start++ != '"' || *cp != '"') | ||
253 | return NULL; | ||
254 | *cp = '\0'; | ||
255 | if (*start && !tomoyo_correct_word(start)) | ||
256 | return NULL; | ||
257 | return tomoyo_get_name(start); | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * tomoyo_parse_name_union_quoted - Parse a quoted word. | ||
262 | * | ||
263 | * @param: Pointer to "struct tomoyo_acl_param". | ||
264 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
265 | * | ||
266 | * Returns true on success, false otherwise. | ||
267 | */ | ||
268 | static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, | ||
269 | struct tomoyo_name_union *ptr) | ||
270 | { | ||
271 | char *filename = param->data; | ||
272 | if (*filename == '@') | ||
273 | return tomoyo_parse_name_union(param, ptr); | ||
274 | ptr->filename = tomoyo_get_dqword(filename); | ||
275 | return ptr->filename != NULL; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * tomoyo_parse_argv - Parse an argv[] condition part. | ||
280 | * | ||
281 | * @left: Lefthand value. | ||
282 | * @right: Righthand value. | ||
283 | * @argv: Pointer to "struct tomoyo_argv". | ||
284 | * | ||
285 | * Returns true on success, false otherwise. | ||
286 | */ | ||
287 | static bool tomoyo_parse_argv(char *left, char *right, | ||
288 | struct tomoyo_argv *argv) | ||
289 | { | ||
290 | if (tomoyo_parse_ulong(&argv->index, &left) != | ||
291 | TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left) | ||
292 | return false; | ||
293 | argv->value = tomoyo_get_dqword(right); | ||
294 | return argv->value != NULL; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * tomoyo_parse_envp - Parse an envp[] condition part. | ||
299 | * | ||
300 | * @left: Lefthand value. | ||
301 | * @right: Righthand value. | ||
302 | * @envp: Pointer to "struct tomoyo_envp". | ||
303 | * | ||
304 | * Returns true on success, false otherwise. | ||
305 | */ | ||
306 | static bool tomoyo_parse_envp(char *left, char *right, | ||
307 | struct tomoyo_envp *envp) | ||
308 | { | ||
309 | const struct tomoyo_path_info *name; | ||
310 | const struct tomoyo_path_info *value; | ||
311 | char *cp = left + strlen(left) - 1; | ||
312 | if (*cp-- != ']' || *cp != '"') | ||
313 | goto out; | ||
314 | *cp = '\0'; | ||
315 | if (!tomoyo_correct_word(left)) | ||
316 | goto out; | ||
317 | name = tomoyo_get_name(left); | ||
318 | if (!name) | ||
319 | goto out; | ||
320 | if (!strcmp(right, "NULL")) { | ||
321 | value = NULL; | ||
322 | } else { | ||
323 | value = tomoyo_get_dqword(right); | ||
324 | if (!value) { | ||
325 | tomoyo_put_name(name); | ||
326 | goto out; | ||
327 | } | ||
328 | } | ||
329 | envp->name = name; | ||
330 | envp->value = value; | ||
331 | return true; | ||
332 | out: | ||
333 | return false; | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. | ||
338 | * | ||
339 | * @a: Pointer to "struct tomoyo_condition". | ||
340 | * @b: Pointer to "struct tomoyo_condition". | ||
341 | * | ||
342 | * Returns true if @a == @b, false otherwise. | ||
343 | */ | ||
344 | static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | ||
345 | const struct tomoyo_condition *b) | ||
346 | { | ||
347 | return a->size == b->size && a->condc == b->condc && | ||
348 | a->numbers_count == b->numbers_count && | ||
349 | a->names_count == b->names_count && | ||
350 | a->argc == b->argc && a->envc == b->envc && | ||
351 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * tomoyo_condition_type - Get condition type. | ||
356 | * | ||
357 | * @word: Keyword string. | ||
358 | * | ||
359 | * Returns one of values in "enum tomoyo_conditions_index" on success, | ||
360 | * TOMOYO_MAX_CONDITION_KEYWORD otherwise. | ||
361 | */ | ||
362 | static u8 tomoyo_condition_type(const char *word) | ||
363 | { | ||
364 | u8 i; | ||
365 | for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) { | ||
366 | if (!strcmp(word, tomoyo_condition_keyword[i])) | ||
367 | break; | ||
368 | } | ||
369 | return i; | ||
370 | } | ||
371 | |||
372 | /* Define this to enable debug mode. */ | ||
373 | /* #define DEBUG_CONDITION */ | ||
374 | |||
375 | #ifdef DEBUG_CONDITION | ||
376 | #define dprintk printk | ||
377 | #else | ||
378 | #define dprintk(...) do { } while (0) | ||
379 | #endif | ||
380 | |||
381 | /** | ||
382 | * tomoyo_commit_condition - Commit "struct tomoyo_condition". | ||
383 | * | ||
384 | * @entry: Pointer to "struct tomoyo_condition". | ||
385 | * | ||
386 | * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. | ||
387 | * | ||
388 | * This function merges duplicated entries. This function returns NULL if | ||
389 | * @entry is not duplicated but memory quota for policy has exceeded. | ||
390 | */ | ||
391 | static struct tomoyo_condition *tomoyo_commit_condition | ||
392 | (struct tomoyo_condition *entry) | ||
393 | { | ||
394 | struct tomoyo_condition *ptr; | ||
395 | bool found = false; | ||
396 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) { | ||
397 | dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); | ||
398 | ptr = NULL; | ||
399 | found = true; | ||
400 | goto out; | ||
401 | } | ||
402 | list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) { | ||
403 | if (!tomoyo_same_condition(ptr, entry)) | ||
404 | continue; | ||
405 | /* Same entry found. Share this entry. */ | ||
406 | atomic_inc(&ptr->head.users); | ||
407 | found = true; | ||
408 | break; | ||
409 | } | ||
410 | if (!found) { | ||
411 | if (tomoyo_memory_ok(entry)) { | ||
412 | atomic_set(&entry->head.users, 1); | ||
413 | list_add_rcu(&entry->head.list, | ||
414 | &tomoyo_condition_list); | ||
415 | } else { | ||
416 | found = true; | ||
417 | ptr = NULL; | ||
418 | } | ||
419 | } | ||
420 | mutex_unlock(&tomoyo_policy_lock); | ||
421 | out: | ||
422 | if (found) { | ||
423 | tomoyo_del_condition(&entry->head.list); | ||
424 | kfree(entry); | ||
425 | entry = ptr; | ||
426 | } | ||
427 | return entry; | ||
428 | } | ||
429 | |||
430 | /** | ||
431 | * tomoyo_get_condition - Parse condition part. | ||
432 | * | ||
433 | * @param: Pointer to "struct tomoyo_acl_param". | ||
434 | * | ||
435 | * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. | ||
436 | */ | ||
437 | struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | ||
438 | { | ||
439 | struct tomoyo_condition *entry = NULL; | ||
440 | struct tomoyo_condition_element *condp = NULL; | ||
441 | struct tomoyo_number_union *numbers_p = NULL; | ||
442 | struct tomoyo_name_union *names_p = NULL; | ||
443 | struct tomoyo_argv *argv = NULL; | ||
444 | struct tomoyo_envp *envp = NULL; | ||
445 | struct tomoyo_condition e = { }; | ||
446 | char * const start_of_string = param->data; | ||
447 | char * const end_of_string = start_of_string + strlen(start_of_string); | ||
448 | char *pos; | ||
449 | rerun: | ||
450 | pos = start_of_string; | ||
451 | while (1) { | ||
452 | u8 left = -1; | ||
453 | u8 right = -1; | ||
454 | char *left_word = pos; | ||
455 | char *cp; | ||
456 | char *right_word; | ||
457 | bool is_not; | ||
458 | if (!*left_word) | ||
459 | break; | ||
460 | /* | ||
461 | * Since left-hand condition does not allow use of "path_group" | ||
462 | * or "number_group" and environment variable's names do not | ||
463 | * accept '=', it is guaranteed that the original line consists | ||
464 | * of one or more repetition of $left$operator$right blocks | ||
465 | * where "$left is free from '=' and ' '" and "$operator is | ||
466 | * either '=' or '!='" and "$right is free from ' '". | ||
467 | * Therefore, we can reconstruct the original line at the end | ||
468 | * of dry run even if we overwrite $operator with '\0'. | ||
469 | */ | ||
470 | cp = strchr(pos, ' '); | ||
471 | if (cp) { | ||
472 | *cp = '\0'; /* Will restore later. */ | ||
473 | pos = cp + 1; | ||
474 | } else { | ||
475 | pos = ""; | ||
476 | } | ||
477 | right_word = strchr(left_word, '='); | ||
478 | if (!right_word || right_word == left_word) | ||
479 | goto out; | ||
480 | is_not = *(right_word - 1) == '!'; | ||
481 | if (is_not) | ||
482 | *(right_word++ - 1) = '\0'; /* Will restore later. */ | ||
483 | else if (*(right_word + 1) != '=') | ||
484 | *right_word++ = '\0'; /* Will restore later. */ | ||
485 | else | ||
486 | goto out; | ||
487 | dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, | ||
488 | is_not ? "!" : "", right_word); | ||
489 | if (!strncmp(left_word, "exec.argv[", 10)) { | ||
490 | if (!argv) { | ||
491 | e.argc++; | ||
492 | e.condc++; | ||
493 | } else { | ||
494 | e.argc--; | ||
495 | e.condc--; | ||
496 | left = TOMOYO_ARGV_ENTRY; | ||
497 | argv->is_not = is_not; | ||
498 | if (!tomoyo_parse_argv(left_word + 10, | ||
499 | right_word, argv++)) | ||
500 | goto out; | ||
501 | } | ||
502 | goto store_value; | ||
503 | } | ||
504 | if (!strncmp(left_word, "exec.envp[\"", 11)) { | ||
505 | if (!envp) { | ||
506 | e.envc++; | ||
507 | e.condc++; | ||
508 | } else { | ||
509 | e.envc--; | ||
510 | e.condc--; | ||
511 | left = TOMOYO_ENVP_ENTRY; | ||
512 | envp->is_not = is_not; | ||
513 | if (!tomoyo_parse_envp(left_word + 11, | ||
514 | right_word, envp++)) | ||
515 | goto out; | ||
516 | } | ||
517 | goto store_value; | ||
518 | } | ||
519 | left = tomoyo_condition_type(left_word); | ||
520 | dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word, | ||
521 | left); | ||
522 | if (left == TOMOYO_MAX_CONDITION_KEYWORD) { | ||
523 | if (!numbers_p) { | ||
524 | e.numbers_count++; | ||
525 | } else { | ||
526 | e.numbers_count--; | ||
527 | left = TOMOYO_NUMBER_UNION; | ||
528 | param->data = left_word; | ||
529 | if (*left_word == '@' || | ||
530 | !tomoyo_parse_number_union(param, | ||
531 | numbers_p++)) | ||
532 | goto out; | ||
533 | } | ||
534 | } | ||
535 | if (!condp) | ||
536 | e.condc++; | ||
537 | else | ||
538 | e.condc--; | ||
539 | if (left == TOMOYO_EXEC_REALPATH || | ||
540 | left == TOMOYO_SYMLINK_TARGET) { | ||
541 | if (!names_p) { | ||
542 | e.names_count++; | ||
543 | } else { | ||
544 | e.names_count--; | ||
545 | right = TOMOYO_NAME_UNION; | ||
546 | param->data = right_word; | ||
547 | if (!tomoyo_parse_name_union_quoted(param, | ||
548 | names_p++)) | ||
549 | goto out; | ||
550 | } | ||
551 | goto store_value; | ||
552 | } | ||
553 | right = tomoyo_condition_type(right_word); | ||
554 | if (right == TOMOYO_MAX_CONDITION_KEYWORD) { | ||
555 | if (!numbers_p) { | ||
556 | e.numbers_count++; | ||
557 | } else { | ||
558 | e.numbers_count--; | ||
559 | right = TOMOYO_NUMBER_UNION; | ||
560 | param->data = right_word; | ||
561 | if (!tomoyo_parse_number_union(param, | ||
562 | numbers_p++)) | ||
563 | goto out; | ||
564 | } | ||
565 | } | ||
566 | store_value: | ||
567 | if (!condp) { | ||
568 | dprintk(KERN_WARNING "%u: dry_run left=%u right=%u " | ||
569 | "match=%u\n", __LINE__, left, right, !is_not); | ||
570 | continue; | ||
571 | } | ||
572 | condp->left = left; | ||
573 | condp->right = right; | ||
574 | condp->equals = !is_not; | ||
575 | dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n", | ||
576 | __LINE__, condp->left, condp->right, | ||
577 | condp->equals); | ||
578 | condp++; | ||
579 | } | ||
580 | dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n", | ||
581 | __LINE__, e.condc, e.numbers_count, e.names_count, e.argc, | ||
582 | e.envc); | ||
583 | if (entry) { | ||
584 | BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc | | ||
585 | e.condc); | ||
586 | return tomoyo_commit_condition(entry); | ||
587 | } | ||
588 | e.size = sizeof(*entry) | ||
589 | + e.condc * sizeof(struct tomoyo_condition_element) | ||
590 | + e.numbers_count * sizeof(struct tomoyo_number_union) | ||
591 | + e.names_count * sizeof(struct tomoyo_name_union) | ||
592 | + e.argc * sizeof(struct tomoyo_argv) | ||
593 | + e.envc * sizeof(struct tomoyo_envp); | ||
594 | entry = kzalloc(e.size, GFP_NOFS); | ||
595 | if (!entry) | ||
596 | return NULL; | ||
597 | *entry = e; | ||
598 | condp = (struct tomoyo_condition_element *) (entry + 1); | ||
599 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); | ||
600 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); | ||
601 | argv = (struct tomoyo_argv *) (names_p + e.names_count); | ||
602 | envp = (struct tomoyo_envp *) (argv + e.argc); | ||
603 | { | ||
604 | bool flag = false; | ||
605 | for (pos = start_of_string; pos < end_of_string; pos++) { | ||
606 | if (*pos) | ||
607 | continue; | ||
608 | if (flag) /* Restore " ". */ | ||
609 | *pos = ' '; | ||
610 | else if (*(pos + 1) == '=') /* Restore "!=". */ | ||
611 | *pos = '!'; | ||
612 | else /* Restore "=". */ | ||
613 | *pos = '='; | ||
614 | flag = !flag; | ||
615 | } | ||
616 | } | ||
617 | goto rerun; | ||
618 | out: | ||
619 | dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); | ||
620 | if (entry) { | ||
621 | tomoyo_del_condition(&entry->head.list); | ||
622 | kfree(entry); | ||
623 | } | ||
624 | return NULL; | ||
625 | } | ||
626 | |||
627 | /** | ||
628 | * tomoyo_get_attributes - Revalidate "struct inode". | ||
629 | * | ||
630 | * @obj: Pointer to "struct tomoyo_obj_info". | ||
631 | * | ||
632 | * Returns nothing. | ||
633 | */ | ||
634 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj) | ||
635 | { | ||
636 | u8 i; | ||
637 | struct dentry *dentry = NULL; | ||
638 | |||
639 | for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { | ||
640 | struct inode *inode; | ||
641 | switch (i) { | ||
642 | case TOMOYO_PATH1: | ||
643 | dentry = obj->path1.dentry; | ||
644 | if (!dentry) | ||
645 | continue; | ||
646 | break; | ||
647 | case TOMOYO_PATH2: | ||
648 | dentry = obj->path2.dentry; | ||
649 | if (!dentry) | ||
650 | continue; | ||
651 | break; | ||
652 | default: | ||
653 | if (!dentry) | ||
654 | continue; | ||
655 | dentry = dget_parent(dentry); | ||
656 | break; | ||
657 | } | ||
658 | inode = dentry->d_inode; | ||
659 | if (inode) { | ||
660 | struct tomoyo_mini_stat *stat = &obj->stat[i]; | ||
661 | stat->uid = inode->i_uid; | ||
662 | stat->gid = inode->i_gid; | ||
663 | stat->ino = inode->i_ino; | ||
664 | stat->mode = inode->i_mode; | ||
665 | stat->dev = inode->i_sb->s_dev; | ||
666 | stat->rdev = inode->i_rdev; | ||
667 | obj->stat_valid[i] = true; | ||
668 | } | ||
669 | if (i & 1) /* i == TOMOYO_PATH1_PARENT || | ||
670 | i == TOMOYO_PATH2_PARENT */ | ||
671 | dput(dentry); | ||
672 | } | ||
673 | } | ||
674 | |||
675 | /** | ||
676 | * tomoyo_condition - Check condition part. | ||
677 | * | ||
678 | * @r: Pointer to "struct tomoyo_request_info". | ||
679 | * @cond: Pointer to "struct tomoyo_condition". Maybe NULL. | ||
680 | * | ||
681 | * Returns true on success, false otherwise. | ||
682 | * | ||
683 | * Caller holds tomoyo_read_lock(). | ||
684 | */ | ||
685 | bool tomoyo_condition(struct tomoyo_request_info *r, | ||
686 | const struct tomoyo_condition *cond) | ||
687 | { | ||
688 | u32 i; | ||
689 | unsigned long min_v[2] = { 0, 0 }; | ||
690 | unsigned long max_v[2] = { 0, 0 }; | ||
691 | const struct tomoyo_condition_element *condp; | ||
692 | const struct tomoyo_number_union *numbers_p; | ||
693 | const struct tomoyo_name_union *names_p; | ||
694 | const struct tomoyo_argv *argv; | ||
695 | const struct tomoyo_envp *envp; | ||
696 | struct tomoyo_obj_info *obj; | ||
697 | u16 condc; | ||
698 | u16 argc; | ||
699 | u16 envc; | ||
700 | struct linux_binprm *bprm = NULL; | ||
701 | if (!cond) | ||
702 | return true; | ||
703 | condc = cond->condc; | ||
704 | argc = cond->argc; | ||
705 | envc = cond->envc; | ||
706 | obj = r->obj; | ||
707 | if (r->ee) | ||
708 | bprm = r->ee->bprm; | ||
709 | if (!bprm && (argc || envc)) | ||
710 | return false; | ||
711 | condp = (struct tomoyo_condition_element *) (cond + 1); | ||
712 | numbers_p = (const struct tomoyo_number_union *) (condp + condc); | ||
713 | names_p = (const struct tomoyo_name_union *) | ||
714 | (numbers_p + cond->numbers_count); | ||
715 | argv = (const struct tomoyo_argv *) (names_p + cond->names_count); | ||
716 | envp = (const struct tomoyo_envp *) (argv + argc); | ||
717 | for (i = 0; i < condc; i++) { | ||
718 | const bool match = condp->equals; | ||
719 | const u8 left = condp->left; | ||
720 | const u8 right = condp->right; | ||
721 | bool is_bitop[2] = { false, false }; | ||
722 | u8 j; | ||
723 | condp++; | ||
724 | /* Check argv[] and envp[] later. */ | ||
725 | if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY) | ||
726 | continue; | ||
727 | /* Check string expressions. */ | ||
728 | if (right == TOMOYO_NAME_UNION) { | ||
729 | const struct tomoyo_name_union *ptr = names_p++; | ||
730 | switch (left) { | ||
731 | struct tomoyo_path_info *symlink; | ||
732 | struct tomoyo_execve *ee; | ||
733 | struct file *file; | ||
734 | case TOMOYO_SYMLINK_TARGET: | ||
735 | symlink = obj ? obj->symlink_target : NULL; | ||
736 | if (!symlink || | ||
737 | !tomoyo_compare_name_union(symlink, ptr) | ||
738 | == match) | ||
739 | goto out; | ||
740 | break; | ||
741 | case TOMOYO_EXEC_REALPATH: | ||
742 | ee = r->ee; | ||
743 | file = ee ? ee->bprm->file : NULL; | ||
744 | if (!tomoyo_scan_exec_realpath(file, ptr, | ||
745 | match)) | ||
746 | goto out; | ||
747 | break; | ||
748 | } | ||
749 | continue; | ||
750 | } | ||
751 | /* Check numeric or bit-op expressions. */ | ||
752 | for (j = 0; j < 2; j++) { | ||
753 | const u8 index = j ? right : left; | ||
754 | unsigned long value = 0; | ||
755 | switch (index) { | ||
756 | case TOMOYO_TASK_UID: | ||
757 | value = current_uid(); | ||
758 | break; | ||
759 | case TOMOYO_TASK_EUID: | ||
760 | value = current_euid(); | ||
761 | break; | ||
762 | case TOMOYO_TASK_SUID: | ||
763 | value = current_suid(); | ||
764 | break; | ||
765 | case TOMOYO_TASK_FSUID: | ||
766 | value = current_fsuid(); | ||
767 | break; | ||
768 | case TOMOYO_TASK_GID: | ||
769 | value = current_gid(); | ||
770 | break; | ||
771 | case TOMOYO_TASK_EGID: | ||
772 | value = current_egid(); | ||
773 | break; | ||
774 | case TOMOYO_TASK_SGID: | ||
775 | value = current_sgid(); | ||
776 | break; | ||
777 | case TOMOYO_TASK_FSGID: | ||
778 | value = current_fsgid(); | ||
779 | break; | ||
780 | case TOMOYO_TASK_PID: | ||
781 | value = tomoyo_sys_getpid(); | ||
782 | break; | ||
783 | case TOMOYO_TASK_PPID: | ||
784 | value = tomoyo_sys_getppid(); | ||
785 | break; | ||
786 | case TOMOYO_TYPE_IS_SOCKET: | ||
787 | value = S_IFSOCK; | ||
788 | break; | ||
789 | case TOMOYO_TYPE_IS_SYMLINK: | ||
790 | value = S_IFLNK; | ||
791 | break; | ||
792 | case TOMOYO_TYPE_IS_FILE: | ||
793 | value = S_IFREG; | ||
794 | break; | ||
795 | case TOMOYO_TYPE_IS_BLOCK_DEV: | ||
796 | value = S_IFBLK; | ||
797 | break; | ||
798 | case TOMOYO_TYPE_IS_DIRECTORY: | ||
799 | value = S_IFDIR; | ||
800 | break; | ||
801 | case TOMOYO_TYPE_IS_CHAR_DEV: | ||
802 | value = S_IFCHR; | ||
803 | break; | ||
804 | case TOMOYO_TYPE_IS_FIFO: | ||
805 | value = S_IFIFO; | ||
806 | break; | ||
807 | case TOMOYO_MODE_SETUID: | ||
808 | value = S_ISUID; | ||
809 | break; | ||
810 | case TOMOYO_MODE_SETGID: | ||
811 | value = S_ISGID; | ||
812 | break; | ||
813 | case TOMOYO_MODE_STICKY: | ||
814 | value = S_ISVTX; | ||
815 | break; | ||
816 | case TOMOYO_MODE_OWNER_READ: | ||
817 | value = S_IRUSR; | ||
818 | break; | ||
819 | case TOMOYO_MODE_OWNER_WRITE: | ||
820 | value = S_IWUSR; | ||
821 | break; | ||
822 | case TOMOYO_MODE_OWNER_EXECUTE: | ||
823 | value = S_IXUSR; | ||
824 | break; | ||
825 | case TOMOYO_MODE_GROUP_READ: | ||
826 | value = S_IRGRP; | ||
827 | break; | ||
828 | case TOMOYO_MODE_GROUP_WRITE: | ||
829 | value = S_IWGRP; | ||
830 | break; | ||
831 | case TOMOYO_MODE_GROUP_EXECUTE: | ||
832 | value = S_IXGRP; | ||
833 | break; | ||
834 | case TOMOYO_MODE_OTHERS_READ: | ||
835 | value = S_IROTH; | ||
836 | break; | ||
837 | case TOMOYO_MODE_OTHERS_WRITE: | ||
838 | value = S_IWOTH; | ||
839 | break; | ||
840 | case TOMOYO_MODE_OTHERS_EXECUTE: | ||
841 | value = S_IXOTH; | ||
842 | break; | ||
843 | case TOMOYO_EXEC_ARGC: | ||
844 | if (!bprm) | ||
845 | goto out; | ||
846 | value = bprm->argc; | ||
847 | break; | ||
848 | case TOMOYO_EXEC_ENVC: | ||
849 | if (!bprm) | ||
850 | goto out; | ||
851 | value = bprm->envc; | ||
852 | break; | ||
853 | case TOMOYO_NUMBER_UNION: | ||
854 | /* Fetch values later. */ | ||
855 | break; | ||
856 | default: | ||
857 | if (!obj) | ||
858 | goto out; | ||
859 | if (!obj->validate_done) { | ||
860 | tomoyo_get_attributes(obj); | ||
861 | obj->validate_done = true; | ||
862 | } | ||
863 | { | ||
864 | u8 stat_index; | ||
865 | struct tomoyo_mini_stat *stat; | ||
866 | switch (index) { | ||
867 | case TOMOYO_PATH1_UID: | ||
868 | case TOMOYO_PATH1_GID: | ||
869 | case TOMOYO_PATH1_INO: | ||
870 | case TOMOYO_PATH1_MAJOR: | ||
871 | case TOMOYO_PATH1_MINOR: | ||
872 | case TOMOYO_PATH1_TYPE: | ||
873 | case TOMOYO_PATH1_DEV_MAJOR: | ||
874 | case TOMOYO_PATH1_DEV_MINOR: | ||
875 | case TOMOYO_PATH1_PERM: | ||
876 | stat_index = TOMOYO_PATH1; | ||
877 | break; | ||
878 | case TOMOYO_PATH2_UID: | ||
879 | case TOMOYO_PATH2_GID: | ||
880 | case TOMOYO_PATH2_INO: | ||
881 | case TOMOYO_PATH2_MAJOR: | ||
882 | case TOMOYO_PATH2_MINOR: | ||
883 | case TOMOYO_PATH2_TYPE: | ||
884 | case TOMOYO_PATH2_DEV_MAJOR: | ||
885 | case TOMOYO_PATH2_DEV_MINOR: | ||
886 | case TOMOYO_PATH2_PERM: | ||
887 | stat_index = TOMOYO_PATH2; | ||
888 | break; | ||
889 | case TOMOYO_PATH1_PARENT_UID: | ||
890 | case TOMOYO_PATH1_PARENT_GID: | ||
891 | case TOMOYO_PATH1_PARENT_INO: | ||
892 | case TOMOYO_PATH1_PARENT_PERM: | ||
893 | stat_index = | ||
894 | TOMOYO_PATH1_PARENT; | ||
895 | break; | ||
896 | case TOMOYO_PATH2_PARENT_UID: | ||
897 | case TOMOYO_PATH2_PARENT_GID: | ||
898 | case TOMOYO_PATH2_PARENT_INO: | ||
899 | case TOMOYO_PATH2_PARENT_PERM: | ||
900 | stat_index = | ||
901 | TOMOYO_PATH2_PARENT; | ||
902 | break; | ||
903 | default: | ||
904 | goto out; | ||
905 | } | ||
906 | if (!obj->stat_valid[stat_index]) | ||
907 | goto out; | ||
908 | stat = &obj->stat[stat_index]; | ||
909 | switch (index) { | ||
910 | case TOMOYO_PATH1_UID: | ||
911 | case TOMOYO_PATH2_UID: | ||
912 | case TOMOYO_PATH1_PARENT_UID: | ||
913 | case TOMOYO_PATH2_PARENT_UID: | ||
914 | value = stat->uid; | ||
915 | break; | ||
916 | case TOMOYO_PATH1_GID: | ||
917 | case TOMOYO_PATH2_GID: | ||
918 | case TOMOYO_PATH1_PARENT_GID: | ||
919 | case TOMOYO_PATH2_PARENT_GID: | ||
920 | value = stat->gid; | ||
921 | break; | ||
922 | case TOMOYO_PATH1_INO: | ||
923 | case TOMOYO_PATH2_INO: | ||
924 | case TOMOYO_PATH1_PARENT_INO: | ||
925 | case TOMOYO_PATH2_PARENT_INO: | ||
926 | value = stat->ino; | ||
927 | break; | ||
928 | case TOMOYO_PATH1_MAJOR: | ||
929 | case TOMOYO_PATH2_MAJOR: | ||
930 | value = MAJOR(stat->dev); | ||
931 | break; | ||
932 | case TOMOYO_PATH1_MINOR: | ||
933 | case TOMOYO_PATH2_MINOR: | ||
934 | value = MINOR(stat->dev); | ||
935 | break; | ||
936 | case TOMOYO_PATH1_TYPE: | ||
937 | case TOMOYO_PATH2_TYPE: | ||
938 | value = stat->mode & S_IFMT; | ||
939 | break; | ||
940 | case TOMOYO_PATH1_DEV_MAJOR: | ||
941 | case TOMOYO_PATH2_DEV_MAJOR: | ||
942 | value = MAJOR(stat->rdev); | ||
943 | break; | ||
944 | case TOMOYO_PATH1_DEV_MINOR: | ||
945 | case TOMOYO_PATH2_DEV_MINOR: | ||
946 | value = MINOR(stat->rdev); | ||
947 | break; | ||
948 | case TOMOYO_PATH1_PERM: | ||
949 | case TOMOYO_PATH2_PERM: | ||
950 | case TOMOYO_PATH1_PARENT_PERM: | ||
951 | case TOMOYO_PATH2_PARENT_PERM: | ||
952 | value = stat->mode & S_IALLUGO; | ||
953 | break; | ||
954 | } | ||
955 | } | ||
956 | break; | ||
957 | } | ||
958 | max_v[j] = value; | ||
959 | min_v[j] = value; | ||
960 | switch (index) { | ||
961 | case TOMOYO_MODE_SETUID: | ||
962 | case TOMOYO_MODE_SETGID: | ||
963 | case TOMOYO_MODE_STICKY: | ||
964 | case TOMOYO_MODE_OWNER_READ: | ||
965 | case TOMOYO_MODE_OWNER_WRITE: | ||
966 | case TOMOYO_MODE_OWNER_EXECUTE: | ||
967 | case TOMOYO_MODE_GROUP_READ: | ||
968 | case TOMOYO_MODE_GROUP_WRITE: | ||
969 | case TOMOYO_MODE_GROUP_EXECUTE: | ||
970 | case TOMOYO_MODE_OTHERS_READ: | ||
971 | case TOMOYO_MODE_OTHERS_WRITE: | ||
972 | case TOMOYO_MODE_OTHERS_EXECUTE: | ||
973 | is_bitop[j] = true; | ||
974 | } | ||
975 | } | ||
976 | if (left == TOMOYO_NUMBER_UNION) { | ||
977 | /* Fetch values now. */ | ||
978 | const struct tomoyo_number_union *ptr = numbers_p++; | ||
979 | min_v[0] = ptr->values[0]; | ||
980 | max_v[0] = ptr->values[1]; | ||
981 | } | ||
982 | if (right == TOMOYO_NUMBER_UNION) { | ||
983 | /* Fetch values now. */ | ||
984 | const struct tomoyo_number_union *ptr = numbers_p++; | ||
985 | if (ptr->group) { | ||
986 | if (tomoyo_number_matches_group(min_v[0], | ||
987 | max_v[0], | ||
988 | ptr->group) | ||
989 | == match) | ||
990 | continue; | ||
991 | } else { | ||
992 | if ((min_v[0] <= ptr->values[1] && | ||
993 | max_v[0] >= ptr->values[0]) == match) | ||
994 | continue; | ||
995 | } | ||
996 | goto out; | ||
997 | } | ||
998 | /* | ||
999 | * Bit operation is valid only when counterpart value | ||
1000 | * represents permission. | ||
1001 | */ | ||
1002 | if (is_bitop[0] && is_bitop[1]) { | ||
1003 | goto out; | ||
1004 | } else if (is_bitop[0]) { | ||
1005 | switch (right) { | ||
1006 | case TOMOYO_PATH1_PERM: | ||
1007 | case TOMOYO_PATH1_PARENT_PERM: | ||
1008 | case TOMOYO_PATH2_PERM: | ||
1009 | case TOMOYO_PATH2_PARENT_PERM: | ||
1010 | if (!(max_v[0] & max_v[1]) == !match) | ||
1011 | continue; | ||
1012 | } | ||
1013 | goto out; | ||
1014 | } else if (is_bitop[1]) { | ||
1015 | switch (left) { | ||
1016 | case TOMOYO_PATH1_PERM: | ||
1017 | case TOMOYO_PATH1_PARENT_PERM: | ||
1018 | case TOMOYO_PATH2_PERM: | ||
1019 | case TOMOYO_PATH2_PARENT_PERM: | ||
1020 | if (!(max_v[0] & max_v[1]) == !match) | ||
1021 | continue; | ||
1022 | } | ||
1023 | goto out; | ||
1024 | } | ||
1025 | /* Normal value range comparison. */ | ||
1026 | if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match) | ||
1027 | continue; | ||
1028 | out: | ||
1029 | return false; | ||
1030 | } | ||
1031 | /* Check argv[] and envp[] now. */ | ||
1032 | if (r->ee && (argc || envc)) | ||
1033 | return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp); | ||
1034 | return true; | ||
1035 | } | ||