オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Diff of /trunk/1.8.x/ccs-patch/security/ccsecurity/domain.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2951 by kumaneko, Tue Aug 25 04:26:20 2009 UTC revision 3627 by kumaneko, Wed May 5 04:55:52 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Version: 1.7.0-pre   2009/08/24   * Version: 1.7.2+   2010/05/05
7   *   *
8   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
# Line 22  Line 22 
22  #endif  #endif
23  #include "internal.h"  #include "internal.h"
24    
 /* For compatibility with older kernels. */  
 #ifndef for_each_process  
 #define for_each_process for_each_task  
 #endif  
   
25  /* Variables definitions.*/  /* Variables definitions.*/
26    
27  /* The initial domain. */  /* The initial domain. */
# Line 39  LIST_HEAD(ccs_domain_list); Line 34  LIST_HEAD(ccs_domain_list);
34   * ccs_audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
35   *   *
36   * @ee:         Pointer to "struct ccs_execve_entry".   * @ee:         Pointer to "struct ccs_execve_entry".
  * @is_default: True if it is "execute_handler" log.  
37   *   *
38   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
39   */   */
40  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee)
                                          const bool is_default)  
41  {  {
42          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
43          const char *handler = ee->handler->name;          const char *handler = ee->handler->name;
44            r->type = CCS_MAC_FILE_EXECUTE;
45          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
46          return ccs_write_audit_log(true, r, "%s %s\n",          return ccs_write_audit_log(true, r, "%s" CCS_KEYWORD_EXECUTE_HANDLER
47                                     is_default ? CCS_KEYWORD_EXECUTE_HANDLER :                                     " %s\n", ee->handler_type ==
48                                     CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);                                     CCS_TYPE_DENIED_EXECUTE_HANDLER ?
49                                       "denied" : "", handler);
50  }  }
51    
52  /**  /**
53   * ccs_audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
54   *   *
  * @domain:  Pointer to "struct ccs_domain_info".  
  *  
55   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
56   */   */
57  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  static int ccs_audit_domain_creation_log(void)
58  {  {
         int error;  
59          struct ccs_request_info r;          struct ccs_request_info r;
60          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);          ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
61          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);          return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
         return error;  
62  }  }
63    
64  /* The list for "struct ccs_domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
# Line 88  static int ccs_update_domain_initializer Line 79  static int ccs_update_domain_initializer
79                                                 const bool is_not,                                                 const bool is_not,
80                                                 const bool is_delete)                                                 const bool is_delete)
81  {  {
         struct ccs_domain_initializer_entry *entry = NULL;  
82          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
83          struct ccs_domain_initializer_entry e = { .is_not = is_not };          struct ccs_domain_initializer_entry e = { .is_not = is_not };
84          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
# Line 107  static int ccs_update_domain_initializer Line 97  static int ccs_update_domain_initializer
97          e.program = ccs_get_name(program);          e.program = ccs_get_name(program);
98          if (!e.program)          if (!e.program)
99                  goto out;                  goto out;
100          if (!is_delete)          if (mutex_lock_interruptible(&ccs_policy_lock))
101                  entry = kmalloc(sizeof(e), GFP_KERNEL);                  goto out;
         mutex_lock(&ccs_policy_lock);  
102          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
103                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),                  if (!ccs_is_same_domain_initializer_entry(ptr, &e))
                                sizeof(e)))  
104                          continue;                          continue;
105                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
106                  error = 0;                  error = 0;
107                  break;                  break;
108          }          }
109          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {          if (!is_delete && error) {
110                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);                  struct ccs_domain_initializer_entry *entry =
111                  entry = NULL;                          ccs_commit_ok(&e, sizeof(e));
112                  error = 0;                  if (entry) {
113                            list_add_tail_rcu(&entry->list,
114                                              &ccs_domain_initializer_list);
115                            error = 0;
116                    }
117          }          }
118          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
119   out:   out:
120          ccs_put_name(e.domainname);          ccs_put_name(e.domainname);
121          ccs_put_name(e.program);          ccs_put_name(e.program);
         kfree(entry);  
122          return error;          return error;
123  }  }
124    
# Line 249  static int ccs_update_domain_keeper_entr Line 240  static int ccs_update_domain_keeper_entr
240                                            const bool is_not,                                            const bool is_not,
241                                            const bool is_delete)                                            const bool is_delete)
242  {  {
         struct ccs_domain_keeper_entry *entry = NULL;  
243          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
244          struct ccs_domain_keeper_entry e = { .is_not = is_not };          struct ccs_domain_keeper_entry e = { .is_not = is_not };
245          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
# Line 268  static int ccs_update_domain_keeper_entr Line 258  static int ccs_update_domain_keeper_entr
258          e.domainname = ccs_get_name(domainname);          e.domainname = ccs_get_name(domainname);
259          if (!e.domainname)          if (!e.domainname)
260                  goto out;                  goto out;
261          if (!is_delete)          if (mutex_lock_interruptible(&ccs_policy_lock))
262                  entry = kmalloc(sizeof(e), GFP_KERNEL);                  goto out;
         mutex_lock(&ccs_policy_lock);  
263          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
264                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),                  if (!ccs_is_same_domain_keeper_entry(ptr, &e))
                                sizeof(e)))  
265                          continue;                          continue;
266                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
267                  error = 0;                  error = 0;
268                  break;                  break;
269          }          }
270          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {          if (!is_delete && error) {
271                  list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);                  struct ccs_domain_keeper_entry *entry =
272                  entry = NULL;                          ccs_commit_ok(&e, sizeof(e));
273                  error = 0;                  if (entry) {
274                            list_add_tail_rcu(&entry->list,
275                                              &ccs_domain_keeper_list);
276                            error = 0;
277                    }
278          }          }
279          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
280   out:   out:
281          ccs_put_name(e.domainname);          ccs_put_name(e.domainname);
282          ccs_put_name(e.program);          ccs_put_name(e.program);
         kfree(entry);  
283          return error;          return error;
284  }  }
285    
# Line 403  static int ccs_update_aggregator_entry(c Line 394  static int ccs_update_aggregator_entry(c
394                                         const char *aggregated_name,                                         const char *aggregated_name,
395                                         const bool is_delete)                                         const bool is_delete)
396  {  {
         struct ccs_aggregator_entry *entry = NULL;  
397          struct ccs_aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
398          struct ccs_aggregator_entry e = { };          struct ccs_aggregator_entry e = { };
399          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
# Line 414  static int ccs_update_aggregator_entry(c Line 404  static int ccs_update_aggregator_entry(c
404          e.aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
405          if (!e.original_name || !e.aggregated_name)          if (!e.original_name || !e.aggregated_name)
406                  goto out;                  goto out;
407          if (!is_delete)          if (mutex_lock_interruptible(&ccs_policy_lock))
408                  entry = kmalloc(sizeof(e), GFP_KERNEL);                  goto out;
         mutex_lock(&ccs_policy_lock);  
409          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
410                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), original_name),                  if (!ccs_is_same_aggregator_entry(ptr, &e))
                                sizeof(e)))  
411                          continue;                          continue;
412                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
413                  error = 0;                  error = 0;
414                  break;                  break;
415          }          }
416          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {          if (!is_delete && error) {
417                  list_add_tail_rcu(&entry->list, &ccs_aggregator_list);                  struct ccs_aggregator_entry *entry =
418                  entry = NULL;                          ccs_commit_ok(&e, sizeof(e));
419                  error = 0;                  if (entry) {
420                            list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
421                            error = 0;
422                    }
423          }          }
424          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
425   out:   out:
426          ccs_put_name(e.original_name);          ccs_put_name(e.original_name);
427          ccs_put_name(e.aggregated_name);          ccs_put_name(e.aggregated_name);
         kfree(entry);  
428          return error;          return error;
429  }  }
430    
# Line 496  int ccs_delete_domain(char *domainname) Line 486  int ccs_delete_domain(char *domainname)
486          struct ccs_path_info name;          struct ccs_path_info name;
487          name.name = domainname;          name.name = domainname;
488          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
489          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
490                    return 0;
491          /* Is there an active domain? */          /* Is there an active domain? */
492          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
493                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
# Line 524  struct ccs_domain_info *ccs_find_or_assi Line 515  struct ccs_domain_info *ccs_find_or_assi
515                                                        const u8 profile)                                                        const u8 profile)
516  {  {
517          struct ccs_domain_info *entry;          struct ccs_domain_info *entry;
518          struct ccs_domain_info *domain;          struct ccs_domain_info *domain = NULL;
519          const struct ccs_path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
520          bool found = false;          bool found = false;
521    
# Line 533  struct ccs_domain_info *ccs_find_or_assi Line 524  struct ccs_domain_info *ccs_find_or_assi
524          saved_domainname = ccs_get_name(domainname);          saved_domainname = ccs_get_name(domainname);
525          if (!saved_domainname)          if (!saved_domainname)
526                  return NULL;                  return NULL;
527          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
528          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
529                    goto out;
530          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
531                  if (domain->is_deleted ||                  if (domain->is_deleted ||
532                      ccs_pathcmp(saved_domainname, domain->domainname))                      ccs_pathcmp(saved_domainname, domain->domainname))
# Line 553  struct ccs_domain_info *ccs_find_or_assi Line 545  struct ccs_domain_info *ccs_find_or_assi
545                  found = true;                  found = true;
546          }          }
547          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
548     out:
549          ccs_put_name(saved_domainname);          ccs_put_name(saved_domainname);
550          kfree(entry);          kfree(entry);
551          return found ? domain : NULL;          return found ? domain : NULL;
# Line 572  static int ccs_find_next_domain(struct c Line 565  static int ccs_find_next_domain(struct c
565          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
566          const struct ccs_path_info *handler = ee->handler;          const struct ccs_path_info *handler = ee->handler;
567          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
568          const char *old_domain_name = r->domain->domainname->name;          struct ccs_domain_info * const old_domain = ccs_current_domain();
569            const char *old_domain_name = old_domain->domainname->name;
570          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
571          const u32 ccs_flags = current->ccs_flags;          struct task_struct *task = current;
572            const u32 ccs_flags = task->ccs_flags;
573          struct ccs_path_info rn = { }; /* real name */          struct ccs_path_info rn = { }; /* real name */
574          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
575          int retval;          int retval;
576          bool need_kfree = false;          bool need_kfree = false;
577            bool domain_created = false;
578          ln.name = ccs_last_word(old_domain_name);          ln.name = ccs_last_word(old_domain_name);
579          ccs_fill_path_info(&ln);          ccs_fill_path_info(&ln);
580   retry:   retry:
# Line 622  static int ccs_find_next_domain(struct c Line 618  static int ccs_find_next_domain(struct c
618    
619                  /* Check execute permission. */                  /* Check execute permission. */
620                  retval = ccs_exec_perm(r, &rn);                  retval = ccs_exec_perm(r, &rn);
621                  if (retval == 1)                  if (retval == CCS_RETRY_REQUEST)
622                          goto retry;                          goto retry;
623                  if (retval < 0)                  if (retval < 0)
624                          goto out;                          goto out;
625          }          }
626    
627          /* Calculate domain to transit to. */          /* Calculate domain to transit to. */
628          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {          if (ccs_is_domain_initializer(old_domain->domainname, &rn, &ln)) {
629                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
630                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
631                           rn.name);                           rn.name);
632          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {          } else if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
633                  /*                  /*
634                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
635                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
636                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
637                   */                   */
638                  domain = r->domain;                  domain = old_domain;
639          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {          } else if (ccs_is_domain_keeper(old_domain->domainname, &rn, &ln)) {
640                  /* Keep current domain. */                  /* Keep current domain. */
641                  domain = r->domain;                  domain = old_domain;
642          } else {          } else {
643                  /* Normal domain transition. */                  /* Normal domain transition. */
644                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
# Line 653  static int ccs_find_next_domain(struct c Line 649  static int ccs_find_next_domain(struct c
649          domain = ccs_find_domain(ee->tmp);          domain = ccs_find_domain(ee->tmp);
650          if (domain)          if (domain)
651                  goto done;                  goto done;
652          if (r->mode == CCS_MAC_MODE_ENFORCING) {          if (r->mode == CCS_CONFIG_ENFORCING) {
653                  int error = ccs_supervisor(r, "# wants to create domain\n"                  int error = ccs_supervisor(r, "# wants to create domain\n"
654                                             "%s\n", ee->tmp);                                             "%s\n", ee->tmp);
655                  if (error == 1)                  if (error == CCS_RETRY_REQUEST)
656                          goto retry;                          goto retry;
657                  if (error < 0)                  if (error < 0)
658                          goto done;                          goto done;
659          }          }
660          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);
661          if (domain)          if (domain)
662                  ccs_audit_domain_creation_log(r->domain);                  domain_created = true;
663   done:   done:
664          if (!domain) {          if (!domain) {
665                  printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
666                         ee->tmp);                  if (!old_domain->domain_transition_failed) {
667                  if (r->mode == CCS_MAC_MODE_ENFORCING)                          old_domain->domain_transition_failed = true;
668                          retval = -EPERM;                          ccs_write_audit_log(false, r,
669                  else {                                              CCS_KEYWORD_TRANSITION_FAILED
670                          retval = 0;                                              "\n");
671                          r->domain->domain_transition_failed = true;                          printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
672                                   ee->tmp);
673                  }                  }
674          } else {          } else {
675                  retval = 0;                  retval = 0;
676          }          }
677   out:          if (!retval && handler)
678                    ccs_audit_execute_handler_log(ee);
679            /*
680             * Tell GC that I started execve().
681             * Also, tell open_exec() to check read permission.
682             */
683            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
684            /*
685             * Make task->ccs_flags visible to GC before changing
686             * task->ccs_domain_info .
687             */
688            smp_mb();
689            /*
690             * Proceed to the next domain in order to allow reaching via PID.
691             * It will be reverted if execve() failed. Reverting is not good.
692             * But it is better than being unable to reach via PID in interactive
693             * enforcing mode.
694             */
695          if (domain)          if (domain)
696                  r->domain = domain;                  task->ccs_domain_info = domain;
697            if (domain_created)
698                    ccs_audit_domain_creation_log();
699     out:
700          if (need_kfree)          if (need_kfree)
701                  kfree(rn.name);                  kfree(rn.name);
702          return retval;          return retval;
# Line 696  static int ccs_environ(struct ccs_execve Line 713  static int ccs_environ(struct ccs_execve
713  {  {
714          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
715          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
716          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
717            struct ccs_page_dump env_page = { };
718            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
719          int arg_len = 0;          int arg_len = 0;
720          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
721          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 704  static int ccs_environ(struct ccs_execve Line 723  static int ccs_environ(struct ccs_execve
723          int envp_count = bprm->envc;          int envp_count = bprm->envc;
724          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
725          int error = -ENOMEM;          int error = -ENOMEM;
726            ee->r.type = CCS_MAC_ENVIRON;
727            ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
728                                      CCS_MAC_ENVIRON);
729          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
730                  return 0;                  return 0;
731            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
732            if (!arg_ptr)
733                    goto out;
734          while (error == -ENOMEM) {          while (error == -ENOMEM) {
735                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
736                          goto out;                          goto out;
737                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
738                  /* Read. */                  /* Read. */
739                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
740                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
741                                  argv_count--;                                  argv_count--;
742                  }                  }
743                  if (argv_count) {                  if (argv_count) {
# Line 721  static int ccs_environ(struct ccs_execve Line 745  static int ccs_environ(struct ccs_execve
745                          continue;                          continue;
746                  }                  }
747                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
748                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
                         const unsigned char c = kaddr[offset++];  
749                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
750                                  if (c == '=') {                                  if (c == '=') {
751                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
# Line 758  static int ccs_environ(struct ccs_execve Line 781  static int ccs_environ(struct ccs_execve
781   out:   out:
782          if (r->mode != 3)          if (r->mode != 3)
783                  error = 0;                  error = 0;
784            kfree(env_page.data);
785            kfree(arg_ptr);
786          return error;          return error;
787  }  }
788    
# Line 808  static void ccs_unescape(unsigned char * Line 833  static void ccs_unescape(unsigned char *
833   *   *
834   * Returns number of directories to strip.   * Returns number of directories to strip.
835   */   */
836  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
837  {  {
838          int depth = 0;          int depth = 0;
839          ccs_realpath_lock();          ccs_realpath_lock();
# Line 862  static int ccs_get_root_depth(void) Line 887  static int ccs_get_root_depth(void)
887          return depth;          return depth;
888  }  }
889    
 static LIST_HEAD(ccs_execve_list);  
 static DEFINE_SPINLOCK(ccs_execve_list_lock);  
   
 /**  
  * ccs_allocate_execve_entry - Allocate memory for execve().  
  *  
  * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.  
  */  
 static struct ccs_execve_entry *ccs_allocate_execve_entry(void)  
 {  
         struct ccs_execve_entry *ee = kzalloc(sizeof(*ee), GFP_KERNEL);  
         if (!ee)  
                 return NULL;  
         ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);  
         if (!ee->tmp) {  
                 kfree(ee);  
                 return NULL;  
         }  
         ee->reader_idx = ccs_read_lock();  
         /* ee->dump->data is allocated by ccs_dump_page(). */  
         ee->task = current;  
         spin_lock(&ccs_execve_list_lock);  
         list_add(&ee->list, &ccs_execve_list);  
         spin_unlock(&ccs_execve_list_lock);  
         return ee;  
 }  
   
 /**  
  * ccs_find_execve_entry - Find ccs_execve_entry of current process.  
  *  
  * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.  
  */  
 static struct ccs_execve_entry *ccs_find_execve_entry(void)  
 {  
         struct task_struct *task = current;  
         struct ccs_execve_entry *ee = NULL;  
         struct ccs_execve_entry *p;  
         spin_lock(&ccs_execve_list_lock);  
         list_for_each_entry(p, &ccs_execve_list, list) {  
                 if (p->task != task)  
                         continue;  
                 ee = p;  
                 break;  
         }  
         spin_unlock(&ccs_execve_list_lock);  
         return ee;  
 }  
   
 /**  
  * ccs_free_execve_entry - Free memory for execve().  
  *  
  * @ee: Pointer to "struct ccs_execve_entry".  
  */  
 static void ccs_free_execve_entry(struct ccs_execve_entry *ee)  
 {  
         if (!ee)  
                 return;  
         spin_lock(&ccs_execve_list_lock);  
         list_del(&ee->list);  
         spin_unlock(&ccs_execve_list_lock);  
         kfree(ee->handler_path);  
         kfree(ee->tmp);  
         kfree(ee->dump.data);  
         ccs_read_unlock(ee->reader_idx);  
         kfree(ee);  
 }  
   
890  /**  /**
891   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
892   *   *
# Line 982  static int ccs_try_alt_exec(struct ccs_e Line 940  static int ccs_try_alt_exec(struct ccs_e
940          struct task_struct *task = current;          struct task_struct *task = current;
941    
942          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
943            ee->obj.path1.dentry = NULL;
944            ee->obj.path1.mnt = NULL;
945            ee->obj.validate_done = false;
946          allow_write_access(bprm->file);          allow_write_access(bprm->file);
947          fput(bprm->file);          fput(bprm->file);
948          bprm->file = NULL;          bprm->file = NULL;
# Line 1029  static int ccs_try_alt_exec(struct ccs_e Line 990  static int ccs_try_alt_exec(struct ccs_e
990                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
991                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
992                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
993                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           (pid_t) ccsecurity_exports.sys_getpid(),
994                           current_euid(), current_egid(), current_suid(),                           current_uid(), current_gid(), current_euid(),
995                           current_sgid(), current_fsuid(), current_fsgid(),                           current_egid(), current_suid(), current_sgid(),
996                             current_fsuid(), current_fsgid(),
997                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
998                           (u8) (ccs_flags >> 8));                           (u8) (ccs_flags >> 8));
999                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
# Line 1071  static int ccs_try_alt_exec(struct ccs_e Line 1033  static int ccs_try_alt_exec(struct ccs_e
1033          {          {
1034                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
1035                  int len = ee->handler->total_len + 1;                  int len = ee->handler->total_len + 1;
1036                  char *cp = kmalloc(len, GFP_KERNEL);                  char *cp = kmalloc(len, CCS_GFP_FLAGS);
1037                  if (!cp) {                  if (!cp) {
1038                          retval = ENOMEM;                          retval = -ENOMEM;
1039                          goto out;                          goto out;
1040                  }                  }
1041                  ee->handler_path = cp;                  ee->handler_path = cp;
# Line 1102  static int ccs_try_alt_exec(struct ccs_e Line 1064  static int ccs_try_alt_exec(struct ccs_e
1064  #endif  #endif
1065  #endif  #endif
1066    
1067          /* OK, now restart the process with execute handler program's dentry. */          /*
1068             * OK, now restart the process with execute handler program's dentry.
1069             */
1070          filp = open_exec(ee->handler_path);          filp = open_exec(ee->handler_path);
1071          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1072                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1073                  goto out;                  goto out;
1074          }          }
1075            ee->obj.path1.dentry = filp->f_dentry;
1076            ee->obj.path1.mnt = filp->f_vfsmnt;
1077          bprm->file = filp;          bprm->file = filp;
1078          bprm->filename = ee->handler_path;          bprm->filename = ee->handler_path;
1079  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
# Line 1137  static bool ccs_find_execute_handler(str Line 1103  static bool ccs_find_execute_handler(str
1103                                       const u8 type)                                       const u8 type)
1104  {  {
1105          struct task_struct *task = current;          struct task_struct *task = current;
1106          const struct ccs_domain_info *domain = ccs_current_domain();          const struct ccs_domain_info * const domain = ccs_current_domain();
1107          struct ccs_acl_info *ptr;          struct ccs_acl_info *ptr;
1108          bool found = false;          bool found = false;
1109          /*          /*
# Line 1153  static bool ccs_find_execute_handler(str Line 1119  static bool ccs_find_execute_handler(str
1119                  acl = container_of(ptr, struct ccs_execute_handler_record,                  acl = container_of(ptr, struct ccs_execute_handler_record,
1120                                     head);                                     head);
1121                  ee->handler = acl->handler;                  ee->handler = acl->handler;
1122                    ee->handler_type = type;
1123                  found = true;                  found = true;
1124                  break;                  break;
1125          }          }
# Line 1172  bool ccs_dump_page(struct linux_binprm * Line 1139  bool ccs_dump_page(struct linux_binprm *
1139                     struct ccs_page_dump *dump)                     struct ccs_page_dump *dump)
1140  {  {
1141          struct page *page;          struct page *page;
1142          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_finish_execve(). */
1143          if (!dump->data) {          if (!dump->data) {
1144                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1145                  if (!dump->data)                  if (!dump->data)
1146                          return false;                          return false;
1147          }          }
# Line 1182  bool ccs_dump_page(struct linux_binprm * Line 1149  bool ccs_dump_page(struct linux_binprm *
1149  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1150          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1151                  return false;                  return false;
1152  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1153            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1154                    return false;
1155    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1156          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1157                  return false;                  return false;
1158  #else  #else
# Line 1197  bool ccs_dump_page(struct linux_binprm * Line 1167  bool ccs_dump_page(struct linux_binprm *
1167                   */                   */
1168                  char *kaddr = kmap_atomic(page, KM_USER0);                  char *kaddr = kmap_atomic(page, KM_USER0);
1169                  dump->page = page;                  dump->page = page;
1170                  memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);                  memcpy(dump->data + offset, kaddr + offset,
1171                           PAGE_SIZE - offset);
1172                  kunmap_atomic(kaddr, KM_USER0);                  kunmap_atomic(kaddr, KM_USER0);
1173          }          }
1174          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1175  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1176          put_page(page);          put_page(page);
1177  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1178            put_page(page);
1179    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1180          put_page(page);          put_page(page);
1181  #endif  #endif
1182          return true;          return true;
1183  }  }
1184    
1185  /**  /**
  * ccs_fetch_next_domain - Fetch next_domain from the list.  
  *  
  * Returns pointer to "struct ccs_domain_info" which will be used if execve()  
  * succeeds. This function does not return NULL.  
  */  
 struct ccs_domain_info *ccs_fetch_next_domain(void)  
 {  
         struct ccs_execve_entry *ee = ccs_find_execve_entry();  
         struct ccs_domain_info *next_domain = NULL;  
         if (ee)  
                 next_domain = ee->r.domain;  
         if (!next_domain)  
                 next_domain = ccs_current_domain();  
         return next_domain;  
 }  
   
 /**  
1186   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1187   *   *
1188   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1189     * @eep:  Pointer to "struct ccs_execve_entry *".
1190   *   *
1191   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1192   */   */
1193  int ccs_start_execve(struct linux_binprm *bprm)  static int ccs_start_execve(struct linux_binprm *bprm,
1194                                struct ccs_execve_entry **eep)
1195  {  {
1196          int retval;          int retval;
1197          struct task_struct *task = current;          struct task_struct *task = current;
1198          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();          struct ccs_execve_entry *ee;
1199          if (!ccs_policy_loaded)          *eep = NULL;
1200                  ccs_load_policy(bprm->filename);          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1201          if (!ee)          if (!ee)
1202                  return -ENOMEM;                  return -ENOMEM;
1203          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1204            if (!ee->tmp) {
1205                    kfree(ee);
1206                    return -ENOMEM;
1207            }
1208            ee->reader_idx = ccs_read_lock();
1209            /* ee->dump->data is allocated by ccs_dump_page(). */
1210            ee->previous_domain = task->ccs_domain_info;
1211            /* Clear manager flag. */
1212            task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1213            *eep = ee;
1214            ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1215          ee->r.ee = ee;          ee->r.ee = ee;
1216          ee->bprm = bprm;          ee->bprm = bprm;
1217          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1218          ee->obj.path1.dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1219          ee->obj.path1.mnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1220          /* Clear manager flag. */          /*
1221          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;           * No need to call ccs_environ() for execute handler because envp[] is
1222          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {           * moved to argv[].
1223                  retval = ccs_try_alt_exec(ee);           */
1224                  if (!retval)          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER))
1225                          ccs_audit_execute_handler_log(ee, true);                  return ccs_try_alt_exec(ee);
                 goto ok;  
         }  
1226          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1227          if (retval != -EPERM)          if (retval == -EPERM) {
1228                  goto ok;                  if (ccs_find_execute_handler(ee,
1229          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {                                               CCS_TYPE_DENIED_EXECUTE_HANDLER))
1230                  retval = ccs_try_alt_exec(ee);                          return ccs_try_alt_exec(ee);
                 if (!retval)  
                         ccs_audit_execute_handler_log(ee, false);  
1231          }          }
1232   ok:          if (!retval)
1233          if (retval < 0)                  retval = ccs_environ(ee);
                 goto out;  
         ee->r.mode = ccs_get_mode(ee->r.profile, CCS_MAC_ENVIRON);  
         retval = ccs_environ(ee);  
         if (retval < 0)  
                 goto out;  
         task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;  
         retval = 0;  
  out:  
         if (retval)  
                 ccs_finish_execve(retval);  
1234          return retval;          return retval;
1235  }  }
1236    
# Line 1283  int ccs_start_execve(struct linux_binprm Line 1238  int ccs_start_execve(struct linux_binprm
1238   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1239   *   *
1240   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1241     * @ee:     Pointer to "struct ccs_execve_entry".
1242   *   *
1243   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1244   */   */
1245  void ccs_finish_execve(int retval)  static void ccs_finish_execve(int retval, struct ccs_execve_entry *ee)
1246  {  {
1247          struct task_struct *task = current;          struct task_struct *task = current;
         struct ccs_execve_entry *ee = ccs_find_execve_entry();  
         task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;  
1248          if (!ee)          if (!ee)
1249                  return;                  return;
1250          if (retval < 0)          if (retval < 0) {
1251                  goto out;                  task->ccs_domain_info = ee->previous_domain;
1252          /* Proceed to next domain if execution suceeded. */                  /*
1253          task->ccs_domain_info = ee->r.domain;                   * Make task->ccs_domain_info visible to GC before changing
1254          /* Mark the current process as execute handler. */                   * task->ccs_flags .
1255          if (ee->handler)                   */
1256                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  smp_mb();
1257          /* Mark the current process as normal process. */          } else {
1258          else                  /* Mark the current process as execute handler. */
1259                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                  if (ee->handler)
1260   out:                          task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1261          ccs_free_execve_entry(ee);                  /* Mark the current process as normal process. */
1262                    else
1263                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1264            }
1265            /* Tell GC that I finished execve(). */
1266            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1267            ccs_read_unlock(ee->reader_idx);
1268            kfree(ee->handler_path);
1269            kfree(ee->tmp);
1270            kfree(ee->dump.data);
1271            kfree(ee);
1272    }
1273    
1274    /**
1275     * ccs_may_transit - Check permission and do domain transition without execve().
1276     *
1277     * @domainname: Domainname to transit to.
1278     * @pathname: Pathname to check.
1279     *
1280     * Returns 0 on success, negative value otherwise.
1281     *
1282     * Caller holds ccs_read_lock().
1283     */
1284    int ccs_may_transit(const char *domainname, const char *pathname)
1285    {
1286            struct ccs_path_info name;
1287            struct ccs_request_info r;
1288            struct ccs_domain_info *domain;
1289            int error;
1290            bool domain_created = false;
1291            name.name = pathname;
1292            ccs_fill_path_info(&name);
1293            /* Check allow_transit permission. */
1294            ccs_init_request_info(&r, CCS_MAC_FILE_TRANSIT);
1295            error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1296            if (error)
1297                    return error;
1298            /* Check destination domain. */
1299            domain = ccs_find_domain(domainname);
1300            if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1301                strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1302                    domain = ccs_find_or_assign_new_domain(domainname, r.profile);
1303                    if (domain)
1304                            domain_created = true;
1305            }
1306            if (domain) {
1307                    error = 0;
1308                    current->ccs_domain_info = domain;
1309                    if (domain_created)
1310                            ccs_audit_domain_creation_log();
1311            } else {
1312                    error = -ENOENT;
1313            }
1314            return error;
1315    }
1316    
1317    static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1318                                           struct pt_regs *regs)
1319    {
1320            struct ccs_execve_entry *ee;
1321            int retval;
1322            if (!ccs_policy_loaded)
1323                    ccsecurity_exports.load_policy(bprm->filename);
1324            retval = ccs_start_execve(bprm, &ee);
1325            if (!retval)
1326                    retval = search_binary_handler(bprm, regs);
1327            ccs_finish_execve(retval, ee);
1328            return retval;
1329    }
1330    
1331    void __init ccs_domain_init(void)
1332    {
1333            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1334  }  }

Legend:
Removed from v.2951  
changed lines
  Added in v.3627

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26