diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2011-07-08 00:24:54 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2011-07-10 21:05:33 -0400 |
commit | 5b636857fee642694e287e3a181b523b16098c93 (patch) | |
tree | 24afcc11fc35350a29f5d6d73d376a551c5569b8 /security/tomoyo/condition.c | |
parent | 2ca9bf453bdd478bcb6c01aa2d0bd4c2f4350563 (diff) |
TOMOYO: Allow using argv[]/envp[] of execve() as conditions.
This patch adds support for permission checks using argv[]/envp[] of execve()
request. Hooks are in the last patch of this pathset.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/condition.c')
-rw-r--r-- | security/tomoyo/condition.c | 337 |
1 files changed, 333 insertions, 4 deletions
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index 790b9872cc37..8a05f71eaf67 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
@@ -11,6 +11,209 @@ | |||
11 | LIST_HEAD(tomoyo_condition_list); | 11 | LIST_HEAD(tomoyo_condition_list); |
12 | 12 | ||
13 | /** | 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 | /** | ||
14 | * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". | 217 | * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". |
15 | * | 218 | * |
16 | * @file: Pointer to "struct file". | 219 | * @file: Pointer to "struct file". |
@@ -73,6 +276,64 @@ static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, | |||
73 | } | 276 | } |
74 | 277 | ||
75 | /** | 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 | /** | ||
76 | * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. | 337 | * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. |
77 | * | 338 | * |
78 | * @a: Pointer to "struct tomoyo_condition". | 339 | * @a: Pointer to "struct tomoyo_condition". |
@@ -86,6 +347,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | |||
86 | return a->size == b->size && a->condc == b->condc && | 347 | return a->size == b->size && a->condc == b->condc && |
87 | a->numbers_count == b->numbers_count && | 348 | a->numbers_count == b->numbers_count && |
88 | a->names_count == b->names_count && | 349 | a->names_count == b->names_count && |
350 | a->argc == b->argc && a->envc == b->envc && | ||
89 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); | 351 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); |
90 | } | 352 | } |
91 | 353 | ||
@@ -178,6 +440,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | |||
178 | struct tomoyo_condition_element *condp = NULL; | 440 | struct tomoyo_condition_element *condp = NULL; |
179 | struct tomoyo_number_union *numbers_p = NULL; | 441 | struct tomoyo_number_union *numbers_p = NULL; |
180 | struct tomoyo_name_union *names_p = NULL; | 442 | struct tomoyo_name_union *names_p = NULL; |
443 | struct tomoyo_argv *argv = NULL; | ||
444 | struct tomoyo_envp *envp = NULL; | ||
181 | struct tomoyo_condition e = { }; | 445 | struct tomoyo_condition e = { }; |
182 | char * const start_of_string = param->data; | 446 | char * const start_of_string = param->data; |
183 | char * const end_of_string = start_of_string + strlen(start_of_string); | 447 | char * const end_of_string = start_of_string + strlen(start_of_string); |
@@ -222,6 +486,36 @@ rerun: | |||
222 | goto out; | 486 | goto out; |
223 | dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, | 487 | dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, |
224 | is_not ? "!" : "", right_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 | } | ||
225 | left = tomoyo_condition_type(left_word); | 519 | left = tomoyo_condition_type(left_word); |
226 | dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word, | 520 | dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word, |
227 | left); | 521 | left); |
@@ -283,16 +577,20 @@ store_value: | |||
283 | condp->equals); | 577 | condp->equals); |
284 | condp++; | 578 | condp++; |
285 | } | 579 | } |
286 | dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u\n", | 580 | dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n", |
287 | __LINE__, e.condc, e.numbers_count, e.names_count); | 581 | __LINE__, e.condc, e.numbers_count, e.names_count, e.argc, |
582 | e.envc); | ||
288 | if (entry) { | 583 | if (entry) { |
289 | BUG_ON(e.names_count | e.numbers_count | e.condc); | 584 | BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc | |
585 | e.condc); | ||
290 | return tomoyo_commit_condition(entry); | 586 | return tomoyo_commit_condition(entry); |
291 | } | 587 | } |
292 | e.size = sizeof(*entry) | 588 | e.size = sizeof(*entry) |
293 | + e.condc * sizeof(struct tomoyo_condition_element) | 589 | + e.condc * sizeof(struct tomoyo_condition_element) |
294 | + e.numbers_count * sizeof(struct tomoyo_number_union) | 590 | + e.numbers_count * sizeof(struct tomoyo_number_union) |
295 | + e.names_count * sizeof(struct tomoyo_name_union); | 591 | + e.names_count * sizeof(struct tomoyo_name_union) |
592 | + e.argc * sizeof(struct tomoyo_argv) | ||
593 | + e.envc * sizeof(struct tomoyo_envp); | ||
296 | entry = kzalloc(e.size, GFP_NOFS); | 594 | entry = kzalloc(e.size, GFP_NOFS); |
297 | if (!entry) | 595 | if (!entry) |
298 | return NULL; | 596 | return NULL; |
@@ -300,6 +598,8 @@ store_value: | |||
300 | condp = (struct tomoyo_condition_element *) (entry + 1); | 598 | condp = (struct tomoyo_condition_element *) (entry + 1); |
301 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); | 599 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); |
302 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); | 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); | ||
303 | { | 603 | { |
304 | bool flag = false; | 604 | bool flag = false; |
305 | for (pos = start_of_string; pos < end_of_string; pos++) { | 605 | for (pos = start_of_string; pos < end_of_string; pos++) { |
@@ -391,16 +691,29 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
391 | const struct tomoyo_condition_element *condp; | 691 | const struct tomoyo_condition_element *condp; |
392 | const struct tomoyo_number_union *numbers_p; | 692 | const struct tomoyo_number_union *numbers_p; |
393 | const struct tomoyo_name_union *names_p; | 693 | const struct tomoyo_name_union *names_p; |
694 | const struct tomoyo_argv *argv; | ||
695 | const struct tomoyo_envp *envp; | ||
394 | struct tomoyo_obj_info *obj; | 696 | struct tomoyo_obj_info *obj; |
395 | u16 condc; | 697 | u16 condc; |
698 | u16 argc; | ||
699 | u16 envc; | ||
700 | struct linux_binprm *bprm = NULL; | ||
396 | if (!cond) | 701 | if (!cond) |
397 | return true; | 702 | return true; |
398 | condc = cond->condc; | 703 | condc = cond->condc; |
704 | argc = cond->argc; | ||
705 | envc = cond->envc; | ||
399 | obj = r->obj; | 706 | obj = r->obj; |
707 | if (r->ee) | ||
708 | bprm = r->ee->bprm; | ||
709 | if (!bprm && (argc || envc)) | ||
710 | return false; | ||
400 | condp = (struct tomoyo_condition_element *) (cond + 1); | 711 | condp = (struct tomoyo_condition_element *) (cond + 1); |
401 | numbers_p = (const struct tomoyo_number_union *) (condp + condc); | 712 | numbers_p = (const struct tomoyo_number_union *) (condp + condc); |
402 | names_p = (const struct tomoyo_name_union *) | 713 | names_p = (const struct tomoyo_name_union *) |
403 | (numbers_p + cond->numbers_count); | 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); | ||
404 | for (i = 0; i < condc; i++) { | 717 | for (i = 0; i < condc; i++) { |
405 | const bool match = condp->equals; | 718 | const bool match = condp->equals; |
406 | const u8 left = condp->left; | 719 | const u8 left = condp->left; |
@@ -408,6 +721,9 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
408 | bool is_bitop[2] = { false, false }; | 721 | bool is_bitop[2] = { false, false }; |
409 | u8 j; | 722 | u8 j; |
410 | condp++; | 723 | condp++; |
724 | /* Check argv[] and envp[] later. */ | ||
725 | if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY) | ||
726 | continue; | ||
411 | /* Check string expressions. */ | 727 | /* Check string expressions. */ |
412 | if (right == TOMOYO_NAME_UNION) { | 728 | if (right == TOMOYO_NAME_UNION) { |
413 | const struct tomoyo_name_union *ptr = names_p++; | 729 | const struct tomoyo_name_union *ptr = names_p++; |
@@ -524,6 +840,16 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
524 | case TOMOYO_MODE_OTHERS_EXECUTE: | 840 | case TOMOYO_MODE_OTHERS_EXECUTE: |
525 | value = S_IXOTH; | 841 | value = S_IXOTH; |
526 | break; | 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; | ||
527 | case TOMOYO_NUMBER_UNION: | 853 | case TOMOYO_NUMBER_UNION: |
528 | /* Fetch values later. */ | 854 | /* Fetch values later. */ |
529 | break; | 855 | break; |
@@ -702,5 +1028,8 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
702 | out: | 1028 | out: |
703 | return false; | 1029 | return false; |
704 | } | 1030 | } |
1031 | /* Check argv[] and envp[] now. */ | ||
1032 | if (r->ee && (argc || envc)) | ||
1033 | return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp); | ||
705 | return true; | 1034 | return true; |
706 | } | 1035 | } |