diff options
Diffstat (limited to 'security/tomoyo/condition.c')
-rw-r--r-- | security/tomoyo/condition.c | 116 |
1 files changed, 112 insertions, 4 deletions
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c index ac7ebeb47d7d..790b9872cc37 100644 --- a/security/tomoyo/condition.c +++ b/security/tomoyo/condition.c | |||
@@ -11,6 +11,68 @@ | |||
11 | LIST_HEAD(tomoyo_condition_list); | 11 | LIST_HEAD(tomoyo_condition_list); |
12 | 12 | ||
13 | /** | 13 | /** |
14 | * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". | ||
15 | * | ||
16 | * @file: Pointer to "struct file". | ||
17 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
18 | * @match: True if "exec.realpath=", false if "exec.realpath!=". | ||
19 | * | ||
20 | * Returns true on success, false otherwise. | ||
21 | */ | ||
22 | static bool tomoyo_scan_exec_realpath(struct file *file, | ||
23 | const struct tomoyo_name_union *ptr, | ||
24 | const bool match) | ||
25 | { | ||
26 | bool result; | ||
27 | struct tomoyo_path_info exe; | ||
28 | if (!file) | ||
29 | return false; | ||
30 | exe.name = tomoyo_realpath_from_path(&file->f_path); | ||
31 | if (!exe.name) | ||
32 | return false; | ||
33 | tomoyo_fill_path_info(&exe); | ||
34 | result = tomoyo_compare_name_union(&exe, ptr); | ||
35 | kfree(exe.name); | ||
36 | return result == match; | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * tomoyo_get_dqword - tomoyo_get_name() for a quoted string. | ||
41 | * | ||
42 | * @start: String to save. | ||
43 | * | ||
44 | * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. | ||
45 | */ | ||
46 | static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) | ||
47 | { | ||
48 | char *cp = start + strlen(start) - 1; | ||
49 | if (cp == start || *start++ != '"' || *cp != '"') | ||
50 | return NULL; | ||
51 | *cp = '\0'; | ||
52 | if (*start && !tomoyo_correct_word(start)) | ||
53 | return NULL; | ||
54 | return tomoyo_get_name(start); | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * tomoyo_parse_name_union_quoted - Parse a quoted word. | ||
59 | * | ||
60 | * @param: Pointer to "struct tomoyo_acl_param". | ||
61 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
62 | * | ||
63 | * Returns true on success, false otherwise. | ||
64 | */ | ||
65 | static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, | ||
66 | struct tomoyo_name_union *ptr) | ||
67 | { | ||
68 | char *filename = param->data; | ||
69 | if (*filename == '@') | ||
70 | return tomoyo_parse_name_union(param, ptr); | ||
71 | ptr->filename = tomoyo_get_dqword(filename); | ||
72 | return ptr->filename != NULL; | ||
73 | } | ||
74 | |||
75 | /** | ||
14 | * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. | 76 | * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. |
15 | * | 77 | * |
16 | * @a: Pointer to "struct tomoyo_condition". | 78 | * @a: Pointer to "struct tomoyo_condition". |
@@ -23,6 +85,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, | |||
23 | { | 85 | { |
24 | return a->size == b->size && a->condc == b->condc && | 86 | return a->size == b->size && a->condc == b->condc && |
25 | a->numbers_count == b->numbers_count && | 87 | a->numbers_count == b->numbers_count && |
88 | a->names_count == b->names_count && | ||
26 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); | 89 | !memcmp(a + 1, b + 1, a->size - sizeof(*a)); |
27 | } | 90 | } |
28 | 91 | ||
@@ -114,6 +177,7 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) | |||
114 | struct tomoyo_condition *entry = NULL; | 177 | struct tomoyo_condition *entry = NULL; |
115 | struct tomoyo_condition_element *condp = NULL; | 178 | struct tomoyo_condition_element *condp = NULL; |
116 | struct tomoyo_number_union *numbers_p = NULL; | 179 | struct tomoyo_number_union *numbers_p = NULL; |
180 | struct tomoyo_name_union *names_p = NULL; | ||
117 | struct tomoyo_condition e = { }; | 181 | struct tomoyo_condition e = { }; |
118 | char * const start_of_string = param->data; | 182 | char * const start_of_string = param->data; |
119 | char * const end_of_string = start_of_string + strlen(start_of_string); | 183 | char * const end_of_string = start_of_string + strlen(start_of_string); |
@@ -178,6 +242,20 @@ rerun: | |||
178 | e.condc++; | 242 | e.condc++; |
179 | else | 243 | else |
180 | e.condc--; | 244 | e.condc--; |
245 | if (left == TOMOYO_EXEC_REALPATH || | ||
246 | left == TOMOYO_SYMLINK_TARGET) { | ||
247 | if (!names_p) { | ||
248 | e.names_count++; | ||
249 | } else { | ||
250 | e.names_count--; | ||
251 | right = TOMOYO_NAME_UNION; | ||
252 | param->data = right_word; | ||
253 | if (!tomoyo_parse_name_union_quoted(param, | ||
254 | names_p++)) | ||
255 | goto out; | ||
256 | } | ||
257 | goto store_value; | ||
258 | } | ||
181 | right = tomoyo_condition_type(right_word); | 259 | right = tomoyo_condition_type(right_word); |
182 | if (right == TOMOYO_MAX_CONDITION_KEYWORD) { | 260 | if (right == TOMOYO_MAX_CONDITION_KEYWORD) { |
183 | if (!numbers_p) { | 261 | if (!numbers_p) { |
@@ -191,6 +269,7 @@ rerun: | |||
191 | goto out; | 269 | goto out; |
192 | } | 270 | } |
193 | } | 271 | } |
272 | store_value: | ||
194 | if (!condp) { | 273 | if (!condp) { |
195 | dprintk(KERN_WARNING "%u: dry_run left=%u right=%u " | 274 | dprintk(KERN_WARNING "%u: dry_run left=%u right=%u " |
196 | "match=%u\n", __LINE__, left, right, !is_not); | 275 | "match=%u\n", __LINE__, left, right, !is_not); |
@@ -204,21 +283,23 @@ rerun: | |||
204 | condp->equals); | 283 | condp->equals); |
205 | condp++; | 284 | condp++; |
206 | } | 285 | } |
207 | dprintk(KERN_INFO "%u: cond=%u numbers=%u\n", | 286 | dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u\n", |
208 | __LINE__, e.condc, e.numbers_count); | 287 | __LINE__, e.condc, e.numbers_count, e.names_count); |
209 | if (entry) { | 288 | if (entry) { |
210 | BUG_ON(e.numbers_count | e.condc); | 289 | BUG_ON(e.names_count | e.numbers_count | e.condc); |
211 | return tomoyo_commit_condition(entry); | 290 | return tomoyo_commit_condition(entry); |
212 | } | 291 | } |
213 | e.size = sizeof(*entry) | 292 | e.size = sizeof(*entry) |
214 | + e.condc * sizeof(struct tomoyo_condition_element) | 293 | + e.condc * sizeof(struct tomoyo_condition_element) |
215 | + e.numbers_count * sizeof(struct tomoyo_number_union); | 294 | + e.numbers_count * sizeof(struct tomoyo_number_union) |
295 | + e.names_count * sizeof(struct tomoyo_name_union); | ||
216 | entry = kzalloc(e.size, GFP_NOFS); | 296 | entry = kzalloc(e.size, GFP_NOFS); |
217 | if (!entry) | 297 | if (!entry) |
218 | return NULL; | 298 | return NULL; |
219 | *entry = e; | 299 | *entry = e; |
220 | condp = (struct tomoyo_condition_element *) (entry + 1); | 300 | condp = (struct tomoyo_condition_element *) (entry + 1); |
221 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); | 301 | numbers_p = (struct tomoyo_number_union *) (condp + e.condc); |
302 | names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); | ||
222 | { | 303 | { |
223 | bool flag = false; | 304 | bool flag = false; |
224 | for (pos = start_of_string; pos < end_of_string; pos++) { | 305 | for (pos = start_of_string; pos < end_of_string; pos++) { |
@@ -309,6 +390,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
309 | unsigned long max_v[2] = { 0, 0 }; | 390 | unsigned long max_v[2] = { 0, 0 }; |
310 | const struct tomoyo_condition_element *condp; | 391 | const struct tomoyo_condition_element *condp; |
311 | const struct tomoyo_number_union *numbers_p; | 392 | const struct tomoyo_number_union *numbers_p; |
393 | const struct tomoyo_name_union *names_p; | ||
312 | struct tomoyo_obj_info *obj; | 394 | struct tomoyo_obj_info *obj; |
313 | u16 condc; | 395 | u16 condc; |
314 | if (!cond) | 396 | if (!cond) |
@@ -317,6 +399,8 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
317 | obj = r->obj; | 399 | obj = r->obj; |
318 | condp = (struct tomoyo_condition_element *) (cond + 1); | 400 | condp = (struct tomoyo_condition_element *) (cond + 1); |
319 | numbers_p = (const struct tomoyo_number_union *) (condp + condc); | 401 | numbers_p = (const struct tomoyo_number_union *) (condp + condc); |
402 | names_p = (const struct tomoyo_name_union *) | ||
403 | (numbers_p + cond->numbers_count); | ||
320 | for (i = 0; i < condc; i++) { | 404 | for (i = 0; i < condc; i++) { |
321 | const bool match = condp->equals; | 405 | const bool match = condp->equals; |
322 | const u8 left = condp->left; | 406 | const u8 left = condp->left; |
@@ -324,6 +408,30 @@ bool tomoyo_condition(struct tomoyo_request_info *r, | |||
324 | bool is_bitop[2] = { false, false }; | 408 | bool is_bitop[2] = { false, false }; |
325 | u8 j; | 409 | u8 j; |
326 | condp++; | 410 | condp++; |
411 | /* Check string expressions. */ | ||
412 | if (right == TOMOYO_NAME_UNION) { | ||
413 | const struct tomoyo_name_union *ptr = names_p++; | ||
414 | switch (left) { | ||
415 | struct tomoyo_path_info *symlink; | ||
416 | struct tomoyo_execve *ee; | ||
417 | struct file *file; | ||
418 | case TOMOYO_SYMLINK_TARGET: | ||
419 | symlink = obj ? obj->symlink_target : NULL; | ||
420 | if (!symlink || | ||
421 | !tomoyo_compare_name_union(symlink, ptr) | ||
422 | == match) | ||
423 | goto out; | ||
424 | break; | ||
425 | case TOMOYO_EXEC_REALPATH: | ||
426 | ee = r->ee; | ||
427 | file = ee ? ee->bprm->file : NULL; | ||
428 | if (!tomoyo_scan_exec_realpath(file, ptr, | ||
429 | match)) | ||
430 | goto out; | ||
431 | break; | ||
432 | } | ||
433 | continue; | ||
434 | } | ||
327 | /* Check numeric or bit-op expressions. */ | 435 | /* Check numeric or bit-op expressions. */ |
328 | for (j = 0; j < 2; j++) { | 436 | for (j = 0; j < 2; j++) { |
329 | const u8 index = j ? right : left; | 437 | const u8 index = j ? right : left; |