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