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

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 2539 by kumaneko, Thu May 14 00:07:19 2009 UTC branches/ccs-patch/security/ccsecurity/domain.c revision 2922 by kumaneko, Wed Aug 19 04:26:56 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/08
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 35  Line 33 
33  struct ccs_domain_info ccs_kernel_domain;  struct ccs_domain_info ccs_kernel_domain;
34    
35  /* The list for "struct ccs_domain_info". */  /* The list for "struct ccs_domain_info". */
36  LIST1_HEAD(ccs_domain_list);  LIST_HEAD(ccs_domain_list);
   
 #ifdef CONFIG_TOMOYO  
   
 /* Domain creation lock. */  
 static DEFINE_MUTEX(ccs_domain_list_lock);  
   
 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */  
 struct ccs_domain_initializer_entry {  
         struct list1_head list;  
         const struct ccs_path_info *domainname;    /* This may be NULL */  
         const struct ccs_path_info *program;  
         bool is_deleted;  
         bool is_not;       /* True if this entry is "no_initialize_domain".  */  
         bool is_last_name; /* True if the domainname is ccs_get_last_name(). */  
 };  
   
 /* Structure for "keep_domain" and "no_keep_domain" keyword. */  
 struct ccs_domain_keeper_entry {  
         struct list1_head list;  
         const struct ccs_path_info *domainname;  
         const struct ccs_path_info *program;       /* This may be NULL */  
         bool is_deleted;  
         bool is_not;       /* True if this entry is "no_keep_domain".        */  
         bool is_last_name; /* True if the domainname is ccs_get_last_name(). */  
 };  
   
 /* Structure for "aggregator" keyword. */  
 struct ccs_aggregator_entry {  
         struct list1_head list;  
         const struct ccs_path_info *original_name;  
         const struct ccs_path_info *aggregated_name;  
         bool is_deleted;  
 };  
   
 /* Structure for "alias" keyword. */  
 struct ccs_alias_entry {  
         struct list1_head list;  
         const struct ccs_path_info *original_name;  
         const struct ccs_path_info *aliased_name;  
         bool is_deleted;  
 };  
   
 /**  
  * ccs_set_domain_flag - Set or clear domain's attribute flags.  
  *  
  * @domain:    Pointer to "struct ccs_domain_info".  
  * @is_delete: True if it is a delete request.  
  * @flags:     Flags to set or clear.  
  *  
  * Returns nothing.  
  */  
 void ccs_set_domain_flag(struct ccs_domain_info *domain, const bool is_delete,  
                          const u8 flags)  
 {  
         /* We need to serialize because this is bitfield operation. */  
         static DEFINE_SPINLOCK(lock);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&lock);  
         if (!is_delete)  
                 domain->flags |= flags;  
         else  
                 domain->flags &= ~flags;  
         spin_unlock(&lock);  
         /***** CRITICAL SECTION END *****/  
 }  
37    
38  /**  /**
39   * ccs_get_last_name - Get last component of a domainname.   * ccs_get_last_name - Get last component of a domainname.
# Line 119  const char *ccs_get_last_name(const stru Line 52  const char *ccs_get_last_name(const stru
52  }  }
53    
54  /**  /**
  * 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) {  
                 /*  
                  * We need to serialize because this function is called by  
                  * various update functions.  
                  */  
                 static DEFINE_SPINLOCK(lock);  
                 /***** CRITICAL SECTION START *****/  
                 spin_lock(&lock);  
                 list1_add_tail_mb(&acl->list, &domain->acl_info_list);  
                 spin_unlock(&lock);  
                 /***** CRITICAL SECTION END *****/  
         } 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;  
 }  
   
 /**  
55   * ccs_audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
56   *   *
57   * @ee:         Pointer to "struct ccs_execve_entry".   * @ee:         Pointer to "struct ccs_execve_entry".
# Line 174  static int ccs_audit_execute_handler_log Line 64  static int ccs_audit_execute_handler_log
64  {  {
65          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
66          const char *handler = ee->handler->name;          const char *handler = ee->handler->name;
67          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);          r->mode = ccs_flags(r->domain, CCS_MAC_EXECUTE);
68          return ccs_write_audit_log(true, r, "%s %s\n",          return ccs_write_audit_log(true, r, "%s %s\n",
69                                     is_default ? KEYWORD_EXECUTE_HANDLER :                                     is_default ? CCS_KEYWORD_EXECUTE_HANDLER :
70                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);                                     CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);
71  }  }
72    
73  /**  /**
# Line 189  static int ccs_audit_execute_handler_log Line 79  static int ccs_audit_execute_handler_log
79   */   */
80  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
81  {  {
82            int error;
83          struct ccs_request_info r;          struct ccs_request_info r;
84          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);          ccs_init_request_info(&r, domain, CCS_MAC_EXECUTE);
85          return 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);
86            return error;
87  }  }
88    
89  /* The list for "struct ccs_domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
90  static LIST1_HEAD(ccs_domain_initializer_list);  LIST_HEAD(ccs_domain_initializer_list);
91    
92  /**  /**
93   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
# Line 212  static int ccs_update_domain_initializer Line 104  static int ccs_update_domain_initializer
104                                                 const bool is_not,                                                 const bool is_not,
105                                                 const bool is_delete)                                                 const bool is_delete)
106  {  {
107          struct ccs_domain_initializer_entry *new_entry;          struct ccs_domain_initializer_entry *entry = NULL;
108          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
109          static DEFINE_MUTEX(lock);          struct ccs_domain_initializer_entry e = { .is_not = is_not };
110          const struct ccs_path_info *saved_program;          int error = is_delete ? -ENOENT : -ENOMEM;
111          const struct ccs_path_info *saved_domainname = NULL;          if (!ccs_is_correct_path(program, 1, -1, -1))
         int error = -ENOMEM;  
         bool is_last_name = false;  
         if (!ccs_is_correct_path(program, 1, -1, -1, __func__))  
112                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
113          if (domainname) {          if (domainname) {
114                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
115                      ccs_is_correct_path(domainname, 1, -1, -1, __func__))                      ccs_is_correct_path(domainname, 1, -1, -1))
116                          is_last_name = true;                          e.is_last_name = true;
117                  else if (!ccs_is_correct_domain(domainname, __func__))                  else if (!ccs_is_correct_domain(domainname))
118                          return -EINVAL;                          return -EINVAL;
119                  saved_domainname = ccs_save_name(domainname);                  e.domainname = ccs_get_name(domainname);
120                  if (!saved_domainname)                  if (!e.domainname)
121                          return -ENOMEM;                          goto out;
122          }          }
123          saved_program = ccs_save_name(program);          e.program = ccs_get_name(program);
124          if (!saved_program)          if (!e.program)
125                  return -ENOMEM;                  goto out;
126          mutex_lock(&lock);          if (!is_delete)
127          list1_for_each_entry(ptr, &ccs_domain_initializer_list, list) {                  entry = kmalloc(sizeof(e), GFP_KERNEL);
128                  if (ptr->is_not != is_not ||          mutex_lock(&ccs_policy_lock);
129                      ptr->domainname != saved_domainname ||          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
130                      ptr->program != saved_program)                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
131                                   sizeof(e)))
132                          continue;                          continue;
133                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
134                  error = 0;                  error = 0;
135                  goto out;                  break;
136          }          }
137          if (is_delete) {          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
138                  error = -ENOENT;                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);
139                  goto out;                  entry = NULL;
140                    error = 0;
141          }          }
142          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
         if (!new_entry)  
                 goto out;  
         new_entry->domainname = saved_domainname;  
         new_entry->program = saved_program;  
         new_entry->is_not = is_not;  
         new_entry->is_last_name = is_last_name;  
         list1_add_tail_mb(&new_entry->list, &ccs_domain_initializer_list);  
         error = 0;  
143   out:   out:
144          mutex_unlock(&lock);          ccs_put_name(e.domainname);
145          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.program);
146            kfree(entry);
147          return error;          return error;
148  }  }
149    
# Line 269  static int ccs_update_domain_initializer Line 153  static int ccs_update_domain_initializer
153   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
154   *   *
155   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
156     *
157     * Caller holds ccs_read_lock().
158   */   */
159  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
160  {  {
161          struct list1_head *pos;          struct list_head *pos;
162          list1_for_each_cookie(pos, head->read_var2,          bool done = true;
163                                &ccs_domain_initializer_list) {          ccs_assert_read_lock();
164            list_for_each_cookie(pos, head->read_var2,
165                                 &ccs_domain_initializer_list) {
166                  const char *no;                  const char *no;
167                  const char *from = "";                  const char *from = "";
168                  const char *domain = "";                  const char *domain = "";
169                  struct ccs_domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
170                  ptr = list1_entry(pos, struct ccs_domain_initializer_entry,                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
171                                    list);                                    list);
172                  if (ptr->is_deleted)                  if (ptr->is_deleted)
173                          continue;                          continue;
# Line 288  bool ccs_read_domain_initializer_policy( Line 176  bool ccs_read_domain_initializer_policy(
176                          from = " from ";                          from = " from ";
177                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
178                  }                  }
179                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
180                                     "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s" CCS_KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",
181                                     no, ptr->program->name, from, domain))                                       no, ptr->program->name, from, domain);
182                          goto out;                  if (!done)
183                            break;
184          }          }
185          return true;          return done;
  out:  
         return false;  
186  }  }
187    
188  /**  /**
# Line 329  int ccs_write_domain_initializer_policy( Line 216  int ccs_write_domain_initializer_policy(
216   *   *
217   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
218   * false otherwise.   * false otherwise.
219     *
220     * Caller holds ccs_read_lock().
221   */   */
222  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
223                                        const struct ccs_path_info *program,                                        const struct ccs_path_info *program,
# Line 336  static bool ccs_is_domain_initializer(co Line 225  static bool ccs_is_domain_initializer(co
225  {  {
226          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
227          bool flag = false;          bool flag = false;
228          list1_for_each_entry(ptr, &ccs_domain_initializer_list, list) {          ccs_assert_read_lock();
229            list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
230                  if (ptr->is_deleted)                  if (ptr->is_deleted)
231                          continue;                          continue;
232                  if (ptr->domainname) {                  if (ptr->domainname) {
# Line 350  static bool ccs_is_domain_initializer(co Line 240  static bool ccs_is_domain_initializer(co
240                  }                  }
241                  if (ccs_pathcmp(ptr->program, program))                  if (ccs_pathcmp(ptr->program, program))
242                          continue;                          continue;
243                  if (ptr->is_not)                  if (ptr->is_not) {
244                          return false;                          flag = false;
245                            break;
246                    }
247                  flag = true;                  flag = true;
248          }          }
249          return flag;          return flag;
250  }  }
251    
252  /* The list for "struct ccs_domain_keeper_entry". */  /* The list for "struct ccs_domain_keeper_entry". */
253  static LIST1_HEAD(ccs_domain_keeper_list);  LIST_HEAD(ccs_domain_keeper_list);
254    
255  /**  /**
256   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
# Line 375  static int ccs_update_domain_keeper_entr Line 267  static int ccs_update_domain_keeper_entr
267                                            const bool is_not,                                            const bool is_not,
268                                            const bool is_delete)                                            const bool is_delete)
269  {  {
270          struct ccs_domain_keeper_entry *new_entry;          struct ccs_domain_keeper_entry *entry = NULL;
271          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
272          const struct ccs_path_info *saved_domainname;          struct ccs_domain_keeper_entry e = { .is_not = is_not };
273          const struct ccs_path_info *saved_program = NULL;          int error = is_delete ? -ENOENT : -ENOMEM;
         static DEFINE_MUTEX(lock);  
         int error = -ENOMEM;  
         bool is_last_name = false;  
274          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
275              ccs_is_correct_path(domainname, 1, -1, -1, __func__))              ccs_is_correct_path(domainname, 1, -1, -1))
276                  is_last_name = true;                  e.is_last_name = true;
277          else if (!ccs_is_correct_domain(domainname, __func__))          else if (!ccs_is_correct_domain(domainname))
278                  return -EINVAL;                  return -EINVAL;
279          if (program) {          if (program) {
280                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))                  if (!ccs_is_correct_path(program, 1, -1, -1))
281                          return -EINVAL;                          return -EINVAL;
282                  saved_program = ccs_save_name(program);                  e.program = ccs_get_name(program);
283                  if (!saved_program)                  if (!e.program)
284                          return -ENOMEM;                          goto out;
285          }          }
286          saved_domainname = ccs_save_name(domainname);          e.domainname = ccs_get_name(domainname);
287          if (!saved_domainname)          if (!e.domainname)
288                  return -ENOMEM;                  goto out;
289          mutex_lock(&lock);          if (!is_delete)
290          list1_for_each_entry(ptr, &ccs_domain_keeper_list, list) {                  entry = kmalloc(sizeof(e), GFP_KERNEL);
291                  if (ptr->is_not != is_not ||          mutex_lock(&ccs_policy_lock);
292                      ptr->domainname != saved_domainname ||          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
293                      ptr->program != saved_program)                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
294                                   sizeof(e)))
295                          continue;                          continue;
296                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
297                  error = 0;                  error = 0;
298                  goto out;                  break;
299          }          }
300          if (is_delete) {          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
301                  error = -ENOENT;                  list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);
302                  goto out;                  entry = NULL;
303                    error = 0;
304          }          }
305          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
         if (!new_entry)  
                 goto out;  
         new_entry->domainname = saved_domainname;  
         new_entry->program = saved_program;  
         new_entry->is_not = is_not;  
         new_entry->is_last_name = is_last_name;  
         list1_add_tail_mb(&new_entry->list, &ccs_domain_keeper_list);  
         error = 0;  
306   out:   out:
307          mutex_unlock(&lock);          ccs_put_name(e.domainname);
308          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.program);
309            kfree(entry);
310          return error;          return error;
311  }  }
312    
# Line 452  int ccs_write_domain_keeper_policy(char Line 336  int ccs_write_domain_keeper_policy(char
336   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
337   *   *
338   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
339     *
340     * Caller holds ccs_read_lock().
341   */   */
342  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
343  {  {
344          struct list1_head *pos;          struct list_head *pos;
345          list1_for_each_cookie(pos, head->read_var2, &ccs_domain_keeper_list) {          bool done = true;
346            ccs_assert_read_lock();
347            list_for_each_cookie(pos, head->read_var2,
348                                 &ccs_domain_keeper_list) {
349                  struct ccs_domain_keeper_entry *ptr;                  struct ccs_domain_keeper_entry *ptr;
350                  const char *no;                  const char *no;
351                  const char *from = "";                  const char *from = "";
352                  const char *program = "";                  const char *program = "";
353                  ptr = list1_entry(pos, struct ccs_domain_keeper_entry, list);                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
354                  if (ptr->is_deleted)                  if (ptr->is_deleted)
355                          continue;                          continue;
356                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 469  bool ccs_read_domain_keeper_policy(struc Line 358  bool ccs_read_domain_keeper_policy(struc
358                          from = " from ";                          from = " from ";
359                          program = ptr->program->name;                          program = ptr->program->name;
360                  }                  }
361                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_KEEP_DOMAIN
362                                     "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s%s%s\n", no, program, from,
363                                     program, from, ptr->domainname->name))                                       ptr->domainname->name);
364                          goto out;                  if (!done)
365                            break;
366          }          }
367          return true;          return done;
  out:  
         return false;  
368  }  }
369    
370  /**  /**
# Line 488  bool ccs_read_domain_keeper_policy(struc Line 376  bool ccs_read_domain_keeper_policy(struc
376   *   *
377   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
378   * false otherwise.   * false otherwise.
379     *
380     * Caller holds ccs_read_lock().
381   */   */
382  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
383                                   const struct ccs_path_info *program,                                   const struct ccs_path_info *program,
# Line 495  static bool ccs_is_domain_keeper(const s Line 385  static bool ccs_is_domain_keeper(const s
385  {  {
386          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
387          bool flag = false;          bool flag = false;
388          list1_for_each_entry(ptr, &ccs_domain_keeper_list, list) {          ccs_assert_read_lock();
389            list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
390                  if (ptr->is_deleted)                  if (ptr->is_deleted)
391                          continue;                          continue;
392                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
# Line 507  static bool ccs_is_domain_keeper(const s Line 398  static bool ccs_is_domain_keeper(const s
398                  }                  }
399                  if (ptr->program && ccs_pathcmp(ptr->program, program))                  if (ptr->program && ccs_pathcmp(ptr->program, program))
400                          continue;                          continue;
401                  if (ptr->is_not)                  if (ptr->is_not) {
402                          return false;                          flag = false;
403                            break;
404                    }
405                  flag = true;                  flag = true;
406          }          }
407          return flag;          return flag;
408  }  }
409    
 /* The list for "struct ccs_alias_entry". */  
 static LIST1_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 *new_entry;  
         struct ccs_alias_entry *ptr;  
         static DEFINE_MUTEX(lock);  
         const struct ccs_path_info *saved_original_name;  
         const struct ccs_path_info *saved_aliased_name;  
         int error = -ENOMEM;  
         if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) ||  
             !ccs_is_correct_path(aliased_name, 1, -1, -1, __func__))  
                 return -EINVAL; /* No patterns allowed. */  
         saved_original_name = ccs_save_name(original_name);  
         saved_aliased_name = ccs_save_name(aliased_name);  
         if (!saved_original_name || !saved_aliased_name)  
                 return -ENOMEM;  
         mutex_lock(&lock);  
         list1_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;  
                 goto out;  
         }  
         if (is_delete) {  
                 error = -ENOENT;  
                 goto out;  
         }  
         new_entry = ccs_alloc_element(sizeof(*new_entry));  
         if (!new_entry)  
                 goto out;  
         new_entry->original_name = saved_original_name;  
         new_entry->aliased_name = saved_aliased_name;  
         list1_add_tail_mb(&new_entry->list, &ccs_alias_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         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 list1_head *pos;  
         list1_for_each_cookie(pos, head->read_var2, &ccs_alias_list) {  
                 struct ccs_alias_entry *ptr;  
                 ptr = list1_entry(pos, struct ccs_alias_entry, list);  
                 if (ptr->is_deleted)  
                         continue;  
                 if (!ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",  
                                    ptr->original_name->name,  
                                    ptr->aliased_name->name))  
                         goto out;  
         }  
         return true;  
  out:  
         return false;  
 }  
   
 /**  
  * 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);  
 }  
   
410  /* The list for "struct ccs_aggregator_entry". */  /* The list for "struct ccs_aggregator_entry". */
411  static LIST1_HEAD(ccs_aggregator_list);  LIST_HEAD(ccs_aggregator_list);
412    
413  /**  /**
414   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
# Line 627  static int ccs_update_aggregator_entry(c Line 423  static int ccs_update_aggregator_entry(c
423                                         const char *aggregated_name,                                         const char *aggregated_name,
424                                         const bool is_delete)                                         const bool is_delete)
425  {  {
426          struct ccs_aggregator_entry *new_entry;          struct ccs_aggregator_entry *entry = NULL;
427          struct ccs_aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
428          static DEFINE_MUTEX(lock);          struct ccs_aggregator_entry e = { };
429          const struct ccs_path_info *saved_original_name;          int error = is_delete ? -ENOENT : -ENOMEM;
430          const struct ccs_path_info *saved_aggregated_name;          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
431          int error = -ENOMEM;              !ccs_is_correct_path(aggregated_name, 1, -1, -1))
         if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) ||  
             !ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__))  
432                  return -EINVAL;                  return -EINVAL;
433          saved_original_name = ccs_save_name(original_name);          e.original_name = ccs_get_name(original_name);
434          saved_aggregated_name = ccs_save_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
435          if (!saved_original_name || !saved_aggregated_name)          if (!e.original_name || !e.aggregated_name)
436                  return -ENOMEM;                  goto out;
437          mutex_lock(&lock);          if (!is_delete)
438          list1_for_each_entry(ptr, &ccs_aggregator_list, list) {                  entry = kmalloc(sizeof(e), GFP_KERNEL);
439                  if (ptr->original_name != saved_original_name ||          mutex_lock(&ccs_policy_lock);
440                      ptr->aggregated_name != saved_aggregated_name)          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
441                    if (ccs_memcmp(ptr, &e, offsetof(typeof(e), original_name),
442                                   sizeof(e)))
443                          continue;                          continue;
444                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
445                  error = 0;                  error = 0;
446                  goto out;                  break;
447          }          }
448          if (is_delete) {          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
449                  error = -ENOENT;                  list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
450                  goto out;                  entry = NULL;
451                    error = 0;
452          }          }
453          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
         if (!new_entry)  
                 goto out;  
         new_entry->original_name = saved_original_name;  
         new_entry->aggregated_name = saved_aggregated_name;  
         list1_add_tail_mb(&new_entry->list, &ccs_aggregator_list);  
         error = 0;  
454   out:   out:
455          mutex_unlock(&lock);          ccs_put_name(e.original_name);
456          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.aggregated_name);
457            kfree(entry);
458          return error;          return error;
459  }  }
460    
# Line 672  static int ccs_update_aggregator_entry(c Line 464  static int ccs_update_aggregator_entry(c
464   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
465   *   *
466   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
467     *
468     * Caller holds ccs_read_lock().
469   */   */
470  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
471  {  {
472          struct list1_head *pos;          struct list_head *pos;
473          list1_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {          bool done = true;
474            ccs_assert_read_lock();
475            list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
476                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
477                  ptr = list1_entry(pos, struct ccs_aggregator_entry, list);                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);
478                  if (ptr->is_deleted)                  if (ptr->is_deleted)
479                          continue;                          continue;
480                  if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, CCS_KEYWORD_AGGREGATOR "%s %s\n",
481                                     ptr->original_name->name,                                       ptr->original_name->name,
482                                     ptr->aggregated_name->name))                                       ptr->aggregated_name->name);
483                          goto out;                  if (!done)
484                            break;
485          }          }
486          return true;          return done;
  out:  
         return false;  
487  }  }
488    
489  /**  /**
# Line 701  bool ccs_read_aggregator_policy(struct c Line 496  bool ccs_read_aggregator_policy(struct c
496   */   */
497  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator_policy(char *data, const bool is_delete)
498  {  {
499          char *cp = strchr(data, ' ');          char *w[2];
500          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
501                  return -EINVAL;                  return -EINVAL;
502          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return ccs_update_aggregator_entry(data, cp, is_delete);  
503  }  }
504    
505  /* Domain create/delete handler. */  /* Domain create/delete handler. */
# Line 723  int ccs_delete_domain(char *domainname) Line 517  int ccs_delete_domain(char *domainname)
517          struct ccs_path_info name;          struct ccs_path_info name;
518          name.name = domainname;          name.name = domainname;
519          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
520          mutex_lock(&ccs_domain_list_lock);          mutex_lock(&ccs_policy_lock);
521          /* Is there an active domain? */          /* Is there an active domain? */
522          list1_for_each_entry(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
523                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
524                  if (domain == &ccs_kernel_domain)                  if (domain == &ccs_kernel_domain)
525                          continue;                          continue;
# Line 735  int ccs_delete_domain(char *domainname) Line 529  int ccs_delete_domain(char *domainname)
529                  domain->is_deleted = true;                  domain->is_deleted = true;
530                  break;                  break;
531          }          }
532          mutex_unlock(&ccs_domain_list_lock);          mutex_unlock(&ccs_policy_lock);
533          return 0;          return 0;
534  }  }
535    
# Line 748  int ccs_delete_domain(char *domainname) Line 542  int ccs_delete_domain(char *domainname)
542   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
543   */   */
544  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
545                                                    const u8 profile)                                                        const u8 profile)
546  {  {
547          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *entry;
548            struct ccs_domain_info *domain;
549          const struct ccs_path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
550          mutex_lock(&ccs_domain_list_lock);          bool found = false;
551          domain = ccs_find_domain(domainname);  
552          if (domain)          if (!ccs_is_correct_domain(domainname))
553                  goto out;                  return NULL;
554          if (!ccs_is_correct_domain(domainname, __func__))          saved_domainname = ccs_get_name(domainname);
                 goto out;  
         saved_domainname = ccs_save_name(domainname);  
555          if (!saved_domainname)          if (!saved_domainname)
556                  goto out;                  return NULL;
557          /* Can I reuse memory of deleted domain? */          entry = kzalloc(sizeof(*entry), GFP_KERNEL);
558          list1_for_each_entry(domain, &ccs_domain_list, list) {          mutex_lock(&ccs_policy_lock);
559                  struct task_struct *p;          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
560                  struct ccs_acl_info *ptr;                  if (domain->is_deleted ||
561                  bool flag;                      ccs_pathcmp(saved_domainname, domain->domainname))
                 if (!domain->is_deleted ||  
                     domain->domainname != saved_domainname)  
                         continue;  
                 flag = false;  
                 /***** CRITICAL SECTION START *****/  
                 read_lock(&tasklist_lock);  
                 for_each_process(p) {  
                         if (ccs_task_domain(p) != domain)  
                                 continue;  
                         flag = true;  
                         break;  
                 }  
                 read_unlock(&tasklist_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (flag)  
562                          continue;                          continue;
563                  list1_for_each_entry(ptr, &domain->acl_info_list, list) {                  found = true;
564                          ptr->type |= ACL_DELETED;                  break;
                 }  
                 ccs_set_domain_flag(domain, true, domain->flags);  
                 domain->profile = profile;  
                 domain->quota_warned = false;  
                 mb(); /* Avoid out-of-order execution. */  
                 domain->is_deleted = false;  
                 goto out;  
         }  
         /* No memory reusable. Create using new memory. */  
         domain = ccs_alloc_element(sizeof(*domain));  
         if (domain) {  
                 INIT_LIST1_HEAD(&domain->acl_info_list);  
                 domain->domainname = saved_domainname;  
                 domain->profile = profile;  
                 list1_add_tail_mb(&domain->list, &ccs_domain_list);  
         }  
  out:  
         mutex_unlock(&ccs_domain_list_lock);  
         return domain;  
 }  
   
 /**  
  * 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;  
565          }          }
566          return true;          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
567   out:                  INIT_LIST_HEAD(&entry->acl_info_list);
568          return false;                  entry->domainname = saved_domainname;
569                    saved_domainname = NULL;
570                    entry->profile = profile;
571                    list_add_tail_rcu(&entry->list, &ccs_domain_list);
572                    domain = entry;
573                    entry = NULL;
574                    found = true;
575            }
576            mutex_unlock(&ccs_policy_lock);
577            ccs_put_name(saved_domainname);
578            kfree(entry);
579            return found ? domain : NULL;
580  }  }
581    
582  /**  /**
# Line 866  static bool ccs_get_argv0(struct ccs_exe Line 585  static bool ccs_get_argv0(struct ccs_exe
585   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
586   *   *
587   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
588     *
589     * Caller holds ccs_read_lock().
590   */   */
591  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve_entry *ee)
592  {  {
# Line 879  static int ccs_find_next_domain(struct c Line 600  static int ccs_find_next_domain(struct c
600          const u32 ccs_flags = current->ccs_flags;          const u32 ccs_flags = current->ccs_flags;
601          char *new_domain_name = NULL;          char *new_domain_name = NULL;
602          struct ccs_path_info rn; /* real name */          struct ccs_path_info rn; /* real name */
         struct ccs_path_info sn; /* symlink name */  
603          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
604          int retval;          int retval;
605            ccs_assert_read_lock();
606   retry:   retry:
607          current->ccs_flags = ccs_flags;          current->ccs_flags = ccs_flags;
608          r->cond = NULL;          r->cond = NULL;
609          /* Get realpath of program and symbolic link. */          /* Get symlink's pathname of program. */
610          retval = ccs_realpath_both(bprm->filename, ee);          retval = ccs_symlink_path(bprm->filename, ee);
611          if (retval < 0)          if (retval < 0)
612                  goto out;                  goto out;
613    
614          rn.name = ee->program_path;          rn.name = ee->program_path;
615          ccs_fill_path_info(&rn);          ccs_fill_path_info(&rn);
         sn.name = ee->tmp;  
         ccs_fill_path_info(&sn);  
616          ln.name = ccs_get_last_name(r->domain);          ln.name = ccs_get_last_name(r->domain);
617          ccs_fill_path_info(&ln);          ccs_fill_path_info(&ln);
618    
# Line 911  static int ccs_find_next_domain(struct c Line 630  static int ccs_find_next_domain(struct c
630                  goto calculate_domain;                  goto calculate_domain;
631          }          }
632    
         /* Check 'alias' directive. */  
         if (ccs_pathcmp(&rn, &sn)) {  
                 struct ccs_alias_entry *ptr;  
                 /* Is this program allowed to be called via symbolic links? */  
                 list1_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;  
                 }  
         }  
         /* 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;  
                 }  
         }  
   
633          /* Check 'aggregator' directive. */          /* Check 'aggregator' directive. */
634          {          {
635                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
636                  /* Is this program allowed to be aggregated? */                  /* Is this program allowed to be aggregated? */
637                  list1_for_each_entry(ptr, &ccs_aggregator_list, list) {                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
638                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
639                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
640                                  continue;                                  continue;
# Line 967  static int ccs_find_next_domain(struct c Line 647  static int ccs_find_next_domain(struct c
647    
648          /* Check execute permission. */          /* Check execute permission. */
649          r->mode = mode;          r->mode = mode;
650          retval = ccs_check_exec_perm(r, &rn);          retval = ccs_exec_perm(r, &rn);
651          if (retval == 1)          if (retval == 1)
652                  goto retry;                  goto retry;
653          if (retval < 0)          if (retval < 0)
# Line 1000  static int ccs_find_next_domain(struct c Line 680  static int ccs_find_next_domain(struct c
680          if (domain)          if (domain)
681                  goto done;                  goto done;
682          if (is_enforce) {          if (is_enforce) {
683                  int error = ccs_check_supervisor(r,                  int error = ccs_supervisor(r,
684                                                   "# wants to create domain\n"                                                   "# wants to create domain\n"
685                                                   "%s\n", new_domain_name);                                                   "%s\n", new_domain_name);
686                  if (error == 1)                  if (error == 1)
# Line 1010  static int ccs_find_next_domain(struct c Line 690  static int ccs_find_next_domain(struct c
690          }          }
691          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
692          if (domain)          if (domain)
693                  ccs_audit_domain_creation_log(domain);                  ccs_audit_domain_creation_log(r->domain);
694   done:   done:
695          if (!domain) {          if (!domain) {
696                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
697                         new_domain_name);                         new_domain_name);
698                  if (is_enforce)                  if (is_enforce)
699                          retval = -EPERM;                          retval = -EPERM;
700                  else {                  else {
701                          retval = 0;                          retval = 0;
702                          ccs_set_domain_flag(r->domain, false,                          r->domain->domain_transition_failed = true;
                                             DOMAIN_FLAGS_TRANSITION_FAILED);  
703                  }                  }
704          } else {          } else {
705                  retval = 0;                  retval = 0;
# Line 1032  static int ccs_find_next_domain(struct c Line 711  static int ccs_find_next_domain(struct c
711  }  }
712    
713  /**  /**
714   * ccs_check_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
715   *   *
716   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
717   *   *
718   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
719   */   */
720  static int ccs_check_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve_entry *ee)
721  {  {
722          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
723          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
# Line 1089  static int ccs_check_environ(struct ccs_ Line 768  static int ccs_check_environ(struct ccs_
768                          }                          }
769                          if (c)                          if (c)
770                                  continue;                                  continue;
771                          if (ccs_check_env_perm(r, arg_ptr)) {                          if (ccs_env_perm(r, arg_ptr)) {
772                                  error = -EPERM;                                  error = -EPERM;
773                                  break;                                  break;
774                          }                          }
# Line 1222  static DEFINE_SPINLOCK(ccs_execve_list_l Line 901  static DEFINE_SPINLOCK(ccs_execve_list_l
901   */   */
902  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
903  {  {
904          struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);          struct ccs_execve_entry *ee = kzalloc(sizeof(*ee), GFP_KERNEL);
905          if (!ee)          if (!ee)
906                  return NULL;                  return NULL;
907          memset(ee, 0, sizeof(*ee));          ee->program_path = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);
908          ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);
         ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);  
909          if (!ee->program_path || !ee->tmp) {          if (!ee->program_path || !ee->tmp) {
910                  ccs_free(ee->program_path);                  kfree(ee->program_path);
911                  ccs_free(ee->tmp);                  kfree(ee->tmp);
912                  ccs_free(ee);                  kfree(ee);
913                  return NULL;                  return NULL;
914          }          }
915            ee->reader_idx = ccs_read_lock();
916          /* ee->dump->data is allocated by ccs_dump_page(). */          /* ee->dump->data is allocated by ccs_dump_page(). */
917          ee->task = current;          ee->task = current;
918          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
# Line 1281  static void ccs_free_execve_entry(struct Line 960  static void ccs_free_execve_entry(struct
960          list_del(&ee->list);          list_del(&ee->list);
961          spin_unlock(&ccs_execve_list_lock);          spin_unlock(&ccs_execve_list_lock);
962          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
963          ccs_free(ee->program_path);          kfree(ee->program_path);
964          ccs_free(ee->tmp);          kfree(ee->tmp);
965          kfree(ee->dump.data);          kfree(ee->dump.data);
966          ccs_free(ee);          ccs_read_unlock(ee->reader_idx);
967            kfree(ee);
968  }  }
969    
970  /**  /**
# Line 1403  static int ccs_try_alt_exec(struct ccs_e Line 1083  static int ccs_try_alt_exec(struct ccs_e
1083                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
1084                  if (exe) {                  if (exe) {
1085                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1086                          ccs_free(exe);                          kfree(exe);
1087                  } else {                  } else {
1088                          exe = ee->tmp;                          exe = ee->tmp;
1089                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
# Line 1474  static int ccs_try_alt_exec(struct ccs_e Line 1154  static int ccs_try_alt_exec(struct ccs_e
1154                   * overwrite ee->program_path and ee->tmp.                   * overwrite ee->program_path and ee->tmp.
1155                   */                   */
1156                  const int len = strlen(ee->program_path) + 1;                  const int len = strlen(ee->program_path) + 1;
1157                  char *cp = kmalloc(len, GFP_KERNEL);                  char *cp = kzalloc(len, GFP_KERNEL);
1158                  if (!cp) {                  if (!cp) {
1159                          retval = -ENOMEM;                          retval = -ENOMEM;
1160                          goto out;                          goto out;
# Line 1506  static int ccs_try_alt_exec(struct ccs_e Line 1186  static int ccs_try_alt_exec(struct ccs_e
1186   * @type: Type of execute handler.   * @type: Type of execute handler.
1187   *   *
1188   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1189     *
1190     * Caller holds ccs_read_lock().
1191   */   */
1192  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1193                                       const u8 type)                                       const u8 type)
# Line 1513  static bool ccs_find_execute_handler(str Line 1195  static bool ccs_find_execute_handler(str
1195          struct task_struct *task = current;          struct task_struct *task = current;
1196          const struct ccs_domain_info *domain = ccs_current_domain();          const struct ccs_domain_info *domain = ccs_current_domain();
1197          struct ccs_acl_info *ptr;          struct ccs_acl_info *ptr;
1198            bool found = false;
1199            ccs_assert_read_lock();
1200          /*          /*
1201           * Don't use execute handler if the current process is           * Don't use execute handler if the current process is
1202           * marked as execute handler to avoid infinite execute handler loop.           * marked as execute handler to avoid infinite execute handler loop.
1203           */           */
1204          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1205                  return false;                  return false;
1206          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry(ptr, &domain->acl_info_list, list) {
1207                  struct ccs_execute_handler_record *acl;                  struct ccs_execute_handler_record *acl;
1208                  if (ptr->type != type)                  if (ptr->type != type)
1209                          continue;                          continue;
1210                  acl = container_of(ptr, struct ccs_execute_handler_record,                  acl = container_of(ptr, struct ccs_execute_handler_record,
1211                                     head);                                     head);
1212                  ee->handler = acl->handler;                  ee->handler = acl->handler;
1213                  return true;                  found = true;
1214                    break;
1215          }          }
1216          return false;          return found;
1217  }  }
1218    
1219  /**  /**
# Line 1546  bool ccs_dump_page(struct linux_binprm * Line 1231  bool ccs_dump_page(struct linux_binprm *
1231          struct page *page;          struct page *page;
1232          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_free_execve_entry(). */
1233          if (!dump->data) {          if (!dump->data) {
1234                  dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);
1235                  if (!dump->data)                  if (!dump->data)
1236                          return false;                          return false;
1237          }          }
# Line 1592  struct ccs_domain_info *ccs_fetch_next_d Line 1277  struct ccs_domain_info *ccs_fetch_next_d
1277          struct ccs_execve_entry *ee = ccs_find_execve_entry();          struct ccs_execve_entry *ee = ccs_find_execve_entry();
1278          struct ccs_domain_info *next_domain = NULL;          struct ccs_domain_info *next_domain = NULL;
1279          if (ee)          if (ee)
1280                  next_domain = ee->next_domain;                  next_domain = ee->r.domain;
1281          if (!next_domain)          if (!next_domain)
1282                  next_domain = ccs_current_domain();                  next_domain = ccs_current_domain();
1283          return next_domain;          return next_domain;
# Line 1614  int ccs_start_execve(struct linux_binprm Line 1299  int ccs_start_execve(struct linux_binprm
1299                  ccs_load_policy(bprm->filename);                  ccs_load_policy(bprm->filename);
1300          if (!ee)          if (!ee)
1301                  return -ENOMEM;                  return -ENOMEM;
1302          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);          ccs_init_request_info(&ee->r, NULL, CCS_MAC_EXECUTE);
1303          ee->r.ee = ee;          ee->r.ee = ee;
1304          ee->bprm = bprm;          ee->bprm = bprm;
1305          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1306          ee->obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1307          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1308          /* Clear manager flag. */          /* Clear manager flag. */
1309          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1310          if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {
1311                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1312                  if (!retval)                  if (!retval)
1313                          ccs_audit_execute_handler_log(ee, true);                          ccs_audit_execute_handler_log(ee, true);
# Line 1631  int ccs_start_execve(struct linux_binprm Line 1316  int ccs_start_execve(struct linux_binprm
1316          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1317          if (retval != -EPERM)          if (retval != -EPERM)
1318                  goto ok;                  goto ok;
1319          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1320                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1321                  if (!retval)                  if (!retval)
1322                          ccs_audit_execute_handler_log(ee, false);                          ccs_audit_execute_handler_log(ee, false);
# Line 1639  int ccs_start_execve(struct linux_binprm Line 1324  int ccs_start_execve(struct linux_binprm
1324   ok:   ok:
1325          if (retval < 0)          if (retval < 0)
1326                  goto out;                  goto out;
1327          ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);          ee->r.mode = ccs_flags(ee->r.domain, CCS_MAC_ENVIRON);
1328          retval = ccs_check_environ(ee);          retval = ccs_environ(ee);
1329          if (retval < 0)          if (retval < 0)
1330                  goto out;                  goto out;
         ee->next_domain = ee->r.domain;  
1331          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1332          retval = 0;          retval = 0;
1333   out:   out:
# Line 1656  int ccs_start_execve(struct linux_binprm Line 1340  int ccs_start_execve(struct linux_binprm
1340   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1341   *   *
1342   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1343     *
1344     * Caller holds ccs_read_lock().
1345   */   */
1346  void ccs_finish_execve(int retval)  void ccs_finish_execve(int retval)
1347  {  {
1348          struct task_struct *task = current;          struct task_struct *task = current;
1349          struct ccs_execve_entry *ee = ccs_find_execve_entry();          struct ccs_execve_entry *ee = ccs_find_execve_entry();
1350            ccs_assert_read_lock();
1351          task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;          task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1352          if (!ee)          if (!ee)
1353                  return;                  return;
# Line 1668  void ccs_finish_execve(int retval) Line 1355  void ccs_finish_execve(int retval)
1355                  goto out;                  goto out;
1356          /* Proceed to next domain if execution suceeded. */          /* Proceed to next domain if execution suceeded. */
1357          task->ccs_domain_info = ee->r.domain;          task->ccs_domain_info = ee->r.domain;
         mb(); /* Make domain transition visible to other CPUs. */  
1358          /* Mark the current process as execute handler. */          /* Mark the current process as execute handler. */
1359          if (ee->handler)          if (ee->handler)
1360                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
# Line 1678  void ccs_finish_execve(int retval) Line 1364  void ccs_finish_execve(int retval)
1364   out:   out:
1365          ccs_free_execve_entry(ee);          ccs_free_execve_entry(ee);
1366  }  }
   
 #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.2539  
changed lines
  Added in v.2922

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