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

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 2577 by kumaneko, Thu May 21 08:25:02 2009 UTC trunk/1.7.x/ccs-patch/security/ccsecurity/domain.c revision 2951 by kumaneko, Tue Aug 25 04:26:20 2009 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_domain.c   * security/ccsecurity/domain.c
  *  
  * Implementation of the Domain-Based Mandatory Access Control.  
3   *   *
4   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Copyright (C) 2005-2009  NTT DATA CORPORATION
5   *   *
6   * Version: 1.6.8-pre   2009/05/08   * Version: 1.7.0-pre   2009/08/24
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"
24    
25  /* For compatibility with older kernels. */  /* For compatibility with older kernels. */
26  #ifndef for_each_process  #ifndef for_each_process
# Line 37  struct ccs_domain_info ccs_kernel_domain Line 35  struct ccs_domain_info ccs_kernel_domain
35  /* The list for "struct ccs_domain_info". */  /* The list for "struct ccs_domain_info". */
36  LIST_HEAD(ccs_domain_list);  LIST_HEAD(ccs_domain_list);
37    
 #ifdef CONFIG_TOMOYO  
   
 /**  
  * 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(&acl->list, &domain->acl_info_list);  
         } else {  
                 acl->type &= ~ACL_DELETED;  
         }  
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
         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;  
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
         return 0;  
 }  
   
38  /**  /**
39   * ccs_audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
40   *   *
# Line 104  static int ccs_audit_execute_handler_log Line 48  static int ccs_audit_execute_handler_log
48  {  {
49          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
50          const char *handler = ee->handler->name;          const char *handler = ee->handler->name;
51          r->mode = ccs_check_flags(r->cookie.u.domain, CCS_MAC_FOR_FILE);          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
52          return ccs_write_audit_log(true, r, "%s %s\n",          return ccs_write_audit_log(true, r, "%s %s\n",
53                                     is_default ? KEYWORD_EXECUTE_HANDLER :                                     is_default ? CCS_KEYWORD_EXECUTE_HANDLER :
54                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);                                     CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);
55  }  }
56    
57  /**  /**
# Line 121  static int ccs_audit_domain_creation_log Line 65  static int ccs_audit_domain_creation_log
65  {  {
66          int error;          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);          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
         ccs_exit_request_info(&r);  
70          return error;          return error;
71  }  }
72    
# Line 147  static int ccs_update_domain_initializer Line 90  static int ccs_update_domain_initializer
90  {  {
91          struct ccs_domain_initializer_entry *entry = NULL;          struct ccs_domain_initializer_entry *entry = NULL;
92          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
93          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;  
94          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
         bool is_last_name = false;  
95          if (!ccs_is_correct_path(program, 1, -1, -1))          if (!ccs_is_correct_path(program, 1, -1, -1))
96                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
97          if (domainname) {          if (domainname) {
98                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
99                      ccs_is_correct_path(domainname, 1, -1, -1))                      ccs_is_correct_path(domainname, 1, -1, -1))
100                          is_last_name = true;                          e.is_last_name = true;
101                  else if (!ccs_is_correct_domain(domainname))                  else if (!ccs_is_correct_domain(domainname))
102                          return -EINVAL;                          return -EINVAL;
103                  saved_domainname = ccs_get_name(domainname);                  e.domainname = ccs_get_name(domainname);
104                  if (!saved_domainname)                  if (!e.domainname)
105                          return -ENOMEM;                          goto out;
         }  
         saved_program = ccs_get_name(program);  
         if (!saved_program) {  
                 ccs_put_name(saved_domainname);  
                 return -ENOMEM;  
106          }          }
107            e.program = ccs_get_name(program);
108            if (!e.program)
109                    goto out;
110          if (!is_delete)          if (!is_delete)
111                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);                  entry = kmalloc(sizeof(e), GFP_KERNEL);
112          /***** WRITER SECTION START *****/          mutex_lock(&ccs_policy_lock);
113          down_write(&ccs_policy_lock);          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
114          list_for_each_entry(ptr, &ccs_domain_initializer_list, list) {                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
115                  if (ptr->is_not != is_not ||                                 sizeof(e)))
                     ptr->domainname != saved_domainname ||  
                     ptr->program != saved_program)  
116                          continue;                          continue;
117                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
118                  error = 0;                  error = 0;
119                  break;                  break;
120          }          }
121          if (!is_delete && error && ccs_memory_ok(entry)) {          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
122                  entry->domainname = saved_domainname;                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);
                 saved_domainname = NULL;  
                 entry->program = saved_program;  
                 saved_program = NULL;  
                 entry->is_not = is_not;  
                 entry->is_last_name = is_last_name;  
                 list_add_tail(&entry->list, &ccs_domain_initializer_list);  
123                  entry = NULL;                  entry = NULL;
124                  error = 0;                  error = 0;
125          }          }
126          up_write(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
127          /***** WRITER SECTION END *****/   out:
128          ccs_put_name(saved_domainname);          ccs_put_name(e.domainname);
129          ccs_put_name(saved_program);          ccs_put_name(e.program);
130          kfree(entry);          kfree(entry);
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
131          return error;          return error;
132  }  }
133    
# Line 207  static int ccs_update_domain_initializer Line 137  static int ccs_update_domain_initializer
137   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
138   *   *
139   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
140     *
141     * Caller holds ccs_read_lock().
142   */   */
143  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
144  {  {
145          struct list_head *pos;          struct list_head *pos;
146          bool done = true;          bool done = true;
147          /***** READER SECTION START *****/          list_for_each_cookie(pos, head->read_var2,
148          down_read(&ccs_policy_lock);                               &ccs_domain_initializer_list) {
         list_for_each_cookie(pos, head->read_var2.u.list,  
                               &ccs_domain_initializer_list) {  
149                  const char *no;                  const char *no;
150                  const char *from = "";                  const char *from = "";
151                  const char *domain = "";                  const char *domain = "";
152                  struct ccs_domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
153                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
154                                    list);                                   list);
155                  if (ptr->is_deleted)                  if (ptr->is_deleted)
156                          continue;                          continue;
157                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 229  bool ccs_read_domain_initializer_policy( Line 159  bool ccs_read_domain_initializer_policy(
159                          from = " from ";                          from = " from ";
160                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
161                  }                  }
162                  done = ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_INITIALIZE_DOMAIN
163                                       "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s%s%s\n", no, ptr->program->name, from,
164                                       no, ptr->program->name, from, domain);                                       domain);
165                  if (!done)                  if (!done)
166                          break;                          break;
167          }          }
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
168          return done;          return done;
169  }  }
170    
# Line 271  int ccs_write_domain_initializer_policy( Line 199  int ccs_write_domain_initializer_policy(
199   *   *
200   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
201   * false otherwise.   * false otherwise.
202     *
203     * Caller holds ccs_read_lock().
204   */   */
205  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
206                                        const struct ccs_path_info *program,                                        const struct ccs_path_info *program,
# Line 278  static bool ccs_is_domain_initializer(co Line 208  static bool ccs_is_domain_initializer(co
208  {  {
209          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
210          bool flag = false;          bool flag = false;
211          /***** READER SECTION START *****/          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
         down_read(&ccs_policy_lock);  
         list_for_each_entry(ptr, &ccs_domain_initializer_list, list) {  
212                  if (ptr->is_deleted)                  if (ptr->is_deleted)
213                          continue;                          continue;
214                  if (ptr->domainname) {                  if (ptr->domainname) {
# Line 300  static bool ccs_is_domain_initializer(co Line 228  static bool ccs_is_domain_initializer(co
228                  }                  }
229                  flag = true;                  flag = true;
230          }          }
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
231          return flag;          return flag;
232  }  }
233    
# Line 325  static int ccs_update_domain_keeper_entr Line 251  static int ccs_update_domain_keeper_entr
251  {  {
252          struct ccs_domain_keeper_entry *entry = NULL;          struct ccs_domain_keeper_entry *entry = NULL;
253          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
254          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;  
255          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
         bool is_last_name = false;  
256          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
257              ccs_is_correct_path(domainname, 1, -1, -1))              ccs_is_correct_path(domainname, 1, -1, -1))
258                  is_last_name = true;                  e.is_last_name = true;
259          else if (!ccs_is_correct_domain(domainname))          else if (!ccs_is_correct_domain(domainname))
260                  return -EINVAL;                  return -EINVAL;
261          if (program) {          if (program) {
262                  if (!ccs_is_correct_path(program, 1, -1, -1))                  if (!ccs_is_correct_path(program, 1, -1, -1))
263                          return -EINVAL;                          return -EINVAL;
264                  saved_program = ccs_get_name(program);                  e.program = ccs_get_name(program);
265                  if (!saved_program)                  if (!e.program)
266                          return -ENOMEM;                          goto out;
         }  
         saved_domainname = ccs_get_name(domainname);  
         if (!saved_domainname) {  
                 ccs_put_name(saved_program);  
                 return -ENOMEM;  
267          }          }
268            e.domainname = ccs_get_name(domainname);
269            if (!e.domainname)
270                    goto out;
271          if (!is_delete)          if (!is_delete)
272                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);                  entry = kmalloc(sizeof(e), GFP_KERNEL);
273          /***** WRITER SECTION START *****/          mutex_lock(&ccs_policy_lock);
274          down_write(&ccs_policy_lock);          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
275          list_for_each_entry(ptr, &ccs_domain_keeper_list, list) {                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
276                  if (ptr->is_not != is_not ||                                 sizeof(e)))
                     ptr->domainname != saved_domainname ||  
                     ptr->program != saved_program)  
277                          continue;                          continue;
278                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
279                  error = 0;                  error = 0;
280                  break;                  break;
281          }          }
282          if (!is_delete && error && ccs_memory_ok(entry)) {          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
283                  entry->domainname = saved_domainname;                  list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);
                 saved_domainname = NULL;  
                 entry->program = saved_program;  
                 saved_program = NULL;  
                 entry->is_not = is_not;  
                 entry->is_last_name = is_last_name;  
                 list_add_tail(&entry->list, &ccs_domain_keeper_list);  
284                  entry = NULL;                  entry = NULL;
285                  error = 0;                  error = 0;
286          }          }
287          up_write(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
288          /***** WRITER SECTION END *****/   out:
289          ccs_put_name(saved_domainname);          ccs_put_name(e.domainname);
290          ccs_put_name(saved_program);          ccs_put_name(e.program);
291          kfree(entry);          kfree(entry);
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
292          return error;          return error;
293  }  }
294    
# Line 405  int ccs_write_domain_keeper_policy(char Line 318  int ccs_write_domain_keeper_policy(char
318   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
319   *   *
320   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
321     *
322     * Caller holds ccs_read_lock().
323   */   */
324  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
325  {  {
326          struct list_head *pos;          struct list_head *pos;
327          bool done = true;          bool done = true;
328          /***** READER SECTION START *****/          list_for_each_cookie(pos, head->read_var2,
329          down_read(&ccs_policy_lock);                               &ccs_domain_keeper_list) {
         list_for_each_cookie(pos, head->read_var2.u.list,  
                               &ccs_domain_keeper_list) {  
330                  struct ccs_domain_keeper_entry *ptr;                  struct ccs_domain_keeper_entry *ptr;
331                  const char *no;                  const char *no;
332                  const char *from = "";                  const char *from = "";
# Line 426  bool ccs_read_domain_keeper_policy(struc Line 339  bool ccs_read_domain_keeper_policy(struc
339                          from = " from ";                          from = " from ";
340                          program = ptr->program->name;                          program = ptr->program->name;
341                  }                  }
342                  done = ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_KEEP_DOMAIN
343                                       "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s%s%s\n", no, program, from,
344                                       program, from, ptr->domainname->name);                                       ptr->domainname->name);
345                  if (!done)                  if (!done)
346                          break;                          break;
347          }          }
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
348          return done;          return done;
349  }  }
350    
# Line 446  bool ccs_read_domain_keeper_policy(struc Line 357  bool ccs_read_domain_keeper_policy(struc
357   *   *
358   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
359   * false otherwise.   * false otherwise.
360     *
361     * Caller holds ccs_read_lock().
362   */   */
363  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
364                                   const struct ccs_path_info *program,                                   const struct ccs_path_info *program,
# Line 453  static bool ccs_is_domain_keeper(const s Line 366  static bool ccs_is_domain_keeper(const s
366  {  {
367          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
368          bool flag = false;          bool flag = false;
369          /***** READER SECTION START *****/          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
         down_read(&ccs_policy_lock);  
         list_for_each_entry(ptr, &ccs_domain_keeper_list, list) {  
370                  if (ptr->is_deleted)                  if (ptr->is_deleted)
371                          continue;                          continue;
372                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
# Line 473  static bool ccs_is_domain_keeper(const s Line 384  static bool ccs_is_domain_keeper(const s
384                  }                  }
385                  flag = true;                  flag = true;
386          }          }
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
387          return flag;          return flag;
388  }  }
389    
 /* 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);  
         /***** WRITER SECTION START *****/  
         down_write(&ccs_policy_lock);  
         list_for_each_entry(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)) {  
                 entry->original_name = saved_original_name;  
                 saved_original_name = NULL;  
                 entry->aliased_name = saved_aliased_name;  
                 saved_aliased_name = NULL;  
                 list_add_tail(&entry->list, &ccs_alias_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         up_write(&ccs_policy_lock);  
         /***** WRITER SECTION END *****/  
         ccs_put_name(saved_original_name);  
         ccs_put_name(saved_aliased_name);  
         kfree(entry);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
         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.  
  */  
 bool ccs_read_alias_policy(struct ccs_io_buffer *head)  
 {  
         struct list_head *pos;  
         bool done = true;  
         /***** READER SECTION START *****/  
         down_read(&ccs_policy_lock);  
         list_for_each_cookie(pos, head->read_var2.u.list, &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;  
         }  
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
         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);  
 }  
   
390  /* The list for "struct ccs_aggregator_entry". */  /* The list for "struct ccs_aggregator_entry". */
391  LIST_HEAD(ccs_aggregator_list);  LIST_HEAD(ccs_aggregator_list);
392    
# Line 603  static int ccs_update_aggregator_entry(c Line 405  static int ccs_update_aggregator_entry(c
405  {  {
406          struct ccs_aggregator_entry *entry = NULL;          struct ccs_aggregator_entry *entry = NULL;
407          struct ccs_aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
408          const struct ccs_path_info *saved_original_name;          struct ccs_aggregator_entry e = { };
         const struct ccs_path_info *saved_aggregated_name;  
409          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
410          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
411              !ccs_is_correct_path(aggregated_name, 1, -1, -1))              !ccs_is_correct_path(aggregated_name, 1, -1, -1))
412                  return -EINVAL;                  return -EINVAL;
413          saved_original_name = ccs_get_name(original_name);          e.original_name = ccs_get_name(original_name);
414          saved_aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
415          if (!saved_original_name || !saved_aggregated_name) {          if (!e.original_name || !e.aggregated_name)
416                  ccs_put_name(saved_original_name);                  goto out;
                 ccs_put_name(saved_aggregated_name);  
                 return -ENOMEM;  
         }  
417          if (!is_delete)          if (!is_delete)
418                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);                  entry = kmalloc(sizeof(e), GFP_KERNEL);
419          /***** WRITER SECTION START *****/          mutex_lock(&ccs_policy_lock);
420          down_write(&ccs_policy_lock);          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
421          list_for_each_entry(ptr, &ccs_aggregator_list, list) {                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), original_name),
422                  if (ptr->original_name != saved_original_name ||                                 sizeof(e)))
                     ptr->aggregated_name != saved_aggregated_name)  
423                          continue;                          continue;
424                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
425                  error = 0;                  error = 0;
426                  break;                  break;
427          }          }
428          if (!is_delete && error && ccs_memory_ok(entry)) {          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
429                  entry->original_name = saved_original_name;                  list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
                 saved_original_name = NULL;  
                 entry->aggregated_name = saved_aggregated_name;  
                 saved_aggregated_name = NULL;  
                 list_add_tail(&entry->list, &ccs_aggregator_list);  
430                  entry = NULL;                  entry = NULL;
431                  error = 0;                  error = 0;
432          }          }
433          up_write(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
434          /***** WRITER SECTION END *****/   out:
435          ccs_put_name(saved_original_name);          ccs_put_name(e.original_name);
436          ccs_put_name(saved_aggregated_name);          ccs_put_name(e.aggregated_name);
437          kfree(entry);          kfree(entry);
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
438          return error;          return error;
439  }  }
440    
# Line 652  static int ccs_update_aggregator_entry(c Line 444  static int ccs_update_aggregator_entry(c
444   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
445   *   *
446   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
447     *
448     * Caller holds ccs_read_lock().
449   */   */
450  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
451  {  {
452          struct list_head *pos;          struct list_head *pos;
453          bool done = true;          bool done = true;
454          /***** READER SECTION START *****/          list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
         down_read(&ccs_policy_lock);  
         list_for_each_cookie(pos, head->read_var2.u.list,  
                               &ccs_aggregator_list) {  
455                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
456                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);
457                  if (ptr->is_deleted)                  if (ptr->is_deleted)
458                          continue;                          continue;
459                  done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, CCS_KEYWORD_AGGREGATOR "%s %s\n",
460                                       ptr->original_name->name,                                       ptr->original_name->name,
461                                       ptr->aggregated_name->name);                                       ptr->aggregated_name->name);
462                  if (!done)                  if (!done)
463                          break;                          break;
464          }          }
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
465          return done;          return done;
466  }  }
467    
# Line 686  bool ccs_read_aggregator_policy(struct c Line 475  bool ccs_read_aggregator_policy(struct c
475   */   */
476  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator_policy(char *data, const bool is_delete)
477  {  {
478          char *cp = strchr(data, ' ');          char *w[2];
479          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
480                  return -EINVAL;                  return -EINVAL;
481          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return ccs_update_aggregator_entry(data, cp, is_delete);  
482  }  }
483    
484  /* Domain create/delete handler. */  /* Domain create/delete handler. */
# Line 708  int ccs_delete_domain(char *domainname) Line 496  int ccs_delete_domain(char *domainname)
496          struct ccs_path_info name;          struct ccs_path_info name;
497          name.name = domainname;          name.name = domainname;
498          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
499          /***** WRITER SECTION START *****/          mutex_lock(&ccs_policy_lock);
         down_write(&ccs_policy_lock);  
500          /* Is there an active domain? */          /* Is there an active domain? */
501          list_for_each_entry(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
502                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
503                  if (domain == &ccs_kernel_domain)                  if (domain == &ccs_kernel_domain)
504                          continue;                          continue;
# Line 721  int ccs_delete_domain(char *domainname) Line 508  int ccs_delete_domain(char *domainname)
508                  domain->is_deleted = true;                  domain->is_deleted = true;
509                  break;                  break;
510          }          }
511          up_write(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
         /***** WRITER SECTION END *****/  
512          return 0;          return 0;
513  }  }
514    
# Line 731  int ccs_delete_domain(char *domainname) Line 517  int ccs_delete_domain(char *domainname)
517   *   *
518   * @domainname: The name of domain.   * @domainname: The name of domain.
519   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
  * @cookie:     Pointer to "struct ccs_cookie".  
520   *   *
521   * Returns true on success, false otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
522   */   */
523  bool ccs_find_or_assign_new_domain(const char *domainname, const u8 profile,  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
524                                     struct ccs_cookie *cookie)                                                        const u8 profile)
525  {  {
526          struct ccs_domain_info *entry;          struct ccs_domain_info *entry;
527          struct ccs_domain_info *domain;          struct ccs_domain_info *domain;
528          const struct ccs_path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
529          cookie->u.domain = NULL;          bool found = false;
530    
531          if (!ccs_is_correct_domain(domainname))          if (!ccs_is_correct_domain(domainname))
532                  return false;                  return NULL;
533          saved_domainname = ccs_get_name(domainname);          saved_domainname = ccs_get_name(domainname);
534          if (!saved_domainname)          if (!saved_domainname)
535                  return false;                  return NULL;
536          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          entry = kzalloc(sizeof(*entry), GFP_KERNEL);
537          /***** WRITER SECTION START *****/          mutex_lock(&ccs_policy_lock);
538          down_write(&ccs_policy_lock);          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
         list_for_each_entry(domain, &ccs_domain_list, list) {  
539                  if (domain->is_deleted ||                  if (domain->is_deleted ||
540                      ccs_pathcmp(saved_domainname, domain->domainname))                      ccs_pathcmp(saved_domainname, domain->domainname))
541                          continue;                          continue;
542                  cookie->u.domain = domain;                  found = true;
543                  break;                  break;
544          }          }
545          if (!cookie->u.domain && ccs_memory_ok(entry)) {          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
546                  INIT_LIST_HEAD(&entry->acl_info_list);                  INIT_LIST_HEAD(&entry->acl_info_list);
547                  entry->domainname = saved_domainname;                  entry->domainname = saved_domainname;
548                  saved_domainname = NULL;                  saved_domainname = NULL;
549                  entry->profile = profile;                  entry->profile = profile;
550                  list_add_tail(&entry->list, &ccs_domain_list);                  list_add_tail_rcu(&entry->list, &ccs_domain_list);
551                  cookie->u.domain = entry;                  domain = entry;
552                  entry = NULL;                  entry = NULL;
553                    found = true;
554          }          }
555          up_write(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
         /***** WRITER SECTION END *****/  
556          ccs_put_name(saved_domainname);          ccs_put_name(saved_domainname);
557          kfree(entry);          kfree(entry);
558          return cookie->u.domain != NULL;          return found ? domain : NULL;
 }  
   
 /**  
  * 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;  
559  }  }
560    
561  /**  /**
# Line 834  static bool ccs_get_argv0(struct ccs_exe Line 564  static bool ccs_get_argv0(struct ccs_exe
564   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
565   *   *
566   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
567     *
568     * Caller holds ccs_read_lock().
569   */   */
570  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve_entry *ee)
571  {  {
572          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
573          const struct ccs_path_info *handler = ee->handler;          const struct ccs_path_info *handler = ee->handler;
574          const char *old_domain_name = r->cookie.u.domain->domainname->name;          struct ccs_domain_info *domain = NULL;
575            const char *old_domain_name = r->domain->domainname->name;
576          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
         const u8 mode = r->mode;  
         const bool is_enforce = (mode == 3);  
577          const u32 ccs_flags = current->ccs_flags;          const u32 ccs_flags = current->ccs_flags;
578          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 */  
579          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
580          int retval;          int retval;
581          bool found = false;          bool need_kfree = false;
582            ln.name = ccs_last_word(old_domain_name);
583            ccs_fill_path_info(&ln);
584   retry:   retry:
585          current->ccs_flags = ccs_flags;          current->ccs_flags = ccs_flags;
586          r->condition_cookie.u.cond = NULL;          r->cond = NULL;
587          /* Get realpath of program and symbolic link. */          if (need_kfree) {
588          retval = ccs_realpath_both(bprm->filename, ee);                  kfree(rn.name);
589                    need_kfree = false;
590            }
591    
592            /* Get symlink's pathname of program. */
593            retval = ccs_symlink_path(bprm->filename, &rn);
594          if (retval < 0)          if (retval < 0)
595                  goto out;                  goto out;
596            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->cookie.u.domain);  
         ccs_fill_path_info(&ln);  
597    
598          if (handler) {          if (handler) {
599                  if (ccs_pathcmp(&rn, handler)) {                  if (ccs_pathcmp(&rn, handler)) {
# Line 876  static int ccs_find_next_domain(struct c Line 606  static int ccs_find_next_domain(struct c
606                          }                          }
607                          goto out;                          goto out;
608                  }                  }
609                  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? */  
                 /***** READER SECTION START *****/  
                 down_read(&ccs_policy_lock);  
                 list_for_each_entry(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;  
                 }  
                 up_read(&ccs_policy_lock);  
                 /***** READER SECTION END *****/  
         }  
         /* sn will be overwritten after here. */  
   
         /* Compare basename of program_path and argv[0] */  
         r->mode = ccs_check_flags(r->cookie.u.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. */  
         {  
610                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
611                  /* Is this program allowed to be aggregated? */                  /* Check 'aggregator' directive. */
612                  /***** READER SECTION START *****/                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
                 down_read(&ccs_policy_lock);  
                 list_for_each_entry(ptr, &ccs_aggregator_list, list) {  
613                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
614                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
615                                  continue;                                  continue;
616                          strncpy(ee->program_path, ptr->aggregated_name->name,                          kfree(rn.name);
617                                  CCS_MAX_PATHNAME_LEN - 1);                          need_kfree = false;
618                          ccs_fill_path_info(&rn);                          /* This is OK because it is read only. */
619                            rn = *ptr->aggregated_name;
620                          break;                          break;
621                  }                  }
                 up_read(&ccs_policy_lock);  
                 /***** READER SECTION END *****/  
         }  
622    
623          /* Check execute permission. */                  /* Check execute permission. */
624          r->mode = mode;                  retval = ccs_exec_perm(r, &rn);
625          retval = ccs_check_exec_perm(r, &rn);                  if (retval == 1)
626          if (retval == 1)                          goto retry;
627                  goto retry;                  if (retval < 0)
628          if (retval < 0)                          goto out;
629                  goto out;          }
630    
631   calculate_domain:          /* Calculate domain to transit to. */
632          new_domain_name = ee->tmp;          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
         if (ccs_is_domain_initializer(r->cookie.u.domain->domainname, &rn,  
                                       &ln)) {  
633                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
634                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
635                           ROOT_NAME " " "%s", ee->program_path);                           rn.name);
636          } else if (r->cookie.u.domain == &ccs_kernel_domain &&          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
                    !ccs_policy_loaded) {  
637                  /*                  /*
638                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
639                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
640                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
641                   */                   */
642                  found = true;                  domain = r->domain;
643          } else if (ccs_is_domain_keeper(r->cookie.u.domain->domainname, &rn, &ln)) {          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
644                  /* Keep current domain. */                  /* Keep current domain. */
645                  found = true;                  domain = r->domain;
646          } else {          } else {
647                  /* Normal domain transition. */                  /* Normal domain transition. */
648                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
649                           "%s %s", old_domain_name, ee->program_path);                           old_domain_name, rn.name);
650          }          }
651          if (found || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
652                  goto done;                  goto done;
653          found = ccs_find_domain(new_domain_name, &r->cookie);          domain = ccs_find_domain(ee->tmp);
654          if (found)          if (domain)
655                  goto done;                  goto done;
656          if (is_enforce) {          if (r->mode == CCS_MAC_MODE_ENFORCING) {
657                  int error = ccs_check_supervisor(r,                  int error = ccs_supervisor(r, "# wants to create domain\n"
658                                                   "# wants to create domain\n"                                             "%s\n", ee->tmp);
                                                  "%s\n", new_domain_name);  
659                  if (error == 1)                  if (error == 1)
660                          goto retry;                          goto retry;
661                  if (error < 0)                  if (error < 0)
662                          goto done;                          goto done;
663          }          }
664          found = ccs_find_or_assign_new_domain(new_domain_name, r->profile,          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);
665                                                &r->cookie);          if (domain)
666          if (found)                  ccs_audit_domain_creation_log(r->domain);
                 ccs_audit_domain_creation_log(r->cookie.u.domain);  
667   done:   done:
668          if (found) {          if (!domain) {
669                  retval = 0;                  printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
670                  goto out;                         ee->tmp);
671          }                  if (r->mode == CCS_MAC_MODE_ENFORCING)
672          printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                          retval = -EPERM;
673                 new_domain_name);                  else {
674          if (is_enforce)                          retval = 0;
675                  retval = -EPERM;                          r->domain->domain_transition_failed = true;
676          else {                  }
677            } else {
678                  retval = 0;                  retval = 0;
                 r->cookie.u.domain->domain_transition_failed = true;  
679          }          }
680   out:   out:
681            if (domain)
682                    r->domain = domain;
683            if (need_kfree)
684                    kfree(rn.name);
685          return retval;          return retval;
686  }  }
687    
688  /**  /**
689   * ccs_check_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
690   *   *
691   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
692   *   *
693   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
694   */   */
695  static int ccs_check_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve_entry *ee)
696  {  {
697          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
698          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
# Line 1045  static int ccs_check_environ(struct ccs_ Line 723  static int ccs_check_environ(struct ccs_
723                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
724                          const char *kaddr = ee->dump.data;                          const char *kaddr = ee->dump.data;
725                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
726                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
727                                  if (c == '=') {                                  if (c == '=') {
728                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
729                                  } else if (c == '\\') {                                  } else if (c == '\\') {
# Line 1065  static int ccs_check_environ(struct ccs_ Line 743  static int ccs_check_environ(struct ccs_
743                          }                          }
744                          if (c)                          if (c)
745                                  continue;                                  continue;
746                          if (ccs_check_env_perm(r, arg_ptr)) {                          if (ccs_env_perm(r, arg_ptr)) {
747                                  error = -EPERM;                                  error = -EPERM;
748                                  break;                                  break;
749                          }                          }
# Line 1133  static void ccs_unescape(unsigned char * Line 811  static void ccs_unescape(unsigned char *
811  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
812  {  {
813          int depth = 0;          int depth = 0;
         /***** CRITICAL SECTION START *****/  
814          ccs_realpath_lock();          ccs_realpath_lock();
815          for (;;) {          for (;;) {
816                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
# Line 1148  static inline int ccs_root_depth(struct Line 825  static inline int ccs_root_depth(struct
825                  depth++;                  depth++;
826          }          }
827          ccs_realpath_unlock();          ccs_realpath_unlock();
         /***** CRITICAL SECTION END *****/  
828          return depth;          return depth;
829  }  }
830    
# Line 1165  static int ccs_get_root_depth(void) Line 841  static int ccs_get_root_depth(void)
841  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
842          struct path root;          struct path root;
843  #endif  #endif
         /***** CRITICAL SECTION START *****/  
844          read_lock(&current->fs->lock);          read_lock(&current->fs->lock);
845  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
846          root = current->fs->root;          root = current->fs->root;
# Line 1177  static int ccs_get_root_depth(void) Line 852  static int ccs_get_root_depth(void)
852          vfsmnt = mntget(current->fs->rootmnt);          vfsmnt = mntget(current->fs->rootmnt);
853  #endif  #endif
854          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
         /***** CRITICAL SECTION END *****/  
855          depth = ccs_root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
856  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
857          path_put(&root);          path_put(&root);
# Line 1198  static DEFINE_SPINLOCK(ccs_execve_list_l Line 872  static DEFINE_SPINLOCK(ccs_execve_list_l
872   */   */
873  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
874  {  {
875          struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);          struct ccs_execve_entry *ee = kzalloc(sizeof(*ee), GFP_KERNEL);
876          if (!ee)          if (!ee)
877                  return NULL;                  return NULL;
878          memset(ee, 0, sizeof(*ee));          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);
879          ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);          if (!ee->tmp) {
880          ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);                  kfree(ee);
         if (!ee->program_path || !ee->tmp) {  
                 ccs_free(ee->program_path);  
                 ccs_free(ee->tmp);  
                 ccs_free(ee);  
881                  return NULL;                  return NULL;
882          }          }
883            ee->reader_idx = ccs_read_lock();
884          /* ee->dump->data is allocated by ccs_dump_page(). */          /* ee->dump->data is allocated by ccs_dump_page(). */
885          ee->task = current;          ee->task = current;
         /***** CRITICAL SECTION START *****/  
886          spin_lock(&ccs_execve_list_lock);          spin_lock(&ccs_execve_list_lock);
887          list_add(&ee->list, &ccs_execve_list);          list_add(&ee->list, &ccs_execve_list);
888          spin_unlock(&ccs_execve_list_lock);          spin_unlock(&ccs_execve_list_lock);
         /***** CRITICAL SECTION END *****/  
889          return ee;          return ee;
890  }  }
891    
# Line 1230  static struct ccs_execve_entry *ccs_find Line 899  static struct ccs_execve_entry *ccs_find
899          struct task_struct *task = current;          struct task_struct *task = current;
900          struct ccs_execve_entry *ee = NULL;          struct ccs_execve_entry *ee = NULL;
901          struct ccs_execve_entry *p;          struct ccs_execve_entry *p;
         /***** CRITICAL SECTION START *****/  
902          spin_lock(&ccs_execve_list_lock);          spin_lock(&ccs_execve_list_lock);
903          list_for_each_entry(p, &ccs_execve_list, list) {          list_for_each_entry(p, &ccs_execve_list, list) {
904                  if (p->task != task)                  if (p->task != task)
# Line 1239  static struct ccs_execve_entry *ccs_find Line 907  static struct ccs_execve_entry *ccs_find
907                  break;                  break;
908          }          }
909          spin_unlock(&ccs_execve_list_lock);          spin_unlock(&ccs_execve_list_lock);
         /***** CRITICAL SECTION END *****/  
910          return ee;          return ee;
911  }  }
912    
# Line 1252  static void ccs_free_execve_entry(struct Line 919  static void ccs_free_execve_entry(struct
919  {  {
920          if (!ee)          if (!ee)
921                  return;                  return;
         /***** CRITICAL SECTION START *****/  
922          spin_lock(&ccs_execve_list_lock);          spin_lock(&ccs_execve_list_lock);
923          list_del(&ee->list);          list_del(&ee->list);
924          spin_unlock(&ccs_execve_list_lock);          spin_unlock(&ccs_execve_list_lock);
925          /***** CRITICAL SECTION END *****/          kfree(ee->handler_path);
926          ccs_free(ee->program_path);          kfree(ee->tmp);
         ccs_free(ee->tmp);  
927          kfree(ee->dump.data);          kfree(ee->dump.data);
928          ccs_free(ee);          ccs_read_unlock(ee->reader_idx);
929            kfree(ee);
930  }  }
931    
932  /**  /**
# Line 1379  static int ccs_try_alt_exec(struct ccs_e Line 1045  static int ccs_try_alt_exec(struct ccs_e
1045                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
1046                  if (exe) {                  if (exe) {
1047                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1048                          ccs_free(exe);                          kfree(exe);
1049                  } else {                  } else {
1050                          exe = ee->tmp;                          exe = ee->tmp;
1051                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
1052                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1053                  }                  }
1054                  if (retval < 0)                  if (retval < 0)
# Line 1393  static int ccs_try_alt_exec(struct ccs_e Line 1059  static int ccs_try_alt_exec(struct ccs_e
1059          /* Set argv[1] */          /* Set argv[1] */
1060          {          {
1061                  char *cp = ee->tmp;                  char *cp = ee->tmp;
1062                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1063                          CCS_EXEC_TMPSIZE - 1);                           ccs_current_domain()->domainname->name);
1064                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1065                  if (retval < 0)                  if (retval < 0)
1066                          goto out;                          goto out;
# Line 1404  static int ccs_try_alt_exec(struct ccs_e Line 1070  static int ccs_try_alt_exec(struct ccs_e
1070          /* Set argv[0] */          /* Set argv[0] */
1071          {          {
1072                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
1073                  char *cp = ee->program_path;                  int len = ee->handler->total_len + 1;
1074                  strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);                  char *cp = kmalloc(len, GFP_KERNEL);
1075                    if (!cp) {
1076                            retval = ENOMEM;
1077                            goto out;
1078                    }
1079                    ee->handler_path = cp;
1080                    memmove(cp, ee->handler->name, len);
1081                  ccs_unescape(cp);                  ccs_unescape(cp);
1082                  retval = -ENOENT;                  retval = -ENOENT;
1083                  if (!*cp || *cp != '/')                  if (!*cp || *cp != '/')
# Line 1417  static int ccs_try_alt_exec(struct ccs_e Line 1089  static int ccs_try_alt_exec(struct ccs_e
1089                                  goto out;                                  goto out;
1090                          depth--;                          depth--;
1091                  }                  }
1092                  memmove(ee->program_path, cp, strlen(cp) + 1);                  memmove(ee->handler_path, cp, strlen(cp) + 1);
1093                  cp = ee->program_path;                  cp = ee->handler_path;
1094                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1095                  if (retval < 0)                  if (retval < 0)
1096                          goto out;                          goto out;
# Line 1431  static int ccs_try_alt_exec(struct ccs_e Line 1103  static int ccs_try_alt_exec(struct ccs_e
1103  #endif  #endif
1104    
1105          /* OK, now restart the process with execute handler program's dentry. */          /* OK, now restart the process with execute handler program's dentry. */
1106          filp = open_exec(ee->program_path);          filp = open_exec(ee->handler_path);
1107          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1108                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1109                  goto out;                  goto out;
1110          }          }
1111          bprm->file = filp;          bprm->file = filp;
1112          bprm->filename = ee->program_path;          bprm->filename = ee->handler_path;
1113  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1114          bprm->interp = bprm->filename;          bprm->interp = bprm->filename;
1115  #endif  #endif
1116          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1117          if (retval < 0)          if (retval < 0)
1118                  goto out;                  goto out;
1119          {          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1120                  /*          retval = ccs_find_next_domain(ee);
1121                   * 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 = kmalloc(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);  
         }  
1122   out:   out:
1123          return retval;          return retval;
1124  }  }
# Line 1482  static int ccs_try_alt_exec(struct ccs_e Line 1130  static int ccs_try_alt_exec(struct ccs_e
1130   * @type: Type of execute handler.   * @type: Type of execute handler.
1131   *   *
1132   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1133     *
1134     * Caller holds ccs_read_lock().
1135   */   */
1136  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1137                                       const u8 type)                                       const u8 type)
# Line 1496  static bool ccs_find_execute_handler(str Line 1146  static bool ccs_find_execute_handler(str
1146           */           */
1147          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1148                  return false;                  return false;
         /***** READER SECTION START *****/  
         down_read(&ccs_policy_lock);  
1149          list_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry(ptr, &domain->acl_info_list, list) {
1150                  struct ccs_execute_handler_record *acl;                  struct ccs_execute_handler_record *acl;
1151                  if (ptr->type != type)                  if (ptr->type != type)
# Line 1508  static bool ccs_find_execute_handler(str Line 1156  static bool ccs_find_execute_handler(str
1156                  found = true;                  found = true;
1157                  break;                  break;
1158          }          }
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
1159          return found;          return found;
1160  }  }
1161    
# Line 1528  bool ccs_dump_page(struct linux_binprm * Line 1174  bool ccs_dump_page(struct linux_binprm *
1174          struct page *page;          struct page *page;
1175          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_free_execve_entry(). */
1176          if (!dump->data) {          if (!dump->data) {
1177                  dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);
1178                  if (!dump->data)                  if (!dump->data)
1179                          return false;                          return false;
1180          }          }
# Line 1574  struct ccs_domain_info *ccs_fetch_next_d Line 1220  struct ccs_domain_info *ccs_fetch_next_d
1220          struct ccs_execve_entry *ee = ccs_find_execve_entry();          struct ccs_execve_entry *ee = ccs_find_execve_entry();
1221          struct ccs_domain_info *next_domain = NULL;          struct ccs_domain_info *next_domain = NULL;
1222          if (ee)          if (ee)
1223                  next_domain = ee->r.cookie.u.domain;                  next_domain = ee->r.domain;
1224          if (!next_domain)          if (!next_domain)
1225                  next_domain = ccs_current_domain();                  next_domain = ccs_current_domain();
1226          return next_domain;          return next_domain;
# Line 1596  int ccs_start_execve(struct linux_binprm Line 1242  int ccs_start_execve(struct linux_binprm
1242                  ccs_load_policy(bprm->filename);                  ccs_load_policy(bprm->filename);
1243          if (!ee)          if (!ee)
1244                  return -ENOMEM;                  return -ENOMEM;
1245          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);
1246          ee->r.ee = ee;          ee->r.ee = ee;
1247          ee->bprm = bprm;          ee->bprm = bprm;
1248          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1249          ee->obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1250          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1251          /* Clear manager flag. */          /* Clear manager flag. */
1252          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1253          if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {
1254                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1255                  if (!retval)                  if (!retval)
1256                          ccs_audit_execute_handler_log(ee, true);                          ccs_audit_execute_handler_log(ee, true);
# Line 1613  int ccs_start_execve(struct linux_binprm Line 1259  int ccs_start_execve(struct linux_binprm
1259          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1260          if (retval != -EPERM)          if (retval != -EPERM)
1261                  goto ok;                  goto ok;
1262          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1263                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1264                  if (!retval)                  if (!retval)
1265                          ccs_audit_execute_handler_log(ee, false);                          ccs_audit_execute_handler_log(ee, false);
# Line 1621  int ccs_start_execve(struct linux_binprm Line 1267  int ccs_start_execve(struct linux_binprm
1267   ok:   ok:
1268          if (retval < 0)          if (retval < 0)
1269                  goto out;                  goto out;
1270          ee->r.mode = ccs_check_flags(ee->r.cookie.u.domain, CCS_MAC_FOR_ENV);          ee->r.mode = ccs_get_mode(ee->r.profile, CCS_MAC_ENVIRON);
1271          retval = ccs_check_environ(ee);          retval = ccs_environ(ee);
1272          if (retval < 0)          if (retval < 0)
1273                  goto out;                  goto out;
1274          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
# Line 1637  int ccs_start_execve(struct linux_binprm Line 1283  int ccs_start_execve(struct linux_binprm
1283   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1284   *   *
1285   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1286     *
1287     * Caller holds ccs_read_lock().
1288   */   */
1289  void ccs_finish_execve(int retval)  void ccs_finish_execve(int retval)
1290  {  {
# Line 1647  void ccs_finish_execve(int retval) Line 1295  void ccs_finish_execve(int retval)
1295                  return;                  return;
1296          if (retval < 0)          if (retval < 0)
1297                  goto out;                  goto out;
         /***** READER SECTION START *****/  
         down_read(&ccs_policy_lock);  
1298          /* Proceed to next domain if execution suceeded. */          /* Proceed to next domain if execution suceeded. */
1299          task->ccs_domain_info = ee->r.cookie.u.domain;          task->ccs_domain_info = ee->r.domain;
         up_read(&ccs_policy_lock);  
         /***** READER SECTION END *****/  
1300          /* Mark the current process as execute handler. */          /* Mark the current process as execute handler. */
1301          if (ee->handler)          if (ee->handler)
1302                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
# Line 1660  void ccs_finish_execve(int retval) Line 1304  void ccs_finish_execve(int retval)
1304          else          else
1305                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1306   out:   out:
         ccs_exit_request_info(&ee->r);  
1307          ccs_free_execve_entry(ee);          ccs_free_execve_entry(ee);
1308  }  }
   
 #else  
   
 /**  
  * ccs_start_execve - Prepare for execve() operation.  
  *  
  * @bprm: Pointer to "struct linux_binprm".  
  *  
  * Returns 0.  
  */  
 int ccs_start_execve(struct linux_binprm *bprm)  
 {  
 #ifdef CONFIG_SAKURA  
         /* Clear manager flag. */  
         current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;  
         if (!ccs_policy_loaded)  
                 ccs_load_policy(bprm->filename);  
 #endif  
         return 0;  
 }  
   
 /**  
  * ccs_finish_execve - Clean up execve() operation.  
  */  
 void ccs_finish_execve(int retval)  
 {  
 }  
   
 #endif  

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

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