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

Subversion リポジトリの参照

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

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

branches/ccs-patch/fs/tomoyo_domain.c revision 2718 by kumaneko, Thu Jul 2 01:30:12 2009 UTC trunk/1.7.x/ccs-patch/security/ccsecurity/domain.c revision 3519 by kumaneko, Sun Mar 21 08:31:39 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Version: 1.7.2-pre   2010/03/21
  *  
  * Version: 1.7.0-pre   2009/05/28  
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.
10   *   *
11   */   */
12    
13  #include <linux/ccs_common.h>  #include <linux/slab.h>
 #include <linux/tomoyo.h>  
 #include <linux/realpath.h>  
14  #include <linux/highmem.h>  #include <linux/highmem.h>
15    #include <linux/version.h>
16  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17  #include <linux/namei.h>  #include <linux/namei.h>
18  #include <linux/mount.h>  #include <linux/mount.h>
# Line 23  Line 20 
20  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
21  #include <linux/fs_struct.h>  #include <linux/fs_struct.h>
22  #endif  #endif
23    #include "internal.h"
 /* For compatibility with older kernels. */  
 #ifndef for_each_process  
 #define for_each_process for_each_task  
 #endif  
24    
25  /* Variables definitions.*/  /* Variables definitions.*/
26    
# Line 38  struct ccs_domain_info ccs_kernel_domain Line 31  struct ccs_domain_info ccs_kernel_domain
31  LIST_HEAD(ccs_domain_list);  LIST_HEAD(ccs_domain_list);
32    
33  /**  /**
  * ccs_get_last_name - Get last component of a domainname.  
  *  
  * @domain: Pointer to "struct ccs_domain_info".  
  *  
  * Returns the last component of the domainname.  
  */  
 const char *ccs_get_last_name(const struct ccs_domain_info *domain)  
 {  
         const char *cp0 = domain->domainname->name;  
         const char *cp1 = strrchr(cp0, ' ');  
         if (cp1)  
                 return cp1 + 1;  
         return cp0;  
 }  
   
 /**  
  * ccs_add_domain_acl - Add the given ACL to the given domain.  
  *  
  * @domain: Pointer to "struct ccs_domain_info". May be NULL.  
  * @acl:    Pointer to "struct ccs_acl_info".  
  *  
  * Returns 0.  
  */  
 int ccs_add_domain_acl(struct ccs_domain_info *domain, struct ccs_acl_info *acl)  
 {  
         if (domain) {  
                 if (acl->cond)  
                         atomic_inc(&acl->cond->users);  
                 list_add_tail_rcu(&acl->list, &domain->acl_info_list);  
         } else {  
                 acl->type &= ~ACL_DELETED;  
         }  
         return 0;  
 }  
   
 /**  
  * ccs_del_domain_acl - Delete the given ACL from the domain.  
  *  
  * @acl: Pointer to "struct ccs_acl_info". May be NULL.  
  *  
  * Returns 0.  
  */  
 int ccs_del_domain_acl(struct ccs_acl_info *acl)  
 {  
         if (acl)  
                 acl->type |= ACL_DELETED;  
         return 0;  
 }  
   
 /**  
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".
# Line 98  int ccs_del_domain_acl(struct ccs_acl_in Line 41  int ccs_del_domain_acl(struct ccs_acl_in
41  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
42                                           const bool is_default)                                           const bool is_default)
43  {  {
44            int error;
45          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
46            struct ccs_domain_info *domain = r->domain;
47          const char *handler = ee->handler->name;          const char *handler = ee->handler->name;
48          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
49          return ccs_write_audit_log(true, r, "%s %s\n",          r->domain = ee->previous_domain;
50                                     is_default ? KEYWORD_EXECUTE_HANDLER :          error = ccs_write_audit_log(true, r, "%s %s\n",
51                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);                                      is_default ? CCS_KEYWORD_EXECUTE_HANDLER :
52                                        CCS_KEYWORD_DENIED_EXECUTE_HANDLER,
53                                        handler);
54            r->domain = domain;
55            return error;
56  }  }
57    
58  /**  /**
# Line 115  static int ccs_audit_execute_handler_log Line 64  static int ccs_audit_execute_handler_log
64   */   */
65  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
66  {  {
         int error;  
67          struct ccs_request_info r;          struct ccs_request_info r;
68          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);
69          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;  
70  }  }
71    
72  /* The list for "struct ccs_domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
# Line 140  static int ccs_update_domain_initializer Line 87  static int ccs_update_domain_initializer
87                                                 const bool is_not,                                                 const bool is_not,
88                                                 const bool is_delete)                                                 const bool is_delete)
89  {  {
         struct ccs_domain_initializer_entry *entry = NULL;  
90          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
91          const struct ccs_path_info *saved_program;          struct ccs_domain_initializer_entry e = { .is_not = is_not };
         const struct ccs_path_info *saved_domainname = NULL;  
92          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
         bool is_last_name = false;  
93          if (!ccs_is_correct_path(program, 1, -1, -1))          if (!ccs_is_correct_path(program, 1, -1, -1))
94                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
95          if (domainname) {          if (domainname) {
96                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
97                      ccs_is_correct_path(domainname, 1, -1, -1))                      ccs_is_correct_path(domainname, 1, -1, -1))
98                          is_last_name = true;                          e.is_last_name = true;
99                  else if (!ccs_is_correct_domain(domainname))                  else if (!ccs_is_correct_domain(domainname))
100                          return -EINVAL;                          return -EINVAL;
101                  saved_domainname = ccs_get_name(domainname);                  e.domainname = ccs_get_name(domainname);
102                  if (!saved_domainname)                  if (!e.domainname)
103                          return -ENOMEM;                          goto out;
         }  
         saved_program = ccs_get_name(program);  
         if (!saved_program) {  
                 ccs_put_name(saved_domainname);  
                 return -ENOMEM;  
104          }          }
105          if (!is_delete)          e.program = ccs_get_name(program);
106                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);          if (!e.program)
107                    goto out;
108          mutex_lock(&ccs_policy_lock);          mutex_lock(&ccs_policy_lock);
109          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
110                  if (ptr->is_not != is_not ||                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
111                      ptr->domainname != saved_domainname ||                                 sizeof(e)))
                     ptr->program != saved_program)  
112                          continue;                          continue;
113                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
114                  error = 0;                  error = 0;
115                  break;                  break;
116          }          }
117          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {          if (!is_delete && error) {
118                  entry->domainname = saved_domainname;                  struct ccs_domain_initializer_entry *entry =
119                  saved_domainname = NULL;                          ccs_commit_ok(&e, sizeof(e));
120                  entry->program = saved_program;                  if (entry) {
121                  saved_program = NULL;                          list_add_tail_rcu(&entry->list,
122                  entry->is_not = is_not;                                            &ccs_domain_initializer_list);
123                  entry->is_last_name = is_last_name;                          error = 0;
124                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);                  }
                 entry = NULL;  
                 error = 0;  
125          }          }
126          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
127          ccs_put_name(saved_domainname);   out:
128          ccs_put_name(saved_program);          ccs_put_name(e.domainname);
129          kfree(entry);          ccs_put_name(e.program);
130          return error;          return error;
131  }  }
132    
# Line 200  static int ccs_update_domain_initializer Line 137  static int ccs_update_domain_initializer
137   *   *
138   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
139   *   *
140   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
141   */   */
142  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
143  {  {
# Line 213  bool ccs_read_domain_initializer_policy( Line 150  bool ccs_read_domain_initializer_policy(
150                  const char *domain = "";                  const char *domain = "";
151                  struct ccs_domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
152                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
153                                    list);                                   list);
154                  if (ptr->is_deleted)                  if (ptr->is_deleted)
155                          continue;                          continue;
156                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 221  bool ccs_read_domain_initializer_policy( Line 158  bool ccs_read_domain_initializer_policy(
158                          from = " from ";                          from = " from ";
159                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
160                  }                  }
161                  done = ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_INITIALIZE_DOMAIN
162                                       "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s%s%s\n", no, ptr->program->name, from,
163                                       no, ptr->program->name, from, domain);                                       domain);
164                  if (!done)                  if (!done)
165                          break;                          break;
166          }          }
# Line 262  int ccs_write_domain_initializer_policy( Line 199  int ccs_write_domain_initializer_policy(
199   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
200   * false otherwise.   * false otherwise.
201   *   *
202   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
203   */   */
204  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
205                                        const struct ccs_path_info *program,                                        const struct ccs_path_info *program,
# Line 311  static int ccs_update_domain_keeper_entr Line 248  static int ccs_update_domain_keeper_entr
248                                            const bool is_not,                                            const bool is_not,
249                                            const bool is_delete)                                            const bool is_delete)
250  {  {
         struct ccs_domain_keeper_entry *entry = NULL;  
251          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
252          const struct ccs_path_info *saved_domainname;          struct ccs_domain_keeper_entry e = { .is_not = is_not };
         const struct ccs_path_info *saved_program = NULL;  
253          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
         bool is_last_name = false;  
254          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
255              ccs_is_correct_path(domainname, 1, -1, -1))              ccs_is_correct_path(domainname, 1, -1, -1))
256                  is_last_name = true;                  e.is_last_name = true;
257          else if (!ccs_is_correct_domain(domainname))          else if (!ccs_is_correct_domain(domainname))
258                  return -EINVAL;                  return -EINVAL;
259          if (program) {          if (program) {
260                  if (!ccs_is_correct_path(program, 1, -1, -1))                  if (!ccs_is_correct_path(program, 1, -1, -1))
261                          return -EINVAL;                          return -EINVAL;
262                  saved_program = ccs_get_name(program);                  e.program = ccs_get_name(program);
263                  if (!saved_program)                  if (!e.program)
264                          return -ENOMEM;                          goto out;
         }  
         saved_domainname = ccs_get_name(domainname);  
         if (!saved_domainname) {  
                 ccs_put_name(saved_program);  
                 return -ENOMEM;  
265          }          }
266          if (!is_delete)          e.domainname = ccs_get_name(domainname);
267                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);          if (!e.domainname)
268                    goto out;
269          mutex_lock(&ccs_policy_lock);          mutex_lock(&ccs_policy_lock);
270          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
271                  if (ptr->is_not != is_not ||                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
272                      ptr->domainname != saved_domainname ||                                 sizeof(e)))
                     ptr->program != saved_program)  
273                          continue;                          continue;
274                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
275                  error = 0;                  error = 0;
276                  break;                  break;
277          }          }
278          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {          if (!is_delete && error) {
279                  entry->domainname = saved_domainname;                  struct ccs_domain_keeper_entry *entry =
280                  saved_domainname = NULL;                          ccs_commit_ok(&e, sizeof(e));
281                  entry->program = saved_program;                  if (entry) {
282                  saved_program = NULL;                          list_add_tail_rcu(&entry->list,
283                  entry->is_not = is_not;                                            &ccs_domain_keeper_list);
284                  entry->is_last_name = is_last_name;                          error = 0;
285                  list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);                  }
                 entry = NULL;  
                 error = 0;  
286          }          }
287          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
288          ccs_put_name(saved_domainname);   out:
289          ccs_put_name(saved_program);          ccs_put_name(e.domainname);
290          kfree(entry);          ccs_put_name(e.program);
291          return error;          return error;
292  }  }
293    
# Line 391  int ccs_write_domain_keeper_policy(char Line 318  int ccs_write_domain_keeper_policy(char
318   *   *
319   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
320   *   *
321   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
322   */   */
323  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
324  {  {
# Line 411  bool ccs_read_domain_keeper_policy(struc Line 338  bool ccs_read_domain_keeper_policy(struc
338                          from = " from ";                          from = " from ";
339                          program = ptr->program->name;                          program = ptr->program->name;
340                  }                  }
341                  done = ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_KEEP_DOMAIN
342                                       "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s%s%s\n", no, program, from,
343                                       program, from, ptr->domainname->name);                                       ptr->domainname->name);
344                  if (!done)                  if (!done)
345                          break;                          break;
346          }          }
# Line 430  bool ccs_read_domain_keeper_policy(struc Line 357  bool ccs_read_domain_keeper_policy(struc
357   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
358   * false otherwise.   * false otherwise.
359   *   *
360   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
361   */   */
362  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
363                                   const struct ccs_path_info *program,                                   const struct ccs_path_info *program,
# Line 459  static bool ccs_is_domain_keeper(const s Line 386  static bool ccs_is_domain_keeper(const s
386          return flag;          return flag;
387  }  }
388    
 /* The list for "struct ccs_alias_entry". */  
 LIST_HEAD(ccs_alias_list);  
   
 /**  
  * ccs_update_alias_entry - Update "struct ccs_alias_entry" list.  
  *  
  * @original_name: The original program's real name.  
  * @aliased_name:  The symbolic program's symbolic link's name.  
  * @is_delete:     True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 static int ccs_update_alias_entry(const char *original_name,  
                                   const char *aliased_name,  
                                   const bool is_delete)  
 {  
         struct ccs_alias_entry *entry = NULL;  
         struct ccs_alias_entry *ptr;  
         const struct ccs_path_info *saved_original_name;  
         const struct ccs_path_info *saved_aliased_name;  
         int error = is_delete ? -ENOENT : -ENOMEM;  
         if (!ccs_is_correct_path(original_name, 1, -1, -1) ||  
             !ccs_is_correct_path(aliased_name, 1, -1, -1))  
                 return -EINVAL; /* No patterns allowed. */  
         saved_original_name = ccs_get_name(original_name);  
         saved_aliased_name = ccs_get_name(aliased_name);  
         if (!saved_original_name || !saved_aliased_name) {  
                 ccs_put_name(saved_original_name);  
                 ccs_put_name(saved_aliased_name);  
                 return -ENOMEM;  
         }  
         if (!is_delete)  
                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);  
         mutex_lock(&ccs_policy_lock);  
         list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {  
                 if (ptr->original_name != saved_original_name ||  
                     ptr->aliased_name != saved_aliased_name)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {  
                 entry->original_name = saved_original_name;  
                 saved_original_name = NULL;  
                 entry->aliased_name = saved_aliased_name;  
                 saved_aliased_name = NULL;  
                 list_add_tail_rcu(&entry->list, &ccs_alias_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
         ccs_put_name(saved_original_name);  
         ccs_put_name(saved_aliased_name);  
         kfree(entry);  
         return error;  
 }  
   
 /**  
  * ccs_read_alias_policy - Read "struct ccs_alias_entry" list.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds srcu_read_lock(&ccs_ss).  
  */  
 bool ccs_read_alias_policy(struct ccs_io_buffer *head)  
 {  
         struct list_head *pos;  
         bool done = true;  
         list_for_each_cookie(pos, head->read_var2, &ccs_alias_list) {  
                 struct ccs_alias_entry *ptr;  
                 ptr = list_entry(pos, struct ccs_alias_entry, list);  
                 if (ptr->is_deleted)  
                         continue;  
                 done = ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",  
                                      ptr->original_name->name,  
                                      ptr->aliased_name->name);  
                 if (!done)  
                         break;  
         }  
         return done;  
 }  
   
 /**  
  * ccs_write_alias_policy - Write "struct ccs_alias_entry" list.  
  *  
  * @data:      String to parse.  
  * @is_delete: True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 int ccs_write_alias_policy(char *data, const bool is_delete)  
 {  
         char *cp = strchr(data, ' ');  
         if (!cp)  
                 return -EINVAL;  
         *cp++ = '\0';  
         return ccs_update_alias_entry(data, cp, is_delete);  
 }  
   
389  /* The list for "struct ccs_aggregator_entry". */  /* The list for "struct ccs_aggregator_entry". */
390  LIST_HEAD(ccs_aggregator_list);  LIST_HEAD(ccs_aggregator_list);
391    
# Line 577  static int ccs_update_aggregator_entry(c Line 402  static int ccs_update_aggregator_entry(c
402                                         const char *aggregated_name,                                         const char *aggregated_name,
403                                         const bool is_delete)                                         const bool is_delete)
404  {  {
         struct ccs_aggregator_entry *entry = NULL;  
405          struct ccs_aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
406          const struct ccs_path_info *saved_original_name;          struct ccs_aggregator_entry e = { };
         const struct ccs_path_info *saved_aggregated_name;  
407          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
408          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
409              !ccs_is_correct_path(aggregated_name, 1, -1, -1))              !ccs_is_correct_path(aggregated_name, 1, -1, -1))
410                  return -EINVAL;                  return -EINVAL;
411          saved_original_name = ccs_get_name(original_name);          e.original_name = ccs_get_name(original_name);
412          saved_aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
413          if (!saved_original_name || !saved_aggregated_name) {          if (!e.original_name || !e.aggregated_name)
414                  ccs_put_name(saved_original_name);                  goto out;
                 ccs_put_name(saved_aggregated_name);  
                 return -ENOMEM;  
         }  
         if (!is_delete)  
                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);  
415          mutex_lock(&ccs_policy_lock);          mutex_lock(&ccs_policy_lock);
416          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
417                  if (ptr->original_name != saved_original_name ||                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), original_name),
418                      ptr->aggregated_name != saved_aggregated_name)                                 sizeof(e)))
419                          continue;                          continue;
420                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
421                  error = 0;                  error = 0;
422                  break;                  break;
423          }          }
424          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {          if (!is_delete && error) {
425                  entry->original_name = saved_original_name;                  struct ccs_aggregator_entry *entry =
426                  saved_original_name = NULL;                          ccs_commit_ok(&e, sizeof(e));
427                  entry->aggregated_name = saved_aggregated_name;                  if (entry) {
428                  saved_aggregated_name = NULL;                          list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
429                  list_add_tail_rcu(&entry->list, &ccs_aggregator_list);                          error = 0;
430                  entry = NULL;                  }
                 error = 0;  
431          }          }
432          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
433          ccs_put_name(saved_original_name);   out:
434          ccs_put_name(saved_aggregated_name);          ccs_put_name(e.original_name);
435          kfree(entry);          ccs_put_name(e.aggregated_name);
436          return error;          return error;
437  }  }
438    
# Line 626  static int ccs_update_aggregator_entry(c Line 443  static int ccs_update_aggregator_entry(c
443   *   *
444   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
445   *   *
446   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
447   */   */
448  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
449  {  {
# Line 637  bool ccs_read_aggregator_policy(struct c Line 454  bool ccs_read_aggregator_policy(struct c
454                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);
455                  if (ptr->is_deleted)                  if (ptr->is_deleted)
456                          continue;                          continue;
457                  done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, CCS_KEYWORD_AGGREGATOR "%s %s\n",
458                                       ptr->original_name->name,                                       ptr->original_name->name,
459                                       ptr->aggregated_name->name);                                       ptr->aggregated_name->name);
460                  if (!done)                  if (!done)
# Line 656  bool ccs_read_aggregator_policy(struct c Line 473  bool ccs_read_aggregator_policy(struct c
473   */   */
474  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator_policy(char *data, const bool is_delete)
475  {  {
476          char *cp = strchr(data, ' ');          char *w[2];
477          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
478                  return -EINVAL;                  return -EINVAL;
479          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return ccs_update_aggregator_entry(data, cp, is_delete);  
480  }  }
481    
482  /* Domain create/delete handler. */  /* Domain create/delete handler. */
# Line 709  struct ccs_domain_info *ccs_find_or_assi Line 525  struct ccs_domain_info *ccs_find_or_assi
525          struct ccs_domain_info *domain;          struct ccs_domain_info *domain;
526          const struct ccs_path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
527          bool found = false;          bool found = false;
528    
529          if (!ccs_is_correct_domain(domainname))          if (!ccs_is_correct_domain(domainname))
530                  return NULL;                  return NULL;
531          saved_domainname = ccs_get_name(domainname);          saved_domainname = ccs_get_name(domainname);
532          if (!saved_domainname)          if (!saved_domainname)
533                  return NULL;                  return NULL;
534          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
535          mutex_lock(&ccs_policy_lock);          mutex_lock(&ccs_policy_lock);
536          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
537                  if (domain->is_deleted ||                  if (domain->is_deleted ||
# Line 741  struct ccs_domain_info *ccs_find_or_assi Line 557  struct ccs_domain_info *ccs_find_or_assi
557  }  }
558    
559  /**  /**
  * ccs_get_argv0 - Get argv[0].  
  *  
  * @ee: Pointer to "struct ccs_execve_entry".  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_get_argv0(struct ccs_execve_entry *ee)  
 {  
         struct linux_binprm *bprm = ee->bprm;  
         char *arg_ptr = ee->tmp;  
         int arg_len = 0;  
         unsigned long pos = bprm->p;  
         int offset = pos % PAGE_SIZE;  
         bool done = false;  
         if (!bprm->argc)  
                 goto out;  
         while (1) {  
                 if (!ccs_dump_page(bprm, pos, &ee->dump))  
                         goto out;  
                 pos += PAGE_SIZE - offset;  
                 /* Read. */  
                 while (offset < PAGE_SIZE) {  
                         const char *kaddr = ee->dump.data;  
                         const unsigned char c = kaddr[offset++];  
                         if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {  
                                 if (c == '\\') {  
                                         arg_ptr[arg_len++] = '\\';  
                                         arg_ptr[arg_len++] = '\\';  
                                 } else if (c == '/') {  
                                         arg_len = 0;  
                                 } else if (c > ' ' && c < 127) {  
                                         arg_ptr[arg_len++] = c;  
                                 } else {  
                                         arg_ptr[arg_len++] = '\\';  
                                         arg_ptr[arg_len++] = (c >> 6) + '0';  
                                         arg_ptr[arg_len++]  
                                                 = ((c >> 3) & 7) + '0';  
                                         arg_ptr[arg_len++] = (c & 7) + '0';  
                                 }  
                         } else {  
                                 arg_ptr[arg_len] = '\0';  
                                 done = true;  
                                 break;  
                         }  
                 }  
                 offset = 0;  
                 if (done)  
                         break;  
         }  
         return true;  
  out:  
         return false;  
 }  
   
 /**  
560   * ccs_find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
561   *   *
562   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
563   *   *
564   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
565   *   *
566   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
567   */   */
568  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve_entry *ee)
569  {  {
# Line 811  static int ccs_find_next_domain(struct c Line 572  static int ccs_find_next_domain(struct c
572          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
573          const char *old_domain_name = r->domain->domainname->name;          const char *old_domain_name = r->domain->domainname->name;
574          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
         const u8 mode = r->mode;  
         const bool is_enforce = (mode == 3);  
575          const u32 ccs_flags = current->ccs_flags;          const u32 ccs_flags = current->ccs_flags;
576          char *new_domain_name = NULL;          struct ccs_path_info rn = { }; /* real name */
         struct ccs_path_info rn; /* real name */  
         struct ccs_path_info sn; /* symlink name */  
577          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
578          int retval;          int retval;
579            bool need_kfree = false;
580            ln.name = ccs_last_word(old_domain_name);
581            ccs_fill_path_info(&ln);
582   retry:   retry:
583          current->ccs_flags = ccs_flags;          current->ccs_flags = ccs_flags;
584          r->cond = NULL;          r->cond = NULL;
585          /* Get realpath of program and symbolic link. */          if (need_kfree) {
586          retval = ccs_realpath_both(bprm->filename, ee);                  kfree(rn.name);
587                    need_kfree = false;
588            }
589    
590            /* Get symlink's pathname of program. */
591            retval = ccs_symlink_path(bprm->filename, &rn);
592          if (retval < 0)          if (retval < 0)
593                  goto out;                  goto out;
594            need_kfree = true;
         rn.name = ee->program_path;  
         ccs_fill_path_info(&rn);  
         sn.name = ee->tmp;  
         ccs_fill_path_info(&sn);  
         ln.name = ccs_get_last_name(r->domain);  
         ccs_fill_path_info(&ln);  
595    
596          if (handler) {          if (handler) {
597                  if (ccs_pathcmp(&rn, handler)) {                  if (ccs_pathcmp(&rn, handler)) {
# Line 845  static int ccs_find_next_domain(struct c Line 604  static int ccs_find_next_domain(struct c
604                          }                          }
605                          goto out;                          goto out;
606                  }                  }
607                  goto calculate_domain;          } else {
         }  
   
         /* Check 'alias' directive. */  
         if (ccs_pathcmp(&rn, &sn)) {  
                 struct ccs_alias_entry *ptr;  
                 /* Is this program allowed to be called via symbolic links? */  
                 list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {  
                         if (ptr->is_deleted ||  
                             ccs_pathcmp(&rn, ptr->original_name) ||  
                             ccs_pathcmp(&sn, ptr->aliased_name))  
                                 continue;  
                         strncpy(ee->program_path, ptr->aliased_name->name,  
                                 CCS_MAX_PATHNAME_LEN - 1);  
                         ccs_fill_path_info(&rn);  
                         break;  
                 }  
         }  
         /* sn will be overwritten after here. */  
   
         /* Compare basename of program_path and argv[0] */  
         r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);  
         if (bprm->argc > 0 && r->mode) {  
                 char *base_argv0 = ee->tmp;  
                 const char *base_filename;  
                 retval = -ENOMEM;  
                 if (!ccs_get_argv0(ee))  
                         goto out;  
                 base_filename = strrchr(ee->program_path, '/');  
                 if (!base_filename)  
                         base_filename = ee->program_path;  
                 else  
                         base_filename++;  
                 if (strcmp(base_argv0, base_filename)) {  
                         retval = ccs_check_argv0_perm(r, &rn, base_argv0);  
                         if (retval == 1)  
                                 goto retry;  
                         if (retval < 0)  
                                 goto out;  
                 }  
         }  
   
         /* Check 'aggregator' directive. */  
         {  
608                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
609                  /* Is this program allowed to be aggregated? */                  /* Check 'aggregator' directive. */
610                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
611                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
612                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
613                                  continue;                                  continue;
614                          strncpy(ee->program_path, ptr->aggregated_name->name,                          kfree(rn.name);
615                                  CCS_MAX_PATHNAME_LEN - 1);                          need_kfree = false;
616                          ccs_fill_path_info(&rn);                          /* This is OK because it is read only. */
617                            rn = *ptr->aggregated_name;
618                          break;                          break;
619                  }                  }
         }  
620    
621          /* Check execute permission. */                  /* Check execute permission. */
622          r->mode = mode;                  retval = ccs_exec_perm(r, &rn);
623          retval = ccs_check_exec_perm(r, &rn);                  if (retval == CCS_RETRY_REQUEST)
624          if (retval == 1)                          goto retry;
625                  goto retry;                  if (retval < 0)
626          if (retval < 0)                          goto out;
627                  goto out;          }
628    
629   calculate_domain:          /* Calculate domain to transit to. */
         new_domain_name = ee->tmp;  
630          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
631                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
632                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
633                           ROOT_NAME " " "%s", ee->program_path);                           rn.name);
634          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
635                  /*                  /*
636                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
# Line 928  static int ccs_find_next_domain(struct c Line 643  static int ccs_find_next_domain(struct c
643                  domain = r->domain;                  domain = r->domain;
644          } else {          } else {
645                  /* Normal domain transition. */                  /* Normal domain transition. */
646                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
647                           "%s %s", old_domain_name, ee->program_path);                           old_domain_name, rn.name);
648          }          }
649          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
650                  goto done;                  goto done;
651          domain = ccs_find_domain(new_domain_name);          domain = ccs_find_domain(ee->tmp);
652          if (domain)          if (domain)
653                  goto done;                  goto done;
654          if (is_enforce) {          if (r->mode == CCS_CONFIG_ENFORCING) {
655                  int error = ccs_check_supervisor(r,                  int error = ccs_supervisor(r, "# wants to create domain\n"
656                                                   "# wants to create domain\n"                                             "%s\n", ee->tmp);
657                                                   "%s\n", new_domain_name);                  if (error == CCS_RETRY_REQUEST)
                 if (error == 1)  
658                          goto retry;                          goto retry;
659                  if (error < 0)                  if (error < 0)
660                          goto done;                          goto done;
661          }          }
662          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);
663          if (domain)          if (domain)
664                  ccs_audit_domain_creation_log(r->domain);                  ccs_audit_domain_creation_log(domain);
665   done:   done:
666          if (!domain) {          if (!domain) {
667                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
668                         new_domain_name);                  if (!r->domain->domain_transition_failed) {
                 if (is_enforce)  
                         retval = -EPERM;  
                 else {  
                         retval = 0;  
669                          r->domain->domain_transition_failed = true;                          r->domain->domain_transition_failed = true;
670                            ccs_write_audit_log(false, r,
671                                                CCS_KEYWORD_TRANSITION_FAILED
672                                                "\n");
673                            printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
674                                   ee->tmp);
675                  }                  }
676          } else {          } else {
677                  retval = 0;                  retval = 0;
678          }          }
679   out:   out:
680          if (domain)          if (domain)
681                  r->domain = domain;                  r->domain = domain;
682            if (need_kfree)
683                    kfree(rn.name);
684          return retval;          return retval;
685  }  }
686    
687  /**  /**
688   * ccs_check_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
689   *   *
690   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
691   *   *
692   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
693   */   */
694  static int ccs_check_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve_entry *ee)
695  {  {
696          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
697          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
698          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
699            struct ccs_page_dump env_page = { };
700            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
701          int arg_len = 0;          int arg_len = 0;
702          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
703          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 988  static int ccs_check_environ(struct ccs_ Line 707  static int ccs_check_environ(struct ccs_
707          int error = -ENOMEM;          int error = -ENOMEM;
708          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
709                  return 0;                  return 0;
710            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
711            if (!arg_ptr)
712                    goto out;
713          while (error == -ENOMEM) {          while (error == -ENOMEM) {
714                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
715                          goto out;                          goto out;
716                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
717                  /* Read. */                  /* Read. */
718                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
719                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
720                                  argv_count--;                                  argv_count--;
721                  }                  }
722                  if (argv_count) {                  if (argv_count) {
# Line 1003  static int ccs_check_environ(struct ccs_ Line 724  static int ccs_check_environ(struct ccs_
724                          continue;                          continue;
725                  }                  }
726                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
727                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
728                          const unsigned char c = kaddr[offset++];                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
                         if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {  
729                                  if (c == '=') {                                  if (c == '=') {
730                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
731                                  } else if (c == '\\') {                                  } else if (c == '\\') {
# Line 1025  static int ccs_check_environ(struct ccs_ Line 745  static int ccs_check_environ(struct ccs_
745                          }                          }
746                          if (c)                          if (c)
747                                  continue;                                  continue;
748                          if (ccs_check_env_perm(r, arg_ptr)) {                          if (ccs_env_perm(r, arg_ptr)) {
749                                  error = -EPERM;                                  error = -EPERM;
750                                  break;                                  break;
751                          }                          }
# Line 1040  static int ccs_check_environ(struct ccs_ Line 760  static int ccs_check_environ(struct ccs_
760   out:   out:
761          if (r->mode != 3)          if (r->mode != 3)
762                  error = 0;                  error = 0;
763            kfree(env_page.data);
764            kfree(arg_ptr);
765          return error;          return error;
766  }  }
767    
# Line 1093  static void ccs_unescape(unsigned char * Line 815  static void ccs_unescape(unsigned char *
815  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
816  {  {
817          int depth = 0;          int depth = 0;
         /***** CRITICAL SECTION START *****/  
818          ccs_realpath_lock();          ccs_realpath_lock();
819          for (;;) {          for (;;) {
820                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
# Line 1108  static inline int ccs_root_depth(struct Line 829  static inline int ccs_root_depth(struct
829                  depth++;                  depth++;
830          }          }
831          ccs_realpath_unlock();          ccs_realpath_unlock();
         /***** CRITICAL SECTION END *****/  
832          return depth;          return depth;
833  }  }
834    
# Line 1125  static int ccs_get_root_depth(void) Line 845  static int ccs_get_root_depth(void)
845  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
846          struct path root;          struct path root;
847  #endif  #endif
         /***** CRITICAL SECTION START *****/  
848          read_lock(&current->fs->lock);          read_lock(&current->fs->lock);
849  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
850          root = current->fs->root;          root = current->fs->root;
# Line 1137  static int ccs_get_root_depth(void) Line 856  static int ccs_get_root_depth(void)
856          vfsmnt = mntget(current->fs->rootmnt);          vfsmnt = mntget(current->fs->rootmnt);
857  #endif  #endif
858          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
         /***** CRITICAL SECTION END *****/  
859          depth = ccs_root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
860  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
861          path_put(&root);          path_put(&root);
# Line 1148  static int ccs_get_root_depth(void) Line 866  static int ccs_get_root_depth(void)
866          return depth;          return depth;
867  }  }
868    
 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;  
         memset(ee, 0, sizeof(*ee));  
         ee->program_path = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);  
         ee->tmp = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);  
         if (!ee->program_path || !ee->tmp) {  
                 kfree(ee->program_path);  
                 kfree(ee->tmp);  
                 kfree(ee);  
                 return NULL;  
         }  
         ee->srcu_idx = srcu_read_lock(&ccs_ss);  
         /* ee->dump->data is allocated by ccs_dump_page(). */  
         ee->task = current;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_add(&ee->list, &ccs_execve_list);  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         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;  
         /***** CRITICAL SECTION START *****/  
         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);  
         /***** CRITICAL SECTION END *****/  
         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;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_del(&ee->list);  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         kfree(ee->program_path);  
         kfree(ee->tmp);  
         kfree(ee->dump.data);  
         srcu_read_unlock(&ccs_ss, ee->srcu_idx);  
         kfree(ee);  
 }  
   
869  /**  /**
870   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
871   *   *
# Line 1278  static int ccs_try_alt_exec(struct ccs_e Line 919  static int ccs_try_alt_exec(struct ccs_e
919          struct task_struct *task = current;          struct task_struct *task = current;
920    
921          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
922            ee->obj.path1.dentry = NULL;
923            ee->obj.path1.mnt = NULL;
924            ee->obj.validate_done = false;
925          allow_write_access(bprm->file);          allow_write_access(bprm->file);
926          fput(bprm->file);          fput(bprm->file);
927          bprm->file = NULL;          bprm->file = NULL;
# Line 1325  static int ccs_try_alt_exec(struct ccs_e Line 969  static int ccs_try_alt_exec(struct ccs_e
969                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
970                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
971                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
972                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           (pid_t) ccsecurity_exports.sys_getpid(),
973                           current_euid(), current_egid(), current_suid(),                           current_uid(), current_gid(), current_euid(),
974                           current_sgid(), current_fsuid(), current_fsgid(),                           current_egid(), current_suid(), current_sgid(),
975                             current_fsuid(), current_fsgid(),
976                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
977                           (u8) (ccs_flags >> 8));                           (u8) (ccs_flags >> 8));
978                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
# Line 1344  static int ccs_try_alt_exec(struct ccs_e Line 989  static int ccs_try_alt_exec(struct ccs_e
989                          kfree(exe);                          kfree(exe);
990                  } else {                  } else {
991                          exe = ee->tmp;                          exe = ee->tmp;
992                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
993                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
994                  }                  }
995                  if (retval < 0)                  if (retval < 0)
# Line 1355  static int ccs_try_alt_exec(struct ccs_e Line 1000  static int ccs_try_alt_exec(struct ccs_e
1000          /* Set argv[1] */          /* Set argv[1] */
1001          {          {
1002                  char *cp = ee->tmp;                  char *cp = ee->tmp;
1003                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1004                          CCS_EXEC_TMPSIZE - 1);                           ccs_current_domain()->domainname->name);
1005                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1006                  if (retval < 0)                  if (retval < 0)
1007                          goto out;                          goto out;
# Line 1366  static int ccs_try_alt_exec(struct ccs_e Line 1011  static int ccs_try_alt_exec(struct ccs_e
1011          /* Set argv[0] */          /* Set argv[0] */
1012          {          {
1013                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
1014                  char *cp = ee->program_path;                  int len = ee->handler->total_len + 1;
1015                  strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);                  char *cp = kmalloc(len, CCS_GFP_FLAGS);
1016                    if (!cp) {
1017                            retval = -ENOMEM;
1018                            goto out;
1019                    }
1020                    ee->handler_path = cp;
1021                    memmove(cp, ee->handler->name, len);
1022                  ccs_unescape(cp);                  ccs_unescape(cp);
1023                  retval = -ENOENT;                  retval = -ENOENT;
1024                  if (!*cp || *cp != '/')                  if (!*cp || *cp != '/')
# Line 1379  static int ccs_try_alt_exec(struct ccs_e Line 1030  static int ccs_try_alt_exec(struct ccs_e
1030                                  goto out;                                  goto out;
1031                          depth--;                          depth--;
1032                  }                  }
1033                  memmove(ee->program_path, cp, strlen(cp) + 1);                  memmove(ee->handler_path, cp, strlen(cp) + 1);
1034                  cp = ee->program_path;                  cp = ee->handler_path;
1035                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1036                  if (retval < 0)                  if (retval < 0)
1037                          goto out;                          goto out;
# Line 1393  static int ccs_try_alt_exec(struct ccs_e Line 1044  static int ccs_try_alt_exec(struct ccs_e
1044  #endif  #endif
1045    
1046          /* OK, now restart the process with execute handler program's dentry. */          /* OK, now restart the process with execute handler program's dentry. */
1047          filp = open_exec(ee->program_path);          filp = open_exec(ee->handler_path);
1048          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1049                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1050                  goto out;                  goto out;
1051          }          }
1052            ee->obj.path1.dentry = filp->f_dentry;
1053            ee->obj.path1.mnt = filp->f_vfsmnt;
1054          bprm->file = filp;          bprm->file = filp;
1055          bprm->filename = ee->program_path;          bprm->filename = ee->handler_path;
1056  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1057          bprm->interp = bprm->filename;          bprm->interp = bprm->filename;
1058  #endif  #endif
1059          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1060          if (retval < 0)          if (retval < 0)
1061                  goto out;                  goto out;
1062          {          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1063                  /*          retval = ccs_find_next_domain(ee);
1064                   * Backup ee->program_path because ccs_find_next_domain() will          task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
                  * overwrite ee->program_path and ee->tmp.  
                  */  
                 const int len = strlen(ee->program_path) + 1;  
                 char *cp = kzalloc(len, GFP_KERNEL);  
                 if (!cp) {  
                         retval = -ENOMEM;  
                         goto out;  
                 }  
                 memmove(cp, ee->program_path, len);  
                 bprm->filename = cp;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
                 bprm->interp = bprm->filename;  
 #endif  
                 task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
                 retval = ccs_find_next_domain(ee);  
                 task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
                 /* Restore ee->program_path for search_binary_handler(). */  
                 memmove(ee->program_path, cp, len);  
                 bprm->filename = ee->program_path;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
                 bprm->interp = bprm->filename;  
 #endif  
                 kfree(cp);  
         }  
1065   out:   out:
1066          return retval;          return retval;
1067  }  }
# Line 1445  static int ccs_try_alt_exec(struct ccs_e Line 1074  static int ccs_try_alt_exec(struct ccs_e
1074   *   *
1075   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1076   *   *
1077   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
1078   */   */
1079  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1080                                       const u8 type)                                       const u8 type)
# Line 1486  bool ccs_dump_page(struct linux_binprm * Line 1115  bool ccs_dump_page(struct linux_binprm *
1115                     struct ccs_page_dump *dump)                     struct ccs_page_dump *dump)
1116  {  {
1117          struct page *page;          struct page *page;
1118          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_finish_execve(). */
1119          if (!dump->data) {          if (!dump->data) {
1120                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1121                  if (!dump->data)                  if (!dump->data)
1122                          return false;                          return false;
1123          }          }
# Line 1496  bool ccs_dump_page(struct linux_binprm * Line 1125  bool ccs_dump_page(struct linux_binprm *
1125  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1126          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)
1127                  return false;                  return false;
1128  #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)
1129            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1130                    return false;
1131    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1132          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)
1133                  return false;                  return false;
1134  #else  #else
# Line 1517  bool ccs_dump_page(struct linux_binprm * Line 1149  bool ccs_dump_page(struct linux_binprm *
1149          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1150  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1151          put_page(page);          put_page(page);
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            put_page(page);
1154    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1155          put_page(page);          put_page(page);
1156  #endif  #endif
1157          return true;          return true;
1158  }  }
1159    
1160  /**  /**
  * 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;  
 }  
   
 /**  
1161   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1162   *   *
1163   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1164     * @eep:  Pointer to "struct ccs_execve_entry *".
1165   *   *
1166   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1167   */   */
1168  int ccs_start_execve(struct linux_binprm *bprm)  static int ccs_start_execve(struct linux_binprm *bprm,
1169                                struct ccs_execve_entry **eep)
1170  {  {
1171          int retval;          int retval;
1172          struct task_struct *task = current;          struct task_struct *task = current;
1173          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();          struct ccs_execve_entry *ee;
1174          if (!ccs_policy_loaded)          *eep = NULL;
1175                  ccs_load_policy(bprm->filename);          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1176          if (!ee)          if (!ee)
1177                  return -ENOMEM;                  return -ENOMEM;
1178          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1179            if (!ee->tmp) {
1180                    kfree(ee);
1181                    return -ENOMEM;
1182            }
1183            ee->reader_idx = ccs_read_lock();
1184            /* ee->dump->data is allocated by ccs_dump_page(). */
1185            ee->previous_domain = task->ccs_domain_info;
1186            /* Clear manager flag. */
1187            task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1188            *eep = ee;
1189            ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);
1190          ee->r.ee = ee;          ee->r.ee = ee;
1191          ee->bprm = bprm;          ee->bprm = bprm;
1192          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1193          ee->obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1194          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1195          /* Clear manager flag. */          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {
         task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;  
         if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {  
1196                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1197                  if (!retval)                  if (!retval)
1198                          ccs_audit_execute_handler_log(ee, true);                          ccs_audit_execute_handler_log(ee, true);
# Line 1573  int ccs_start_execve(struct linux_binprm Line 1201  int ccs_start_execve(struct linux_binprm
1201          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1202          if (retval != -EPERM)          if (retval != -EPERM)
1203                  goto ok;                  goto ok;
1204          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1205                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1206                  if (!retval)                  if (!retval)
1207                          ccs_audit_execute_handler_log(ee, false);                          ccs_audit_execute_handler_log(ee, false);
# Line 1581  int ccs_start_execve(struct linux_binprm Line 1209  int ccs_start_execve(struct linux_binprm
1209   ok:   ok:
1210          if (retval < 0)          if (retval < 0)
1211                  goto out;                  goto out;
1212          ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);          /*
1213          retval = ccs_check_environ(ee);           * Tell GC that I started execve().
1214             * Also, tell open_exec() to check read permission.
1215             */
1216            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
1217            /*
1218             * Make task->ccs_flags visible to GC before changing
1219             * task->ccs_domain_info .
1220             */
1221            smp_mb();
1222            /*
1223             * Proceed to the next domain in order to allow reaching via PID.
1224             * It will be reverted if execve() failed. Reverting is not good.
1225             * But it is better than being unable to reach via PID in interactive
1226             * enforcing mode.
1227             */
1228            task->ccs_domain_info = ee->r.domain;
1229            ee->r.mode = ccs_get_mode(ee->r.domain->profile, CCS_MAC_ENVIRON);
1230            retval = ccs_environ(ee);
1231          if (retval < 0)          if (retval < 0)
1232                  goto out;                  goto out;
         task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;  
1233          retval = 0;          retval = 0;
1234   out:   out:
         if (retval)  
                 ccs_finish_execve(retval);  
1235          return retval;          return retval;
1236  }  }
1237    
# Line 1597  int ccs_start_execve(struct linux_binprm Line 1239  int ccs_start_execve(struct linux_binprm
1239   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1240   *   *
1241   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1242     * @ee:     Pointer to "struct ccs_execve_entry".
1243   *   *
1244   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
1245   */   */
1246  void ccs_finish_execve(int retval)  static void ccs_finish_execve(int retval, struct ccs_execve_entry *ee)
1247  {  {
1248          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;  
1249          if (!ee)          if (!ee)
1250                  return;                  return;
1251          if (retval < 0)          if (retval < 0) {
1252                  goto out;                  task->ccs_domain_info = ee->previous_domain;
1253          /* Proceed to next domain if execution suceeded. */                  /*
1254          task->ccs_domain_info = ee->r.domain;                   * Make task->ccs_domain_info visible to GC before changing
1255          /* Mark the current process as execute handler. */                   * task->ccs_flags .
1256          if (ee->handler)                   */
1257                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  smp_mb();
1258          /* Mark the current process as normal process. */          } else {
1259          else                  /* Mark the current process as execute handler. */
1260                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                  if (ee->handler)
1261   out:                          task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1262          ccs_free_execve_entry(ee);                  /* Mark the current process as normal process. */
1263                    else
1264                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1265            }
1266            /* Tell GC that I finished execve(). */
1267            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1268            ccs_read_unlock(ee->reader_idx);
1269            kfree(ee->handler_path);
1270            kfree(ee->tmp);
1271            kfree(ee->dump.data);
1272            kfree(ee);
1273    }
1274    
1275    /**
1276     * ccs_may_transit - Check permission and do domain transition without execve().
1277     *
1278     * @domainname: Domainname to transit to.
1279     * @pathname: Pathname to check.
1280     *
1281     * Returns 0 on success, negative value otherwise.
1282     *
1283     * Caller holds ccs_read_lock().
1284     */
1285    int ccs_may_transit(const char *domainname, const char *pathname)
1286    {
1287            struct ccs_path_info name;
1288            struct ccs_request_info r;
1289            struct ccs_domain_info *domain;
1290            int error;
1291            name.name = pathname;
1292            ccs_fill_path_info(&name);
1293            /* Check allow_transit permission. */
1294            ccs_init_request_info(&r, NULL, 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                            ccs_audit_domain_creation_log(domain);
1305            }
1306            if (domain) {
1307                    error = 0;
1308                    current->ccs_domain_info = domain;
1309            } else {
1310                    error = -ENOENT;
1311            }
1312            return error;
1313    }
1314    
1315    static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1316                                           struct pt_regs *regs)
1317    {
1318            struct ccs_execve_entry *ee;
1319            int retval;
1320            if (!ccs_policy_loaded)
1321                    ccsecurity_exports.load_policy(bprm->filename);
1322            retval = ccs_start_execve(bprm, &ee);
1323            if (!retval)
1324                    retval = search_binary_handler(bprm, regs);
1325            ccs_finish_execve(retval, ee);
1326            return retval;
1327    }
1328    
1329    void __init ccs_domain_init(void)
1330    {
1331            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1332  }  }

Legend:
Removed from v.2718  
changed lines
  Added in v.3519

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