blob: ac7ebeb47d7d2c59b6fc980b0bba642f0764f3b8 [file] [log] [blame]
Tetsuo Handa2066a362011-07-08 13:21:37 +09001/*
2 * security/tomoyo/condition.c
3 *
4 * Copyright (C) 2005-2011 NTT DATA CORPORATION
5 */
6
7#include "common.h"
8#include <linux/slab.h>
9
10/* List of "struct tomoyo_condition". */
11LIST_HEAD(tomoyo_condition_list);
12
13/**
14 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
15 *
16 * @a: Pointer to "struct tomoyo_condition".
17 * @b: Pointer to "struct tomoyo_condition".
18 *
19 * Returns true if @a == @b, false otherwise.
20 */
21static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
22 const struct tomoyo_condition *b)
23{
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));
27}
28
29/**
30 * tomoyo_condition_type - Get condition type.
31 *
32 * @word: Keyword string.
33 *
34 * Returns one of values in "enum tomoyo_conditions_index" on success,
35 * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
36 */
37static u8 tomoyo_condition_type(const char *word)
38{
39 u8 i;
40 for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
41 if (!strcmp(word, tomoyo_condition_keyword[i]))
42 break;
43 }
44 return i;
45}
46
47/* Define this to enable debug mode. */
48/* #define DEBUG_CONDITION */
49
50#ifdef DEBUG_CONDITION
51#define dprintk printk
52#else
53#define dprintk(...) do { } while (0)
54#endif
55
56/**
57 * tomoyo_commit_condition - Commit "struct tomoyo_condition".
58 *
59 * @entry: Pointer to "struct tomoyo_condition".
60 *
61 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
62 *
63 * This function merges duplicated entries. This function returns NULL if
64 * @entry is not duplicated but memory quota for policy has exceeded.
65 */
66static struct tomoyo_condition *tomoyo_commit_condition
67(struct tomoyo_condition *entry)
68{
69 struct tomoyo_condition *ptr;
70 bool found = false;
71 if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
72 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
73 ptr = NULL;
74 found = true;
75 goto out;
76 }
77 list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
78 if (!tomoyo_same_condition(ptr, entry))
79 continue;
80 /* Same entry found. Share this entry. */
81 atomic_inc(&ptr->head.users);
82 found = true;
83 break;
84 }
85 if (!found) {
86 if (tomoyo_memory_ok(entry)) {
87 atomic_set(&entry->head.users, 1);
88 list_add_rcu(&entry->head.list,
89 &tomoyo_condition_list);
90 } else {
91 found = true;
92 ptr = NULL;
93 }
94 }
95 mutex_unlock(&tomoyo_policy_lock);
96out:
97 if (found) {
98 tomoyo_del_condition(&entry->head.list);
99 kfree(entry);
100 entry = ptr;
101 }
102 return entry;
103}
104
105/**
106 * tomoyo_get_condition - Parse condition part.
107 *
108 * @param: Pointer to "struct tomoyo_acl_param".
109 *
110 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
111 */
112struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
113{
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);
120 char *pos;
121rerun:
122 pos = start_of_string;
123 while (1) {
124 u8 left = -1;
125 u8 right = -1;
126 char *left_word = pos;
127 char *cp;
128 char *right_word;
129 bool is_not;
130 if (!*left_word)
131 break;
132 /*
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'.
141 */
142 cp = strchr(pos, ' ');
143 if (cp) {
144 *cp = '\0'; /* Will restore later. */
145 pos = cp + 1;
146 } else {
147 pos = "";
148 }
149 right_word = strchr(left_word, '=');
150 if (!right_word || right_word == left_word)
151 goto out;
152 is_not = *(right_word - 1) == '!';
153 if (is_not)
154 *(right_word++ - 1) = '\0'; /* Will restore later. */
155 else if (*(right_word + 1) != '=')
156 *right_word++ = '\0'; /* Will restore later. */
157 else
158 goto out;
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,
163 left);
164 if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
165 if (!numbers_p) {
166 e.numbers_count++;
167 } else {
168 e.numbers_count--;
169 left = TOMOYO_NUMBER_UNION;
170 param->data = left_word;
171 if (*left_word == '@' ||
172 !tomoyo_parse_number_union(param,
173 numbers_p++))
174 goto out;
175 }
176 }
177 if (!condp)
178 e.condc++;
179 else
180 e.condc--;
181 right = tomoyo_condition_type(right_word);
182 if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
183 if (!numbers_p) {
184 e.numbers_count++;
185 } else {
186 e.numbers_count--;
187 right = TOMOYO_NUMBER_UNION;
188 param->data = right_word;
189 if (!tomoyo_parse_number_union(param,
190 numbers_p++))
191 goto out;
192 }
193 }
194 if (!condp) {
195 dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
196 "match=%u\n", __LINE__, left, right, !is_not);
197 continue;
198 }
199 condp->left = left;
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,
204 condp->equals);
205 condp++;
206 }
207 dprintk(KERN_INFO "%u: cond=%u numbers=%u\n",
208 __LINE__, e.condc, e.numbers_count);
209 if (entry) {
210 BUG_ON(e.numbers_count | e.condc);
211 return tomoyo_commit_condition(entry);
212 }
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);
217 if (!entry)
218 return NULL;
219 *entry = e;
220 condp = (struct tomoyo_condition_element *) (entry + 1);
221 numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
222 {
223 bool flag = false;
224 for (pos = start_of_string; pos < end_of_string; pos++) {
225 if (*pos)
226 continue;
227 if (flag) /* Restore " ". */
228 *pos = ' ';
229 else if (*(pos + 1) == '=') /* Restore "!=". */
230 *pos = '!';
231 else /* Restore "=". */
232 *pos = '=';
233 flag = !flag;
234 }
235 }
236 goto rerun;
237out:
238 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
239 if (entry) {
240 tomoyo_del_condition(&entry->head.list);
241 kfree(entry);
242 }
243 return NULL;
244}
245
246/**
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900247 * tomoyo_get_attributes - Revalidate "struct inode".
248 *
249 * @obj: Pointer to "struct tomoyo_obj_info".
250 *
251 * Returns nothing.
252 */
253void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
254{
255 u8 i;
256 struct dentry *dentry = NULL;
257
258 for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
259 struct inode *inode;
260 switch (i) {
261 case TOMOYO_PATH1:
262 dentry = obj->path1.dentry;
263 if (!dentry)
264 continue;
265 break;
266 case TOMOYO_PATH2:
267 dentry = obj->path2.dentry;
268 if (!dentry)
269 continue;
270 break;
271 default:
272 if (!dentry)
273 continue;
274 dentry = dget_parent(dentry);
275 break;
276 }
277 inode = dentry->d_inode;
278 if (inode) {
279 struct tomoyo_mini_stat *stat = &obj->stat[i];
280 stat->uid = inode->i_uid;
281 stat->gid = inode->i_gid;
282 stat->ino = inode->i_ino;
283 stat->mode = inode->i_mode;
284 stat->dev = inode->i_sb->s_dev;
285 stat->rdev = inode->i_rdev;
286 obj->stat_valid[i] = true;
287 }
288 if (i & 1) /* i == TOMOYO_PATH1_PARENT ||
289 i == TOMOYO_PATH2_PARENT */
290 dput(dentry);
291 }
292}
293
294/**
Tetsuo Handa2066a362011-07-08 13:21:37 +0900295 * tomoyo_condition - Check condition part.
296 *
297 * @r: Pointer to "struct tomoyo_request_info".
298 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
299 *
300 * Returns true on success, false otherwise.
301 *
302 * Caller holds tomoyo_read_lock().
303 */
304bool tomoyo_condition(struct tomoyo_request_info *r,
305 const struct tomoyo_condition *cond)
306{
307 u32 i;
308 unsigned long min_v[2] = { 0, 0 };
309 unsigned long max_v[2] = { 0, 0 };
310 const struct tomoyo_condition_element *condp;
311 const struct tomoyo_number_union *numbers_p;
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900312 struct tomoyo_obj_info *obj;
Tetsuo Handa2066a362011-07-08 13:21:37 +0900313 u16 condc;
314 if (!cond)
315 return true;
316 condc = cond->condc;
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900317 obj = r->obj;
Tetsuo Handa2066a362011-07-08 13:21:37 +0900318 condp = (struct tomoyo_condition_element *) (cond + 1);
319 numbers_p = (const struct tomoyo_number_union *) (condp + condc);
320 for (i = 0; i < condc; i++) {
321 const bool match = condp->equals;
322 const u8 left = condp->left;
323 const u8 right = condp->right;
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900324 bool is_bitop[2] = { false, false };
Tetsuo Handa2066a362011-07-08 13:21:37 +0900325 u8 j;
326 condp++;
327 /* Check numeric or bit-op expressions. */
328 for (j = 0; j < 2; j++) {
329 const u8 index = j ? right : left;
330 unsigned long value = 0;
331 switch (index) {
332 case TOMOYO_TASK_UID:
333 value = current_uid();
334 break;
335 case TOMOYO_TASK_EUID:
336 value = current_euid();
337 break;
338 case TOMOYO_TASK_SUID:
339 value = current_suid();
340 break;
341 case TOMOYO_TASK_FSUID:
342 value = current_fsuid();
343 break;
344 case TOMOYO_TASK_GID:
345 value = current_gid();
346 break;
347 case TOMOYO_TASK_EGID:
348 value = current_egid();
349 break;
350 case TOMOYO_TASK_SGID:
351 value = current_sgid();
352 break;
353 case TOMOYO_TASK_FSGID:
354 value = current_fsgid();
355 break;
356 case TOMOYO_TASK_PID:
357 value = tomoyo_sys_getpid();
358 break;
359 case TOMOYO_TASK_PPID:
360 value = tomoyo_sys_getppid();
361 break;
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900362 case TOMOYO_TYPE_IS_SOCKET:
363 value = S_IFSOCK;
364 break;
365 case TOMOYO_TYPE_IS_SYMLINK:
366 value = S_IFLNK;
367 break;
368 case TOMOYO_TYPE_IS_FILE:
369 value = S_IFREG;
370 break;
371 case TOMOYO_TYPE_IS_BLOCK_DEV:
372 value = S_IFBLK;
373 break;
374 case TOMOYO_TYPE_IS_DIRECTORY:
375 value = S_IFDIR;
376 break;
377 case TOMOYO_TYPE_IS_CHAR_DEV:
378 value = S_IFCHR;
379 break;
380 case TOMOYO_TYPE_IS_FIFO:
381 value = S_IFIFO;
382 break;
383 case TOMOYO_MODE_SETUID:
384 value = S_ISUID;
385 break;
386 case TOMOYO_MODE_SETGID:
387 value = S_ISGID;
388 break;
389 case TOMOYO_MODE_STICKY:
390 value = S_ISVTX;
391 break;
392 case TOMOYO_MODE_OWNER_READ:
393 value = S_IRUSR;
394 break;
395 case TOMOYO_MODE_OWNER_WRITE:
396 value = S_IWUSR;
397 break;
398 case TOMOYO_MODE_OWNER_EXECUTE:
399 value = S_IXUSR;
400 break;
401 case TOMOYO_MODE_GROUP_READ:
402 value = S_IRGRP;
403 break;
404 case TOMOYO_MODE_GROUP_WRITE:
405 value = S_IWGRP;
406 break;
407 case TOMOYO_MODE_GROUP_EXECUTE:
408 value = S_IXGRP;
409 break;
410 case TOMOYO_MODE_OTHERS_READ:
411 value = S_IROTH;
412 break;
413 case TOMOYO_MODE_OTHERS_WRITE:
414 value = S_IWOTH;
415 break;
416 case TOMOYO_MODE_OTHERS_EXECUTE:
417 value = S_IXOTH;
418 break;
Tetsuo Handa2066a362011-07-08 13:21:37 +0900419 case TOMOYO_NUMBER_UNION:
420 /* Fetch values later. */
421 break;
422 default:
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900423 if (!obj)
424 goto out;
425 if (!obj->validate_done) {
426 tomoyo_get_attributes(obj);
427 obj->validate_done = true;
428 }
429 {
430 u8 stat_index;
431 struct tomoyo_mini_stat *stat;
432 switch (index) {
433 case TOMOYO_PATH1_UID:
434 case TOMOYO_PATH1_GID:
435 case TOMOYO_PATH1_INO:
436 case TOMOYO_PATH1_MAJOR:
437 case TOMOYO_PATH1_MINOR:
438 case TOMOYO_PATH1_TYPE:
439 case TOMOYO_PATH1_DEV_MAJOR:
440 case TOMOYO_PATH1_DEV_MINOR:
441 case TOMOYO_PATH1_PERM:
442 stat_index = TOMOYO_PATH1;
443 break;
444 case TOMOYO_PATH2_UID:
445 case TOMOYO_PATH2_GID:
446 case TOMOYO_PATH2_INO:
447 case TOMOYO_PATH2_MAJOR:
448 case TOMOYO_PATH2_MINOR:
449 case TOMOYO_PATH2_TYPE:
450 case TOMOYO_PATH2_DEV_MAJOR:
451 case TOMOYO_PATH2_DEV_MINOR:
452 case TOMOYO_PATH2_PERM:
453 stat_index = TOMOYO_PATH2;
454 break;
455 case TOMOYO_PATH1_PARENT_UID:
456 case TOMOYO_PATH1_PARENT_GID:
457 case TOMOYO_PATH1_PARENT_INO:
458 case TOMOYO_PATH1_PARENT_PERM:
459 stat_index =
460 TOMOYO_PATH1_PARENT;
461 break;
462 case TOMOYO_PATH2_PARENT_UID:
463 case TOMOYO_PATH2_PARENT_GID:
464 case TOMOYO_PATH2_PARENT_INO:
465 case TOMOYO_PATH2_PARENT_PERM:
466 stat_index =
467 TOMOYO_PATH2_PARENT;
468 break;
469 default:
470 goto out;
471 }
472 if (!obj->stat_valid[stat_index])
473 goto out;
474 stat = &obj->stat[stat_index];
475 switch (index) {
476 case TOMOYO_PATH1_UID:
477 case TOMOYO_PATH2_UID:
478 case TOMOYO_PATH1_PARENT_UID:
479 case TOMOYO_PATH2_PARENT_UID:
480 value = stat->uid;
481 break;
482 case TOMOYO_PATH1_GID:
483 case TOMOYO_PATH2_GID:
484 case TOMOYO_PATH1_PARENT_GID:
485 case TOMOYO_PATH2_PARENT_GID:
486 value = stat->gid;
487 break;
488 case TOMOYO_PATH1_INO:
489 case TOMOYO_PATH2_INO:
490 case TOMOYO_PATH1_PARENT_INO:
491 case TOMOYO_PATH2_PARENT_INO:
492 value = stat->ino;
493 break;
494 case TOMOYO_PATH1_MAJOR:
495 case TOMOYO_PATH2_MAJOR:
496 value = MAJOR(stat->dev);
497 break;
498 case TOMOYO_PATH1_MINOR:
499 case TOMOYO_PATH2_MINOR:
500 value = MINOR(stat->dev);
501 break;
502 case TOMOYO_PATH1_TYPE:
503 case TOMOYO_PATH2_TYPE:
504 value = stat->mode & S_IFMT;
505 break;
506 case TOMOYO_PATH1_DEV_MAJOR:
507 case TOMOYO_PATH2_DEV_MAJOR:
508 value = MAJOR(stat->rdev);
509 break;
510 case TOMOYO_PATH1_DEV_MINOR:
511 case TOMOYO_PATH2_DEV_MINOR:
512 value = MINOR(stat->rdev);
513 break;
514 case TOMOYO_PATH1_PERM:
515 case TOMOYO_PATH2_PERM:
516 case TOMOYO_PATH1_PARENT_PERM:
517 case TOMOYO_PATH2_PARENT_PERM:
518 value = stat->mode & S_IALLUGO;
519 break;
520 }
521 }
Tetsuo Handa2066a362011-07-08 13:21:37 +0900522 break;
523 }
524 max_v[j] = value;
525 min_v[j] = value;
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900526 switch (index) {
527 case TOMOYO_MODE_SETUID:
528 case TOMOYO_MODE_SETGID:
529 case TOMOYO_MODE_STICKY:
530 case TOMOYO_MODE_OWNER_READ:
531 case TOMOYO_MODE_OWNER_WRITE:
532 case TOMOYO_MODE_OWNER_EXECUTE:
533 case TOMOYO_MODE_GROUP_READ:
534 case TOMOYO_MODE_GROUP_WRITE:
535 case TOMOYO_MODE_GROUP_EXECUTE:
536 case TOMOYO_MODE_OTHERS_READ:
537 case TOMOYO_MODE_OTHERS_WRITE:
538 case TOMOYO_MODE_OTHERS_EXECUTE:
539 is_bitop[j] = true;
540 }
Tetsuo Handa2066a362011-07-08 13:21:37 +0900541 }
542 if (left == TOMOYO_NUMBER_UNION) {
543 /* Fetch values now. */
544 const struct tomoyo_number_union *ptr = numbers_p++;
545 min_v[0] = ptr->values[0];
546 max_v[0] = ptr->values[1];
547 }
548 if (right == TOMOYO_NUMBER_UNION) {
549 /* Fetch values now. */
550 const struct tomoyo_number_union *ptr = numbers_p++;
551 if (ptr->group) {
552 if (tomoyo_number_matches_group(min_v[0],
553 max_v[0],
554 ptr->group)
555 == match)
556 continue;
557 } else {
558 if ((min_v[0] <= ptr->values[1] &&
559 max_v[0] >= ptr->values[0]) == match)
560 continue;
561 }
562 goto out;
563 }
Tetsuo Handa8761afd2011-07-08 13:22:41 +0900564 /*
565 * Bit operation is valid only when counterpart value
566 * represents permission.
567 */
568 if (is_bitop[0] && is_bitop[1]) {
569 goto out;
570 } else if (is_bitop[0]) {
571 switch (right) {
572 case TOMOYO_PATH1_PERM:
573 case TOMOYO_PATH1_PARENT_PERM:
574 case TOMOYO_PATH2_PERM:
575 case TOMOYO_PATH2_PARENT_PERM:
576 if (!(max_v[0] & max_v[1]) == !match)
577 continue;
578 }
579 goto out;
580 } else if (is_bitop[1]) {
581 switch (left) {
582 case TOMOYO_PATH1_PERM:
583 case TOMOYO_PATH1_PARENT_PERM:
584 case TOMOYO_PATH2_PERM:
585 case TOMOYO_PATH2_PARENT_PERM:
586 if (!(max_v[0] & max_v[1]) == !match)
587 continue;
588 }
589 goto out;
590 }
Tetsuo Handa2066a362011-07-08 13:21:37 +0900591 /* Normal value range comparison. */
592 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
593 continue;
594out:
595 return false;
596 }
597 return true;
598}