~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/tomoyo/domain.c

Version: ~ [ linux-5.3-rc4 ] ~ [ linux-5.2.8 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.66 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.138 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.71 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * security/tomoyo/domain.c
  3  *
  4  * Copyright (C) 2005-2011  NTT DATA CORPORATION
  5  */
  6 
  7 #include "common.h"
  8 #include <linux/binfmts.h>
  9 #include <linux/slab.h>
 10 
 11 /* Variables definitions.*/
 12 
 13 /* The initial domain. */
 14 struct tomoyo_domain_info tomoyo_kernel_domain;
 15 
 16 /**
 17  * tomoyo_update_policy - Update an entry for exception policy.
 18  *
 19  * @new_entry:       Pointer to "struct tomoyo_acl_info".
 20  * @size:            Size of @new_entry in bytes.
 21  * @param:           Pointer to "struct tomoyo_acl_param".
 22  * @check_duplicate: Callback function to find duplicated entry.
 23  *
 24  * Returns 0 on success, negative value otherwise.
 25  *
 26  * Caller holds tomoyo_read_lock().
 27  */
 28 int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
 29                          struct tomoyo_acl_param *param,
 30                          bool (*check_duplicate) (const struct tomoyo_acl_head
 31                                                   *,
 32                                                   const struct tomoyo_acl_head
 33                                                   *))
 34 {
 35         int error = param->is_delete ? -ENOENT : -ENOMEM;
 36         struct tomoyo_acl_head *entry;
 37         struct list_head *list = param->list;
 38 
 39         if (mutex_lock_interruptible(&tomoyo_policy_lock))
 40                 return -ENOMEM;
 41         list_for_each_entry_rcu(entry, list, list) {
 42                 if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
 43                         continue;
 44                 if (!check_duplicate(entry, new_entry))
 45                         continue;
 46                 entry->is_deleted = param->is_delete;
 47                 error = 0;
 48                 break;
 49         }
 50         if (error && !param->is_delete) {
 51                 entry = tomoyo_commit_ok(new_entry, size);
 52                 if (entry) {
 53                         list_add_tail_rcu(&entry->list, list);
 54                         error = 0;
 55                 }
 56         }
 57         mutex_unlock(&tomoyo_policy_lock);
 58         return error;
 59 }
 60 
 61 /**
 62  * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
 63  *
 64  * @a: Pointer to "struct tomoyo_acl_info".
 65  * @b: Pointer to "struct tomoyo_acl_info".
 66  *
 67  * Returns true if @a == @b, false otherwise.
 68  */
 69 static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
 70                                         const struct tomoyo_acl_info *b)
 71 {
 72         return a->type == b->type && a->cond == b->cond;
 73 }
 74 
 75 /**
 76  * tomoyo_update_domain - Update an entry for domain policy.
 77  *
 78  * @new_entry:       Pointer to "struct tomoyo_acl_info".
 79  * @size:            Size of @new_entry in bytes.
 80  * @param:           Pointer to "struct tomoyo_acl_param".
 81  * @check_duplicate: Callback function to find duplicated entry.
 82  * @merge_duplicate: Callback function to merge duplicated entry.
 83  *
 84  * Returns 0 on success, negative value otherwise.
 85  *
 86  * Caller holds tomoyo_read_lock().
 87  */
 88 int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
 89                          struct tomoyo_acl_param *param,
 90                          bool (*check_duplicate) (const struct tomoyo_acl_info
 91                                                   *,
 92                                                   const struct tomoyo_acl_info
 93                                                   *),
 94                          bool (*merge_duplicate) (struct tomoyo_acl_info *,
 95                                                   struct tomoyo_acl_info *,
 96                                                   const bool))
 97 {
 98         const bool is_delete = param->is_delete;
 99         int error = is_delete ? -ENOENT : -ENOMEM;
100         struct tomoyo_acl_info *entry;
101         struct list_head * const list = param->list;
102 
103         if (param->data[0]) {
104                 new_entry->cond = tomoyo_get_condition(param);
105                 if (!new_entry->cond)
106                         return -EINVAL;
107                 /*
108                  * Domain transition preference is allowed for only
109                  * "file execute" entries.
110                  */
111                 if (new_entry->cond->transit &&
112                     !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
113                       container_of(new_entry, struct tomoyo_path_acl, head)
114                       ->perm == 1 << TOMOYO_TYPE_EXECUTE))
115                         goto out;
116         }
117         if (mutex_lock_interruptible(&tomoyo_policy_lock))
118                 goto out;
119         list_for_each_entry_rcu(entry, list, list) {
120                 if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
121                         continue;
122                 if (!tomoyo_same_acl_head(entry, new_entry) ||
123                     !check_duplicate(entry, new_entry))
124                         continue;
125                 if (merge_duplicate)
126                         entry->is_deleted = merge_duplicate(entry, new_entry,
127                                                             is_delete);
128                 else
129                         entry->is_deleted = is_delete;
130                 error = 0;
131                 break;
132         }
133         if (error && !is_delete) {
134                 entry = tomoyo_commit_ok(new_entry, size);
135                 if (entry) {
136                         list_add_tail_rcu(&entry->list, list);
137                         error = 0;
138                 }
139         }
140         mutex_unlock(&tomoyo_policy_lock);
141 out:
142         tomoyo_put_condition(new_entry->cond);
143         return error;
144 }
145 
146 /**
147  * tomoyo_check_acl - Do permission check.
148  *
149  * @r:           Pointer to "struct tomoyo_request_info".
150  * @check_entry: Callback function to check type specific parameters.
151  *
152  * Returns 0 on success, negative value otherwise.
153  *
154  * Caller holds tomoyo_read_lock().
155  */
156 void tomoyo_check_acl(struct tomoyo_request_info *r,
157                       bool (*check_entry) (struct tomoyo_request_info *,
158                                            const struct tomoyo_acl_info *))
159 {
160         const struct tomoyo_domain_info *domain = r->domain;
161         struct tomoyo_acl_info *ptr;
162         bool retried = false;
163         const struct list_head *list = &domain->acl_info_list;
164 
165 retry:
166         list_for_each_entry_rcu(ptr, list, list) {
167                 if (ptr->is_deleted || ptr->type != r->param_type)
168                         continue;
169                 if (!check_entry(r, ptr))
170                         continue;
171                 if (!tomoyo_condition(r, ptr->cond))
172                         continue;
173                 r->matched_acl = ptr;
174                 r->granted = true;
175                 return;
176         }
177         if (!retried) {
178                 retried = true;
179                 list = &domain->ns->acl_group[domain->group];
180                 goto retry;
181         }
182         r->granted = false;
183 }
184 
185 /* The list for "struct tomoyo_domain_info". */
186 LIST_HEAD(tomoyo_domain_list);
187 
188 /**
189  * tomoyo_last_word - Get last component of a domainname.
190  *
191  * @name: Domainname to check.
192  *
193  * Returns the last word of @domainname.
194  */
195 static const char *tomoyo_last_word(const char *name)
196 {
197         const char *cp = strrchr(name, ' ');
198         if (cp)
199                 return cp + 1;
200         return name;
201 }
202 
203 /**
204  * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
205  *
206  * @a: Pointer to "struct tomoyo_acl_head".
207  * @b: Pointer to "struct tomoyo_acl_head".
208  *
209  * Returns true if @a == @b, false otherwise.
210  */
211 static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
212                                            const struct tomoyo_acl_head *b)
213 {
214         const struct tomoyo_transition_control *p1 = container_of(a,
215                                                                   typeof(*p1),
216                                                                   head);
217         const struct tomoyo_transition_control *p2 = container_of(b,
218                                                                   typeof(*p2),
219                                                                   head);
220         return p1->type == p2->type && p1->is_last_name == p2->is_last_name
221                 && p1->domainname == p2->domainname
222                 && p1->program == p2->program;
223 }
224 
225 /**
226  * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
227  *
228  * @param: Pointer to "struct tomoyo_acl_param".
229  * @type:  Type of this entry.
230  *
231  * Returns 0 on success, negative value otherwise.
232  */
233 int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
234                                     const u8 type)
235 {
236         struct tomoyo_transition_control e = { .type = type };
237         int error = param->is_delete ? -ENOENT : -ENOMEM;
238         char *program = param->data;
239         char *domainname = strstr(program, " from ");
240         if (domainname) {
241                 *domainname = '\0';
242                 domainname += 6;
243         } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
244                    type == TOMOYO_TRANSITION_CONTROL_KEEP) {
245                 domainname = program;
246                 program = NULL;
247         }
248         if (program && strcmp(program, "any")) {
249                 if (!tomoyo_correct_path(program))
250                         return -EINVAL;
251                 e.program = tomoyo_get_name(program);
252                 if (!e.program)
253                         goto out;
254         }
255         if (domainname && strcmp(domainname, "any")) {
256                 if (!tomoyo_correct_domain(domainname)) {
257                         if (!tomoyo_correct_path(domainname))
258                                 goto out;
259                         e.is_last_name = true;
260                 }
261                 e.domainname = tomoyo_get_name(domainname);
262                 if (!e.domainname)
263                         goto out;
264         }
265         param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
266         error = tomoyo_update_policy(&e.head, sizeof(e), param,
267                                      tomoyo_same_transition_control);
268 out:
269         tomoyo_put_name(e.domainname);
270         tomoyo_put_name(e.program);
271         return error;
272 }
273 
274 /**
275  * tomoyo_scan_transition - Try to find specific domain transition type.
276  *
277  * @list:       Pointer to "struct list_head".
278  * @domainname: The name of current domain.
279  * @program:    The name of requested program.
280  * @last_name:  The last component of @domainname.
281  * @type:       One of values in "enum tomoyo_transition_type".
282  *
283  * Returns true if found one, false otherwise.
284  *
285  * Caller holds tomoyo_read_lock().
286  */
287 static inline bool tomoyo_scan_transition
288 (const struct list_head *list, const struct tomoyo_path_info *domainname,
289  const struct tomoyo_path_info *program, const char *last_name,
290  const enum tomoyo_transition_type type)
291 {
292         const struct tomoyo_transition_control *ptr;
293         list_for_each_entry_rcu(ptr, list, head.list) {
294                 if (ptr->head.is_deleted || ptr->type != type)
295                         continue;
296                 if (ptr->domainname) {
297                         if (!ptr->is_last_name) {
298                                 if (ptr->domainname != domainname)
299                                         continue;
300                         } else {
301                                 /*
302                                  * Use direct strcmp() since this is
303                                  * unlikely used.
304                                  */
305                                 if (strcmp(ptr->domainname->name, last_name))
306                                         continue;
307                         }
308                 }
309                 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
310                         continue;
311                 return true;
312         }
313         return false;
314 }
315 
316 /**
317  * tomoyo_transition_type - Get domain transition type.
318  *
319  * @ns:         Pointer to "struct tomoyo_policy_namespace".
320  * @domainname: The name of current domain.
321  * @program:    The name of requested program.
322  *
323  * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
324  * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
325  * executing @program reinitializes domain transition within that namespace,
326  * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
327  * others otherwise.
328  *
329  * Caller holds tomoyo_read_lock().
330  */
331 static enum tomoyo_transition_type tomoyo_transition_type
332 (const struct tomoyo_policy_namespace *ns,
333  const struct tomoyo_path_info *domainname,
334  const struct tomoyo_path_info *program)
335 {
336         const char *last_name = tomoyo_last_word(domainname->name);
337         enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
338         while (type < TOMOYO_MAX_TRANSITION_TYPE) {
339                 const struct list_head * const list =
340                         &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
341                 if (!tomoyo_scan_transition(list, domainname, program,
342                                             last_name, type)) {
343                         type++;
344                         continue;
345                 }
346                 if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
347                     type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
348                         break;
349                 /*
350                  * Do not check for reset_domain if no_reset_domain matched.
351                  * Do not check for initialize_domain if no_initialize_domain
352                  * matched.
353                  */
354                 type++;
355                 type++;
356         }
357         return type;
358 }
359 
360 /**
361  * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
362  *
363  * @a: Pointer to "struct tomoyo_acl_head".
364  * @b: Pointer to "struct tomoyo_acl_head".
365  *
366  * Returns true if @a == @b, false otherwise.
367  */
368 static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
369                                    const struct tomoyo_acl_head *b)
370 {
371         const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
372                                                           head);
373         const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
374                                                           head);
375         return p1->original_name == p2->original_name &&
376                 p1->aggregated_name == p2->aggregated_name;
377 }
378 
379 /**
380  * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
381  *
382  * @param: Pointer to "struct tomoyo_acl_param".
383  *
384  * Returns 0 on success, negative value otherwise.
385  *
386  * Caller holds tomoyo_read_lock().
387  */
388 int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
389 {
390         struct tomoyo_aggregator e = { };
391         int error = param->is_delete ? -ENOENT : -ENOMEM;
392         const char *original_name = tomoyo_read_token(param);
393         const char *aggregated_name = tomoyo_read_token(param);
394         if (!tomoyo_correct_word(original_name) ||
395             !tomoyo_correct_path(aggregated_name))
396                 return -EINVAL;
397         e.original_name = tomoyo_get_name(original_name);
398         e.aggregated_name = tomoyo_get_name(aggregated_name);
399         if (!e.original_name || !e.aggregated_name ||
400             e.aggregated_name->is_patterned) /* No patterns allowed. */
401                 goto out;
402         param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
403         error = tomoyo_update_policy(&e.head, sizeof(e), param,
404                                      tomoyo_same_aggregator);
405 out:
406         tomoyo_put_name(e.original_name);
407         tomoyo_put_name(e.aggregated_name);
408         return error;
409 }
410 
411 /**
412  * tomoyo_find_namespace - Find specified namespace.
413  *
414  * @name: Name of namespace to find.
415  * @len:  Length of @name.
416  *
417  * Returns pointer to "struct tomoyo_policy_namespace" if found,
418  * NULL otherwise.
419  *
420  * Caller holds tomoyo_read_lock().
421  */
422 static struct tomoyo_policy_namespace *tomoyo_find_namespace
423 (const char *name, const unsigned int len)
424 {
425         struct tomoyo_policy_namespace *ns;
426         list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
427                 if (strncmp(name, ns->name, len) ||
428                     (name[len] && name[len] != ' '))
429                         continue;
430                 return ns;
431         }
432         return NULL;
433 }
434 
435 /**
436  * tomoyo_assign_namespace - Create a new namespace.
437  *
438  * @domainname: Name of namespace to create.
439  *
440  * Returns pointer to "struct tomoyo_policy_namespace" on success,
441  * NULL otherwise.
442  *
443  * Caller holds tomoyo_read_lock().
444  */
445 struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
446 {
447         struct tomoyo_policy_namespace *ptr;
448         struct tomoyo_policy_namespace *entry;
449         const char *cp = domainname;
450         unsigned int len = 0;
451         while (*cp && *cp++ != ' ')
452                 len++;
453         ptr = tomoyo_find_namespace(domainname, len);
454         if (ptr)
455                 return ptr;
456         if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
457                 return NULL;
458         entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
459         if (!entry)
460                 return NULL;
461         if (mutex_lock_interruptible(&tomoyo_policy_lock))
462                 goto out;
463         ptr = tomoyo_find_namespace(domainname, len);
464         if (!ptr && tomoyo_memory_ok(entry)) {
465                 char *name = (char *) (entry + 1);
466                 ptr = entry;
467                 memmove(name, domainname, len);
468                 name[len] = '\0';
469                 entry->name = name;
470                 tomoyo_init_policy_namespace(entry);
471                 entry = NULL;
472         }
473         mutex_unlock(&tomoyo_policy_lock);
474 out:
475         kfree(entry);
476         return ptr;
477 }
478 
479 /**
480  * tomoyo_namespace_jump - Check for namespace jump.
481  *
482  * @domainname: Name of domain.
483  *
484  * Returns true if namespace differs, false otherwise.
485  */
486 static bool tomoyo_namespace_jump(const char *domainname)
487 {
488         const char *namespace = tomoyo_current_namespace()->name;
489         const int len = strlen(namespace);
490         return strncmp(domainname, namespace, len) ||
491                 (domainname[len] && domainname[len] != ' ');
492 }
493 
494 /**
495  * tomoyo_assign_domain - Create a domain or a namespace.
496  *
497  * @domainname: The name of domain.
498  * @transit:    True if transit to domain found or created.
499  *
500  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
501  *
502  * Caller holds tomoyo_read_lock().
503  */
504 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
505                                                 const bool transit)
506 {
507         struct tomoyo_domain_info e = { };
508         struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
509         bool created = false;
510         if (entry) {
511                 if (transit) {
512                         /*
513                          * Since namespace is created at runtime, profiles may
514                          * not be created by the moment the process transits to
515                          * that domain. Do not perform domain transition if
516                          * profile for that domain is not yet created.
517                          */
518                         if (tomoyo_policy_loaded &&
519                             !entry->ns->profile_ptr[entry->profile])
520                                 return NULL;
521                 }
522                 return entry;
523         }
524         /* Requested domain does not exist. */
525         /* Don't create requested domain if domainname is invalid. */
526         if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
527             !tomoyo_correct_domain(domainname))
528                 return NULL;
529         /*
530          * Since definition of profiles and acl_groups may differ across
531          * namespaces, do not inherit "use_profile" and "use_group" settings
532          * by automatically creating requested domain upon domain transition.
533          */
534         if (transit && tomoyo_namespace_jump(domainname))
535                 return NULL;
536         e.ns = tomoyo_assign_namespace(domainname);
537         if (!e.ns)
538                 return NULL;
539         /*
540          * "use_profile" and "use_group" settings for automatically created
541          * domains are inherited from current domain. These are 0 for manually
542          * created domains.
543          */
544         if (transit) {
545                 const struct tomoyo_domain_info *domain = tomoyo_domain();
546                 e.profile = domain->profile;
547                 e.group = domain->group;
548         }
549         e.domainname = tomoyo_get_name(domainname);
550         if (!e.domainname)
551                 return NULL;
552         if (mutex_lock_interruptible(&tomoyo_policy_lock))
553                 goto out;
554         entry = tomoyo_find_domain(domainname);
555         if (!entry) {
556                 entry = tomoyo_commit_ok(&e, sizeof(e));
557                 if (entry) {
558                         INIT_LIST_HEAD(&entry->acl_info_list);
559                         list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
560                         created = true;
561                 }
562         }
563         mutex_unlock(&tomoyo_policy_lock);
564 out:
565         tomoyo_put_name(e.domainname);
566         if (entry && transit) {
567                 if (created) {
568                         struct tomoyo_request_info r;
569                         tomoyo_init_request_info(&r, entry,
570                                                  TOMOYO_MAC_FILE_EXECUTE);
571                         r.granted = false;
572                         tomoyo_write_log(&r, "use_profile %u\n",
573                                          entry->profile);
574                         tomoyo_write_log(&r, "use_group %u\n", entry->group);
575                         tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
576                 }
577         }
578         return entry;
579 }
580 
581 /**
582  * tomoyo_environ - Check permission for environment variable names.
583  *
584  * @ee: Pointer to "struct tomoyo_execve".
585  *
586  * Returns 0 on success, negative value otherwise.
587  */
588 static int tomoyo_environ(struct tomoyo_execve *ee)
589 {
590         struct tomoyo_request_info *r = &ee->r;
591         struct linux_binprm *bprm = ee->bprm;
592         /* env_page.data is allocated by tomoyo_dump_page(). */
593         struct tomoyo_page_dump env_page = { };
594         char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
595         int arg_len = 0;
596         unsigned long pos = bprm->p;
597         int offset = pos % PAGE_SIZE;
598         int argv_count = bprm->argc;
599         int envp_count = bprm->envc;
600         int error = -ENOMEM;
601 
602         ee->r.type = TOMOYO_MAC_ENVIRON;
603         ee->r.profile = r->domain->profile;
604         ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
605                                      TOMOYO_MAC_ENVIRON);
606         if (!r->mode || !envp_count)
607                 return 0;
608         arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
609         if (!arg_ptr)
610                 goto out;
611         while (error == -ENOMEM) {
612                 if (!tomoyo_dump_page(bprm, pos, &env_page))
613                         goto out;
614                 pos += PAGE_SIZE - offset;
615                 /* Read. */
616                 while (argv_count && offset < PAGE_SIZE) {
617                         if (!env_page.data[offset++])
618                                 argv_count--;
619                 }
620                 if (argv_count) {
621                         offset = 0;
622                         continue;
623                 }
624                 while (offset < PAGE_SIZE) {
625                         const unsigned char c = env_page.data[offset++];
626 
627                         if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
628                                 if (c == '=') {
629                                         arg_ptr[arg_len++] = '\0';
630                                 } else if (c == '\\') {
631                                         arg_ptr[arg_len++] = '\\';
632                                         arg_ptr[arg_len++] = '\\';
633                                 } else if (c > ' ' && c < 127) {
634                                         arg_ptr[arg_len++] = c;
635                                 } else {
636                                         arg_ptr[arg_len++] = '\\';
637                                         arg_ptr[arg_len++] = (c >> 6) + '';
638                                         arg_ptr[arg_len++]
639                                                 = ((c >> 3) & 7) + '';
640                                         arg_ptr[arg_len++] = (c & 7) + '';
641                                 }
642                         } else {
643                                 arg_ptr[arg_len] = '\0';
644                         }
645                         if (c)
646                                 continue;
647                         if (tomoyo_env_perm(r, arg_ptr)) {
648                                 error = -EPERM;
649                                 break;
650                         }
651                         if (!--envp_count) {
652                                 error = 0;
653                                 break;
654                         }
655                         arg_len = 0;
656                 }
657                 offset = 0;
658         }
659 out:
660         if (r->mode != TOMOYO_CONFIG_ENFORCING)
661                 error = 0;
662         kfree(env_page.data);
663         kfree(arg_ptr);
664         return error;
665 }
666 
667 /**
668  * tomoyo_find_next_domain - Find a domain.
669  *
670  * @bprm: Pointer to "struct linux_binprm".
671  *
672  * Returns 0 on success, negative value otherwise.
673  *
674  * Caller holds tomoyo_read_lock().
675  */
676 int tomoyo_find_next_domain(struct linux_binprm *bprm)
677 {
678         struct tomoyo_domain_info *old_domain = tomoyo_domain();
679         struct tomoyo_domain_info *domain = NULL;
680         const char *original_name = bprm->filename;
681         int retval = -ENOMEM;
682         bool reject_on_transition_failure = false;
683         const struct tomoyo_path_info *candidate;
684         struct tomoyo_path_info exename;
685         struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
686 
687         if (!ee)
688                 return -ENOMEM;
689         ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
690         if (!ee->tmp) {
691                 kfree(ee);
692                 return -ENOMEM;
693         }
694         /* ee->dump->data is allocated by tomoyo_dump_page(). */
695         tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
696         ee->r.ee = ee;
697         ee->bprm = bprm;
698         ee->r.obj = &ee->obj;
699         ee->obj.path1 = bprm->file->f_path;
700         /* Get symlink's pathname of program. */
701         retval = -ENOENT;
702         exename.name = tomoyo_realpath_nofollow(original_name);
703         if (!exename.name)
704                 goto out;
705         tomoyo_fill_path_info(&exename);
706 retry:
707         /* Check 'aggregator' directive. */
708         {
709                 struct tomoyo_aggregator *ptr;
710                 struct list_head *list =
711                         &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
712                 /* Check 'aggregator' directive. */
713                 candidate = &exename;
714                 list_for_each_entry_rcu(ptr, list, head.list) {
715                         if (ptr->head.is_deleted ||
716                             !tomoyo_path_matches_pattern(&exename,
717                                                          ptr->original_name))
718                                 continue;
719                         candidate = ptr->aggregated_name;
720                         break;
721                 }
722         }
723 
724         /* Check execute permission. */
725         retval = tomoyo_execute_permission(&ee->r, candidate);
726         if (retval == TOMOYO_RETRY_REQUEST)
727                 goto retry;
728         if (retval < 0)
729                 goto out;
730         /*
731          * To be able to specify domainnames with wildcards, use the
732          * pathname specified in the policy (which may contain
733          * wildcard) rather than the pathname passed to execve()
734          * (which never contains wildcard).
735          */
736         if (ee->r.param.path.matched_path)
737                 candidate = ee->r.param.path.matched_path;
738 
739         /*
740          * Check for domain transition preference if "file execute" matched.
741          * If preference is given, make do_execve() fail if domain transition
742          * has failed, for domain transition preference should be used with
743          * destination domain defined.
744          */
745         if (ee->transition) {
746                 const char *domainname = ee->transition->name;
747                 reject_on_transition_failure = true;
748                 if (!strcmp(domainname, "keep"))
749                         goto force_keep_domain;
750                 if (!strcmp(domainname, "child"))
751                         goto force_child_domain;
752                 if (!strcmp(domainname, "reset"))
753                         goto force_reset_domain;
754                 if (!strcmp(domainname, "initialize"))
755                         goto force_initialize_domain;
756                 if (!strcmp(domainname, "parent")) {
757                         char *cp;
758                         strncpy(ee->tmp, old_domain->domainname->name,
759                                 TOMOYO_EXEC_TMPSIZE - 1);
760                         cp = strrchr(ee->tmp, ' ');
761                         if (cp)
762                                 *cp = '\0';
763                 } else if (*domainname == '<')
764                         strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
765                 else
766                         snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
767                                  old_domain->domainname->name, domainname);
768                 goto force_jump_domain;
769         }
770         /*
771          * No domain transition preference specified.
772          * Calculate domain to transit to.
773          */
774         switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
775                                        candidate)) {
776         case TOMOYO_TRANSITION_CONTROL_RESET:
777 force_reset_domain:
778                 /* Transit to the root of specified namespace. */
779                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
780                          candidate->name);
781                 /*
782                  * Make do_execve() fail if domain transition across namespaces
783                  * has failed.
784                  */
785                 reject_on_transition_failure = true;
786                 break;
787         case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
788 force_initialize_domain:
789                 /* Transit to the child of current namespace's root. */
790                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
791                          old_domain->ns->name, candidate->name);
792                 break;
793         case TOMOYO_TRANSITION_CONTROL_KEEP:
794 force_keep_domain:
795                 /* Keep current domain. */
796                 domain = old_domain;
797                 break;
798         default:
799                 if (old_domain == &tomoyo_kernel_domain &&
800                     !tomoyo_policy_loaded) {
801                         /*
802                          * Needn't to transit from kernel domain before
803                          * starting /sbin/init. But transit from kernel domain
804                          * if executing initializers because they might start
805                          * before /sbin/init.
806                          */
807                         domain = old_domain;
808                         break;
809                 }
810 force_child_domain:
811                 /* Normal domain transition. */
812                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
813                          old_domain->domainname->name, candidate->name);
814                 break;
815         }
816 force_jump_domain:
817         if (!domain)
818                 domain = tomoyo_assign_domain(ee->tmp, true);
819         if (domain)
820                 retval = 0;
821         else if (reject_on_transition_failure) {
822                 printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
823                        ee->tmp);
824                 retval = -ENOMEM;
825         } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
826                 retval = -ENOMEM;
827         else {
828                 retval = 0;
829                 if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
830                         old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
831                         ee->r.granted = false;
832                         tomoyo_write_log(&ee->r, "%s", tomoyo_dif
833                                          [TOMOYO_DIF_TRANSITION_FAILED]);
834                         printk(KERN_WARNING
835                                "ERROR: Domain '%s' not defined.\n", ee->tmp);
836                 }
837         }
838  out:
839         if (!domain)
840                 domain = old_domain;
841         /* Update reference count on "struct tomoyo_domain_info". */
842         atomic_inc(&domain->users);
843         bprm->cred->security = domain;
844         kfree(exename.name);
845         if (!retval) {
846                 ee->r.domain = domain;
847                 retval = tomoyo_environ(ee);
848         }
849         kfree(ee->tmp);
850         kfree(ee->dump.data);
851         kfree(ee);
852         return retval;
853 }
854 
855 /**
856  * tomoyo_dump_page - Dump a page to buffer.
857  *
858  * @bprm: Pointer to "struct linux_binprm".
859  * @pos:  Location to dump.
860  * @dump: Poiner to "struct tomoyo_page_dump".
861  *
862  * Returns true on success, false otherwise.
863  */
864 bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
865                       struct tomoyo_page_dump *dump)
866 {
867         struct page *page;
868 
869         /* dump->data is released by tomoyo_find_next_domain(). */
870         if (!dump->data) {
871                 dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
872                 if (!dump->data)
873                         return false;
874         }
875         /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
876 #ifdef CONFIG_MMU
877         if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
878                 return false;
879 #else
880         page = bprm->page[pos / PAGE_SIZE];
881 #endif
882         if (page != dump->page) {
883                 const unsigned int offset = pos % PAGE_SIZE;
884                 /*
885                  * Maybe kmap()/kunmap() should be used here.
886                  * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
887                  * So do I.
888                  */
889                 char *kaddr = kmap_atomic(page);
890 
891                 dump->page = page;
892                 memcpy(dump->data + offset, kaddr + offset,
893                        PAGE_SIZE - offset);
894                 kunmap_atomic(kaddr);
895         }
896         /* Same with put_arg_page(page) in fs/exec.c */
897 #ifdef CONFIG_MMU
898         put_page(page);
899 #endif
900         return true;
901 }
902 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp