aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo/condition.c
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2011-07-08 00:24:54 -0400
committerJames Morris <jmorris@namei.org>2011-07-10 21:05:33 -0400
commit5b636857fee642694e287e3a181b523b16098c93 (patch)
tree24afcc11fc35350a29f5d6d73d376a551c5569b8 /security/tomoyo/condition.c
parent2ca9bf453bdd478bcb6c01aa2d0bd4c2f4350563 (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.c337
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 @@
11LIST_HEAD(tomoyo_condition_list); 11LIST_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 */
24static 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 */
57static 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 */
100static 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 }
181out:
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 */
287static 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 */
306static 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;
332out:
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,
702out: 1028out:
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}