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