TOMOYO: Allow using UID/GID etc. of current thread as conditions.
[firefly-linux-kernel-4.4.55.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_condition - Check condition part.
248  *
249  * @r:    Pointer to "struct tomoyo_request_info".
250  * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
251  *
252  * Returns true on success, false otherwise.
253  *
254  * Caller holds tomoyo_read_lock().
255  */
256 bool tomoyo_condition(struct tomoyo_request_info *r,
257                       const struct tomoyo_condition *cond)
258 {
259         u32 i;
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;
264         u16 condc;
265         if (!cond)
266                 return true;
267         condc = cond->condc;
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;
274                 u8 j;
275                 condp++;
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;
280                         switch (index) {
281                         case TOMOYO_TASK_UID:
282                                 value = current_uid();
283                                 break;
284                         case TOMOYO_TASK_EUID:
285                                 value = current_euid();
286                                 break;
287                         case TOMOYO_TASK_SUID:
288                                 value = current_suid();
289                                 break;
290                         case TOMOYO_TASK_FSUID:
291                                 value = current_fsuid();
292                                 break;
293                         case TOMOYO_TASK_GID:
294                                 value = current_gid();
295                                 break;
296                         case TOMOYO_TASK_EGID:
297                                 value = current_egid();
298                                 break;
299                         case TOMOYO_TASK_SGID:
300                                 value = current_sgid();
301                                 break;
302                         case TOMOYO_TASK_FSGID:
303                                 value = current_fsgid();
304                                 break;
305                         case TOMOYO_TASK_PID:
306                                 value = tomoyo_sys_getpid();
307                                 break;
308                         case TOMOYO_TASK_PPID:
309                                 value = tomoyo_sys_getppid();
310                                 break;
311                         case TOMOYO_NUMBER_UNION:
312                                 /* Fetch values later. */
313                                 break;
314                         default:
315                                 break;
316                         }
317                         max_v[j] = value;
318                         min_v[j] = value;
319                 }
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];
325                 }
326                 if (right == TOMOYO_NUMBER_UNION) {
327                         /* Fetch values now. */
328                         const struct tomoyo_number_union *ptr = numbers_p++;
329                         if (ptr->group) {
330                                 if (tomoyo_number_matches_group(min_v[0],
331                                                                 max_v[0],
332                                                                 ptr->group)
333                                     == match)
334                                         continue;
335                         } else {
336                                 if ((min_v[0] <= ptr->values[1] &&
337                                      max_v[0] >= ptr->values[0]) == match)
338                                         continue;
339                         }
340                         goto out;
341                 }
342                 /* Normal value range comparison. */
343                 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
344                         continue;
345 out:
346                 return false;
347         }
348         return true;
349 }