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_same_condition - Check for duplicated "struct tomoyo_condition" entry.
16 * @a: Pointer to "struct tomoyo_condition".
17 * @b: Pointer to "struct tomoyo_condition".
19 * Returns true if @a == @b, false otherwise.
21 static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
22 const struct tomoyo_condition *b)
24 return a->size == b->size && a->condc == b->condc &&
25 a->numbers_count == b->numbers_count &&
26 !memcmp(a + 1, b + 1, a->size - sizeof(*a));
30 * tomoyo_condition_type - Get condition type.
32 * @word: Keyword string.
34 * Returns one of values in "enum tomoyo_conditions_index" on success,
35 * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
37 static u8 tomoyo_condition_type(const char *word)
40 for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
41 if (!strcmp(word, tomoyo_condition_keyword[i]))
47 /* Define this to enable debug mode. */
48 /* #define DEBUG_CONDITION */
50 #ifdef DEBUG_CONDITION
51 #define dprintk printk
53 #define dprintk(...) do { } while (0)
57 * tomoyo_commit_condition - Commit "struct tomoyo_condition".
59 * @entry: Pointer to "struct tomoyo_condition".
61 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
63 * This function merges duplicated entries. This function returns NULL if
64 * @entry is not duplicated but memory quota for policy has exceeded.
66 static struct tomoyo_condition *tomoyo_commit_condition
67 (struct tomoyo_condition *entry)
69 struct tomoyo_condition *ptr;
71 if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
72 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
77 list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
78 if (!tomoyo_same_condition(ptr, entry))
80 /* Same entry found. Share this entry. */
81 atomic_inc(&ptr->head.users);
86 if (tomoyo_memory_ok(entry)) {
87 atomic_set(&entry->head.users, 1);
88 list_add_rcu(&entry->head.list,
89 &tomoyo_condition_list);
95 mutex_unlock(&tomoyo_policy_lock);
98 tomoyo_del_condition(&entry->head.list);
106 * tomoyo_get_condition - Parse condition part.
108 * @param: Pointer to "struct tomoyo_acl_param".
110 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
112 struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
114 struct tomoyo_condition *entry = NULL;
115 struct tomoyo_condition_element *condp = NULL;
116 struct tomoyo_number_union *numbers_p = NULL;
117 struct tomoyo_condition e = { };
118 char * const start_of_string = param->data;
119 char * const end_of_string = start_of_string + strlen(start_of_string);
122 pos = start_of_string;
126 char *left_word = pos;
133 * Since left-hand condition does not allow use of "path_group"
134 * or "number_group" and environment variable's names do not
135 * accept '=', it is guaranteed that the original line consists
136 * of one or more repetition of $left$operator$right blocks
137 * where "$left is free from '=' and ' '" and "$operator is
138 * either '=' or '!='" and "$right is free from ' '".
139 * Therefore, we can reconstruct the original line at the end
140 * of dry run even if we overwrite $operator with '\0'.
142 cp = strchr(pos, ' ');
144 *cp = '\0'; /* Will restore later. */
149 right_word = strchr(left_word, '=');
150 if (!right_word || right_word == left_word)
152 is_not = *(right_word - 1) == '!';
154 *(right_word++ - 1) = '\0'; /* Will restore later. */
155 else if (*(right_word + 1) != '=')
156 *right_word++ = '\0'; /* Will restore later. */
159 dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
160 is_not ? "!" : "", right_word);
161 left = tomoyo_condition_type(left_word);
162 dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
164 if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
169 left = TOMOYO_NUMBER_UNION;
170 param->data = left_word;
171 if (*left_word == '@' ||
172 !tomoyo_parse_number_union(param,
181 right = tomoyo_condition_type(right_word);
182 if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
187 right = TOMOYO_NUMBER_UNION;
188 param->data = right_word;
189 if (!tomoyo_parse_number_union(param,
195 dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
196 "match=%u\n", __LINE__, left, right, !is_not);
200 condp->right = right;
201 condp->equals = !is_not;
202 dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
203 __LINE__, condp->left, condp->right,
207 dprintk(KERN_INFO "%u: cond=%u numbers=%u\n",
208 __LINE__, e.condc, e.numbers_count);
210 BUG_ON(e.numbers_count | e.condc);
211 return tomoyo_commit_condition(entry);
213 e.size = sizeof(*entry)
214 + e.condc * sizeof(struct tomoyo_condition_element)
215 + e.numbers_count * sizeof(struct tomoyo_number_union);
216 entry = kzalloc(e.size, GFP_NOFS);
220 condp = (struct tomoyo_condition_element *) (entry + 1);
221 numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
224 for (pos = start_of_string; pos < end_of_string; pos++) {
227 if (flag) /* Restore " ". */
229 else if (*(pos + 1) == '=') /* Restore "!=". */
231 else /* Restore "=". */
238 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
240 tomoyo_del_condition(&entry->head.list);
247 * tomoyo_condition - Check condition part.
249 * @r: Pointer to "struct tomoyo_request_info".
250 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
252 * Returns true on success, false otherwise.
254 * Caller holds tomoyo_read_lock().
256 bool tomoyo_condition(struct tomoyo_request_info *r,
257 const struct tomoyo_condition *cond)
260 unsigned long min_v[2] = { 0, 0 };
261 unsigned long max_v[2] = { 0, 0 };
262 const struct tomoyo_condition_element *condp;
263 const struct tomoyo_number_union *numbers_p;
268 condp = (struct tomoyo_condition_element *) (cond + 1);
269 numbers_p = (const struct tomoyo_number_union *) (condp + condc);
270 for (i = 0; i < condc; i++) {
271 const bool match = condp->equals;
272 const u8 left = condp->left;
273 const u8 right = condp->right;
276 /* Check numeric or bit-op expressions. */
277 for (j = 0; j < 2; j++) {
278 const u8 index = j ? right : left;
279 unsigned long value = 0;
281 case TOMOYO_TASK_UID:
282 value = current_uid();
284 case TOMOYO_TASK_EUID:
285 value = current_euid();
287 case TOMOYO_TASK_SUID:
288 value = current_suid();
290 case TOMOYO_TASK_FSUID:
291 value = current_fsuid();
293 case TOMOYO_TASK_GID:
294 value = current_gid();
296 case TOMOYO_TASK_EGID:
297 value = current_egid();
299 case TOMOYO_TASK_SGID:
300 value = current_sgid();
302 case TOMOYO_TASK_FSGID:
303 value = current_fsgid();
305 case TOMOYO_TASK_PID:
306 value = tomoyo_sys_getpid();
308 case TOMOYO_TASK_PPID:
309 value = tomoyo_sys_getppid();
311 case TOMOYO_NUMBER_UNION:
312 /* Fetch values later. */
320 if (left == TOMOYO_NUMBER_UNION) {
321 /* Fetch values now. */
322 const struct tomoyo_number_union *ptr = numbers_p++;
323 min_v[0] = ptr->values[0];
324 max_v[0] = ptr->values[1];
326 if (right == TOMOYO_NUMBER_UNION) {
327 /* Fetch values now. */
328 const struct tomoyo_number_union *ptr = numbers_p++;
330 if (tomoyo_number_matches_group(min_v[0],
336 if ((min_v[0] <= ptr->values[1] &&
337 max_v[0] >= ptr->values[0]) == match)
342 /* Normal value range comparison. */
343 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)