TOMOYO: Allow using owner/group etc. of file objects as conditions.
[cascardo/linux.git] / security / tomoyo / condition.c
1 /*
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". */
11 LIST_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  */
21 static 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  */
37 static 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  */
66 static 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);
96 out:
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  */
112 struct 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;
121 rerun:
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;
237 out:
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 /**
247  * tomoyo_get_attributes - Revalidate "struct inode".
248  *
249  * @obj: Pointer to "struct tomoyo_obj_info".
250  *
251  * Returns nothing.
252  */
253 void 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 /**
295  * 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  */
304 bool 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;
312         struct tomoyo_obj_info *obj;
313         u16 condc;
314         if (!cond)
315                 return true;
316         condc = cond->condc;
317         obj = r->obj;
318         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;
324                 bool is_bitop[2] = { false, false };
325                 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;
362                         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;
419                         case TOMOYO_NUMBER_UNION:
420                                 /* Fetch values later. */
421                                 break;
422                         default:
423                                 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                                 }
522                                 break;
523                         }
524                         max_v[j] = value;
525                         min_v[j] = value;
526                         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                         }
541                 }
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                 }
564                 /*
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                 }
591                 /* Normal value range comparison. */
592                 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
593                         continue;
594 out:
595                 return false;
596         }
597         return true;
598 }