2 * security/tomoyo/condition.c
4 * Copyright (C) 2005-2011 NTT DATA CORPORATION
8 #include <linux/slab.h>
10 /* List of "struct tomoyo_condition". */
11 LIST_HEAD(tomoyo_condition_list);
14 * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
16 * @file: Pointer to "struct file".
17 * @ptr: Pointer to "struct tomoyo_name_union".
18 * @match: True if "exec.realpath=", false if "exec.realpath!=".
20 * Returns true on success, false otherwise.
22 static bool tomoyo_scan_exec_realpath(struct file *file,
23 const struct tomoyo_name_union *ptr,
27 struct tomoyo_path_info exe;
30 exe.name = tomoyo_realpath_from_path(&file->f_path);
33 tomoyo_fill_path_info(&exe);
34 result = tomoyo_compare_name_union(&exe, ptr);
36 return result == match;
40 * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
42 * @start: String to save.
44 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
46 static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
48 char *cp = start + strlen(start) - 1;
49 if (cp == start || *start++ != '"' || *cp != '"')
52 if (*start && !tomoyo_correct_word(start))
54 return tomoyo_get_name(start);
58 * tomoyo_parse_name_union_quoted - Parse a quoted word.
60 * @param: Pointer to "struct tomoyo_acl_param".
61 * @ptr: Pointer to "struct tomoyo_name_union".
63 * Returns true on success, false otherwise.
65 static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
66 struct tomoyo_name_union *ptr)
68 char *filename = param->data;
70 return tomoyo_parse_name_union(param, ptr);
71 ptr->filename = tomoyo_get_dqword(filename);
72 return ptr->filename != NULL;
76 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
78 * @a: Pointer to "struct tomoyo_condition".
79 * @b: Pointer to "struct tomoyo_condition".
81 * Returns true if @a == @b, false otherwise.
83 static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
84 const struct tomoyo_condition *b)
86 return a->size == b->size && a->condc == b->condc &&
87 a->numbers_count == b->numbers_count &&
88 a->names_count == b->names_count &&
89 !memcmp(a + 1, b + 1, a->size - sizeof(*a));
93 * tomoyo_condition_type - Get condition type.
95 * @word: Keyword string.
97 * Returns one of values in "enum tomoyo_conditions_index" on success,
98 * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
100 static u8 tomoyo_condition_type(const char *word)
103 for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
104 if (!strcmp(word, tomoyo_condition_keyword[i]))
110 /* Define this to enable debug mode. */
111 /* #define DEBUG_CONDITION */
113 #ifdef DEBUG_CONDITION
114 #define dprintk printk
116 #define dprintk(...) do { } while (0)
120 * tomoyo_commit_condition - Commit "struct tomoyo_condition".
122 * @entry: Pointer to "struct tomoyo_condition".
124 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
126 * This function merges duplicated entries. This function returns NULL if
127 * @entry is not duplicated but memory quota for policy has exceeded.
129 static struct tomoyo_condition *tomoyo_commit_condition
130 (struct tomoyo_condition *entry)
132 struct tomoyo_condition *ptr;
134 if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
135 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
140 list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
141 if (!tomoyo_same_condition(ptr, entry))
143 /* Same entry found. Share this entry. */
144 atomic_inc(&ptr->head.users);
149 if (tomoyo_memory_ok(entry)) {
150 atomic_set(&entry->head.users, 1);
151 list_add_rcu(&entry->head.list,
152 &tomoyo_condition_list);
158 mutex_unlock(&tomoyo_policy_lock);
161 tomoyo_del_condition(&entry->head.list);
169 * tomoyo_get_condition - Parse condition part.
171 * @param: Pointer to "struct tomoyo_acl_param".
173 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
175 struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
177 struct tomoyo_condition *entry = NULL;
178 struct tomoyo_condition_element *condp = NULL;
179 struct tomoyo_number_union *numbers_p = NULL;
180 struct tomoyo_name_union *names_p = NULL;
181 struct tomoyo_condition e = { };
182 char * const start_of_string = param->data;
183 char * const end_of_string = start_of_string + strlen(start_of_string);
186 pos = start_of_string;
190 char *left_word = pos;
197 * Since left-hand condition does not allow use of "path_group"
198 * or "number_group" and environment variable's names do not
199 * accept '=', it is guaranteed that the original line consists
200 * of one or more repetition of $left$operator$right blocks
201 * where "$left is free from '=' and ' '" and "$operator is
202 * either '=' or '!='" and "$right is free from ' '".
203 * Therefore, we can reconstruct the original line at the end
204 * of dry run even if we overwrite $operator with '\0'.
206 cp = strchr(pos, ' ');
208 *cp = '\0'; /* Will restore later. */
213 right_word = strchr(left_word, '=');
214 if (!right_word || right_word == left_word)
216 is_not = *(right_word - 1) == '!';
218 *(right_word++ - 1) = '\0'; /* Will restore later. */
219 else if (*(right_word + 1) != '=')
220 *right_word++ = '\0'; /* Will restore later. */
223 dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
224 is_not ? "!" : "", right_word);
225 left = tomoyo_condition_type(left_word);
226 dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
228 if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
233 left = TOMOYO_NUMBER_UNION;
234 param->data = left_word;
235 if (*left_word == '@' ||
236 !tomoyo_parse_number_union(param,
245 if (left == TOMOYO_EXEC_REALPATH ||
246 left == TOMOYO_SYMLINK_TARGET) {
251 right = TOMOYO_NAME_UNION;
252 param->data = right_word;
253 if (!tomoyo_parse_name_union_quoted(param,
259 right = tomoyo_condition_type(right_word);
260 if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
265 right = TOMOYO_NUMBER_UNION;
266 param->data = right_word;
267 if (!tomoyo_parse_number_union(param,
274 dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
275 "match=%u\n", __LINE__, left, right, !is_not);
279 condp->right = right;
280 condp->equals = !is_not;
281 dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
282 __LINE__, condp->left, condp->right,
286 dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u\n",
287 __LINE__, e.condc, e.numbers_count, e.names_count);
289 BUG_ON(e.names_count | e.numbers_count | e.condc);
290 return tomoyo_commit_condition(entry);
292 e.size = sizeof(*entry)
293 + e.condc * sizeof(struct tomoyo_condition_element)
294 + e.numbers_count * sizeof(struct tomoyo_number_union)
295 + e.names_count * sizeof(struct tomoyo_name_union);
296 entry = kzalloc(e.size, GFP_NOFS);
300 condp = (struct tomoyo_condition_element *) (entry + 1);
301 numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
302 names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
305 for (pos = start_of_string; pos < end_of_string; pos++) {
308 if (flag) /* Restore " ". */
310 else if (*(pos + 1) == '=') /* Restore "!=". */
312 else /* Restore "=". */
319 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
321 tomoyo_del_condition(&entry->head.list);
328 * tomoyo_get_attributes - Revalidate "struct inode".
330 * @obj: Pointer to "struct tomoyo_obj_info".
334 void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
337 struct dentry *dentry = NULL;
339 for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
343 dentry = obj->path1.dentry;
348 dentry = obj->path2.dentry;
355 dentry = dget_parent(dentry);
358 inode = dentry->d_inode;
360 struct tomoyo_mini_stat *stat = &obj->stat[i];
361 stat->uid = inode->i_uid;
362 stat->gid = inode->i_gid;
363 stat->ino = inode->i_ino;
364 stat->mode = inode->i_mode;
365 stat->dev = inode->i_sb->s_dev;
366 stat->rdev = inode->i_rdev;
367 obj->stat_valid[i] = true;
369 if (i & 1) /* i == TOMOYO_PATH1_PARENT ||
370 i == TOMOYO_PATH2_PARENT */
376 * tomoyo_condition - Check condition part.
378 * @r: Pointer to "struct tomoyo_request_info".
379 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
381 * Returns true on success, false otherwise.
383 * Caller holds tomoyo_read_lock().
385 bool tomoyo_condition(struct tomoyo_request_info *r,
386 const struct tomoyo_condition *cond)
389 unsigned long min_v[2] = { 0, 0 };
390 unsigned long max_v[2] = { 0, 0 };
391 const struct tomoyo_condition_element *condp;
392 const struct tomoyo_number_union *numbers_p;
393 const struct tomoyo_name_union *names_p;
394 struct tomoyo_obj_info *obj;
400 condp = (struct tomoyo_condition_element *) (cond + 1);
401 numbers_p = (const struct tomoyo_number_union *) (condp + condc);
402 names_p = (const struct tomoyo_name_union *)
403 (numbers_p + cond->numbers_count);
404 for (i = 0; i < condc; i++) {
405 const bool match = condp->equals;
406 const u8 left = condp->left;
407 const u8 right = condp->right;
408 bool is_bitop[2] = { false, false };
411 /* Check string expressions. */
412 if (right == TOMOYO_NAME_UNION) {
413 const struct tomoyo_name_union *ptr = names_p++;
415 struct tomoyo_path_info *symlink;
416 struct tomoyo_execve *ee;
418 case TOMOYO_SYMLINK_TARGET:
419 symlink = obj ? obj->symlink_target : NULL;
421 !tomoyo_compare_name_union(symlink, ptr)
425 case TOMOYO_EXEC_REALPATH:
427 file = ee ? ee->bprm->file : NULL;
428 if (!tomoyo_scan_exec_realpath(file, ptr,
435 /* Check numeric or bit-op expressions. */
436 for (j = 0; j < 2; j++) {
437 const u8 index = j ? right : left;
438 unsigned long value = 0;
440 case TOMOYO_TASK_UID:
441 value = current_uid();
443 case TOMOYO_TASK_EUID:
444 value = current_euid();
446 case TOMOYO_TASK_SUID:
447 value = current_suid();
449 case TOMOYO_TASK_FSUID:
450 value = current_fsuid();
452 case TOMOYO_TASK_GID:
453 value = current_gid();
455 case TOMOYO_TASK_EGID:
456 value = current_egid();
458 case TOMOYO_TASK_SGID:
459 value = current_sgid();
461 case TOMOYO_TASK_FSGID:
462 value = current_fsgid();
464 case TOMOYO_TASK_PID:
465 value = tomoyo_sys_getpid();
467 case TOMOYO_TASK_PPID:
468 value = tomoyo_sys_getppid();
470 case TOMOYO_TYPE_IS_SOCKET:
473 case TOMOYO_TYPE_IS_SYMLINK:
476 case TOMOYO_TYPE_IS_FILE:
479 case TOMOYO_TYPE_IS_BLOCK_DEV:
482 case TOMOYO_TYPE_IS_DIRECTORY:
485 case TOMOYO_TYPE_IS_CHAR_DEV:
488 case TOMOYO_TYPE_IS_FIFO:
491 case TOMOYO_MODE_SETUID:
494 case TOMOYO_MODE_SETGID:
497 case TOMOYO_MODE_STICKY:
500 case TOMOYO_MODE_OWNER_READ:
503 case TOMOYO_MODE_OWNER_WRITE:
506 case TOMOYO_MODE_OWNER_EXECUTE:
509 case TOMOYO_MODE_GROUP_READ:
512 case TOMOYO_MODE_GROUP_WRITE:
515 case TOMOYO_MODE_GROUP_EXECUTE:
518 case TOMOYO_MODE_OTHERS_READ:
521 case TOMOYO_MODE_OTHERS_WRITE:
524 case TOMOYO_MODE_OTHERS_EXECUTE:
527 case TOMOYO_NUMBER_UNION:
528 /* Fetch values later. */
533 if (!obj->validate_done) {
534 tomoyo_get_attributes(obj);
535 obj->validate_done = true;
539 struct tomoyo_mini_stat *stat;
541 case TOMOYO_PATH1_UID:
542 case TOMOYO_PATH1_GID:
543 case TOMOYO_PATH1_INO:
544 case TOMOYO_PATH1_MAJOR:
545 case TOMOYO_PATH1_MINOR:
546 case TOMOYO_PATH1_TYPE:
547 case TOMOYO_PATH1_DEV_MAJOR:
548 case TOMOYO_PATH1_DEV_MINOR:
549 case TOMOYO_PATH1_PERM:
550 stat_index = TOMOYO_PATH1;
552 case TOMOYO_PATH2_UID:
553 case TOMOYO_PATH2_GID:
554 case TOMOYO_PATH2_INO:
555 case TOMOYO_PATH2_MAJOR:
556 case TOMOYO_PATH2_MINOR:
557 case TOMOYO_PATH2_TYPE:
558 case TOMOYO_PATH2_DEV_MAJOR:
559 case TOMOYO_PATH2_DEV_MINOR:
560 case TOMOYO_PATH2_PERM:
561 stat_index = TOMOYO_PATH2;
563 case TOMOYO_PATH1_PARENT_UID:
564 case TOMOYO_PATH1_PARENT_GID:
565 case TOMOYO_PATH1_PARENT_INO:
566 case TOMOYO_PATH1_PARENT_PERM:
570 case TOMOYO_PATH2_PARENT_UID:
571 case TOMOYO_PATH2_PARENT_GID:
572 case TOMOYO_PATH2_PARENT_INO:
573 case TOMOYO_PATH2_PARENT_PERM:
580 if (!obj->stat_valid[stat_index])
582 stat = &obj->stat[stat_index];
584 case TOMOYO_PATH1_UID:
585 case TOMOYO_PATH2_UID:
586 case TOMOYO_PATH1_PARENT_UID:
587 case TOMOYO_PATH2_PARENT_UID:
590 case TOMOYO_PATH1_GID:
591 case TOMOYO_PATH2_GID:
592 case TOMOYO_PATH1_PARENT_GID:
593 case TOMOYO_PATH2_PARENT_GID:
596 case TOMOYO_PATH1_INO:
597 case TOMOYO_PATH2_INO:
598 case TOMOYO_PATH1_PARENT_INO:
599 case TOMOYO_PATH2_PARENT_INO:
602 case TOMOYO_PATH1_MAJOR:
603 case TOMOYO_PATH2_MAJOR:
604 value = MAJOR(stat->dev);
606 case TOMOYO_PATH1_MINOR:
607 case TOMOYO_PATH2_MINOR:
608 value = MINOR(stat->dev);
610 case TOMOYO_PATH1_TYPE:
611 case TOMOYO_PATH2_TYPE:
612 value = stat->mode & S_IFMT;
614 case TOMOYO_PATH1_DEV_MAJOR:
615 case TOMOYO_PATH2_DEV_MAJOR:
616 value = MAJOR(stat->rdev);
618 case TOMOYO_PATH1_DEV_MINOR:
619 case TOMOYO_PATH2_DEV_MINOR:
620 value = MINOR(stat->rdev);
622 case TOMOYO_PATH1_PERM:
623 case TOMOYO_PATH2_PERM:
624 case TOMOYO_PATH1_PARENT_PERM:
625 case TOMOYO_PATH2_PARENT_PERM:
626 value = stat->mode & S_IALLUGO;
635 case TOMOYO_MODE_SETUID:
636 case TOMOYO_MODE_SETGID:
637 case TOMOYO_MODE_STICKY:
638 case TOMOYO_MODE_OWNER_READ:
639 case TOMOYO_MODE_OWNER_WRITE:
640 case TOMOYO_MODE_OWNER_EXECUTE:
641 case TOMOYO_MODE_GROUP_READ:
642 case TOMOYO_MODE_GROUP_WRITE:
643 case TOMOYO_MODE_GROUP_EXECUTE:
644 case TOMOYO_MODE_OTHERS_READ:
645 case TOMOYO_MODE_OTHERS_WRITE:
646 case TOMOYO_MODE_OTHERS_EXECUTE:
650 if (left == TOMOYO_NUMBER_UNION) {
651 /* Fetch values now. */
652 const struct tomoyo_number_union *ptr = numbers_p++;
653 min_v[0] = ptr->values[0];
654 max_v[0] = ptr->values[1];
656 if (right == TOMOYO_NUMBER_UNION) {
657 /* Fetch values now. */
658 const struct tomoyo_number_union *ptr = numbers_p++;
660 if (tomoyo_number_matches_group(min_v[0],
666 if ((min_v[0] <= ptr->values[1] &&
667 max_v[0] >= ptr->values[0]) == match)
673 * Bit operation is valid only when counterpart value
674 * represents permission.
676 if (is_bitop[0] && is_bitop[1]) {
678 } else if (is_bitop[0]) {
680 case TOMOYO_PATH1_PERM:
681 case TOMOYO_PATH1_PARENT_PERM:
682 case TOMOYO_PATH2_PERM:
683 case TOMOYO_PATH2_PARENT_PERM:
684 if (!(max_v[0] & max_v[1]) == !match)
688 } else if (is_bitop[1]) {
690 case TOMOYO_PATH1_PERM:
691 case TOMOYO_PATH1_PARENT_PERM:
692 case TOMOYO_PATH2_PERM:
693 case TOMOYO_PATH2_PARENT_PERM:
694 if (!(max_v[0] & max_v[1]) == !match)
699 /* Normal value range comparison. */
700 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)