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

Subversion リポジトリの参照

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

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

trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c revision 2346 by kumaneko, Wed Apr 1 05:40:08 2009 UTC trunk/1.7.x/ccs-patch/security/ccsecurity/domain.c revision 3626 by kumaneko, Wed May 5 02:06:14 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Version: 1.7.2+   2010/05/05
  *  
  * Version: 1.6.7   2009/04/01  
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>
19  #endif  #endif
20    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
21  /* For compatibility with older kernels. */  #include <linux/fs_struct.h>
 #ifndef for_each_process  
 #define for_each_process for_each_task  
22  #endif  #endif
23    #include "internal.h"
24    
25  /* Variables definitions.*/  /* Variables definitions.*/
26    
# Line 32  Line 28 
28  struct ccs_domain_info ccs_kernel_domain;  struct ccs_domain_info ccs_kernel_domain;
29    
30  /* The list for "struct ccs_domain_info". */  /* The list for "struct ccs_domain_info". */
31  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 *****/  
 }  
   
 /**  
  * 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) {  
                 /*  
                  * 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;  
 }  
32    
33  /**  /**
34   * ccs_audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
# Line 169  int ccs_del_domain_acl(struct ccs_acl_in Line 41  int ccs_del_domain_acl(struct ccs_acl_in
41  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
42                                           const bool is_default)                                           const bool is_default)
43  {  {
44            int error;
45          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
46            struct ccs_domain_info *domain = r->domain;
47          const char *handler = ee->handler->name;          const char *handler = ee->handler->name;
48          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);          r->type = CCS_MAC_FILE_EXECUTE;
49          return ccs_write_audit_log(true, r, "%s %s\n",          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
50                                     is_default ? KEYWORD_EXECUTE_HANDLER :          r->domain = ee->previous_domain;
51                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);          error = ccs_write_audit_log(true, r, "%s %s\n",
52                                        is_default ? CCS_KEYWORD_EXECUTE_HANDLER :
53                                        CCS_KEYWORD_DENIED_EXECUTE_HANDLER,
54                                        handler);
55            r->domain = domain;
56            return error;
57  }  }
58    
59  /**  /**
# Line 187  static int ccs_audit_execute_handler_log Line 66  static int ccs_audit_execute_handler_log
66  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
67  {  {
68          struct ccs_request_info r;          struct ccs_request_info r;
69          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);
70          return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);          return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
71  }  }
72    
73  /* The list for "struct ccs_domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
74  static LIST1_HEAD(ccs_domain_initializer_list);  LIST_HEAD(ccs_domain_initializer_list);
75    
76  /**  /**
77   * 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 209  static int ccs_update_domain_initializer Line 88  static int ccs_update_domain_initializer
88                                                 const bool is_not,                                                 const bool is_not,
89                                                 const bool is_delete)                                                 const bool is_delete)
90  {  {
         struct ccs_domain_initializer_entry *new_entry;  
91          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
92          static DEFINE_MUTEX(lock);          struct ccs_domain_initializer_entry e = { .is_not = is_not };
93          const struct ccs_path_info *saved_program;          int error = is_delete ? -ENOENT : -ENOMEM;
94          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__))  
95                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
96          if (domainname) {          if (domainname) {
97                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
98                      ccs_is_correct_path(domainname, 1, -1, -1, __func__))                      ccs_is_correct_path(domainname, 1, -1, -1))
99                          is_last_name = true;                          e.is_last_name = true;
100                  else if (!ccs_is_correct_domain(domainname, __func__))                  else if (!ccs_is_correct_domain(domainname))
101                          return -EINVAL;                          return -EINVAL;
102                  saved_domainname = ccs_save_name(domainname);                  e.domainname = ccs_get_name(domainname);
103                  if (!saved_domainname)                  if (!e.domainname)
104                          return -ENOMEM;                          goto out;
105          }          }
106          saved_program = ccs_save_name(program);          e.program = ccs_get_name(program);
107          if (!saved_program)          if (!e.program)
108                  return -ENOMEM;                  goto out;
109          mutex_lock(&lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
110          list1_for_each_entry(ptr, &ccs_domain_initializer_list, list) {                  goto out;
111                  if (ptr->is_not != is_not ||          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
112                      ptr->domainname != saved_domainname ||                  if (!ccs_is_same_domain_initializer_entry(ptr, &e))
                     ptr->program != saved_program)  
113                          continue;                          continue;
114                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
115                  error = 0;                  error = 0;
116                  goto out;                  break;
117          }          }
118          if (is_delete) {          if (!is_delete && error) {
119                  error = -ENOENT;                  struct ccs_domain_initializer_entry *entry =
120                  goto out;                          ccs_commit_ok(&e, sizeof(e));
121                    if (entry) {
122                            list_add_tail_rcu(&entry->list,
123                                              &ccs_domain_initializer_list);
124                            error = 0;
125                    }
126          }          }
127          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;  
128   out:   out:
129          mutex_unlock(&lock);          ccs_put_name(e.domainname);
130          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.program);
131          return error;          return error;
132  }  }
133    
# Line 266  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 list1_head *pos;          struct list_head *pos;
146          list1_for_each_cookie(pos, head->read_var2,          bool done = true;
147                                &ccs_domain_initializer_list) {          list_for_each_cookie(pos, head->read_var2,
148                                 &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 = list1_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 285  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                  if (!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                          goto out;                  if (!done)
166                            break;
167          }          }
168          return true;          return done;
  out:  
         return false;  
169  }  }
170    
171  /**  /**
# Line 326  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 333  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          list1_for_each_entry(ptr, &ccs_domain_initializer_list, list) {          list_for_each_entry_rcu(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 347  static bool ccs_is_domain_initializer(co Line 222  static bool ccs_is_domain_initializer(co
222                  }                  }
223                  if (ccs_pathcmp(ptr->program, program))                  if (ccs_pathcmp(ptr->program, program))
224                          continue;                          continue;
225                  if (ptr->is_not)                  if (ptr->is_not) {
226                          return false;                          flag = false;
227                            break;
228                    }
229                  flag = true;                  flag = true;
230          }          }
231          return flag;          return flag;
232  }  }
233    
234  /* The list for "struct ccs_domain_keeper_entry". */  /* The list for "struct ccs_domain_keeper_entry". */
235  static LIST1_HEAD(ccs_domain_keeper_list);  LIST_HEAD(ccs_domain_keeper_list);
236    
237  /**  /**
238   * 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 372  static int ccs_update_domain_keeper_entr Line 249  static int ccs_update_domain_keeper_entr
249                                            const bool is_not,                                            const bool is_not,
250                                            const bool is_delete)                                            const bool is_delete)
251  {  {
         struct ccs_domain_keeper_entry *new_entry;  
252          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
253          const struct ccs_path_info *saved_domainname;          struct ccs_domain_keeper_entry e = { .is_not = is_not };
254          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;  
255          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
256              ccs_is_correct_path(domainname, 1, -1, -1, __func__))              ccs_is_correct_path(domainname, 1, -1, -1))
257                  is_last_name = true;                  e.is_last_name = true;
258          else if (!ccs_is_correct_domain(domainname, __func__))          else if (!ccs_is_correct_domain(domainname))
259                  return -EINVAL;                  return -EINVAL;
260          if (program) {          if (program) {
261                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))                  if (!ccs_is_correct_path(program, 1, -1, -1))
262                          return -EINVAL;                          return -EINVAL;
263                  saved_program = ccs_save_name(program);                  e.program = ccs_get_name(program);
264                  if (!saved_program)                  if (!e.program)
265                          return -ENOMEM;                          goto out;
266          }          }
267          saved_domainname = ccs_save_name(domainname);          e.domainname = ccs_get_name(domainname);
268          if (!saved_domainname)          if (!e.domainname)
269                  return -ENOMEM;                  goto out;
270          mutex_lock(&lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
271          list1_for_each_entry(ptr, &ccs_domain_keeper_list, list) {                  goto out;
272                  if (ptr->is_not != is_not ||          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
273                      ptr->domainname != saved_domainname ||                  if (!ccs_is_same_domain_keeper_entry(ptr, &e))
                     ptr->program != saved_program)  
274                          continue;                          continue;
275                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
276                  error = 0;                  error = 0;
277                  goto out;                  break;
278          }          }
279          if (is_delete) {          if (!is_delete && error) {
280                  error = -ENOENT;                  struct ccs_domain_keeper_entry *entry =
281                  goto out;                          ccs_commit_ok(&e, sizeof(e));
282                    if (entry) {
283                            list_add_tail_rcu(&entry->list,
284                                              &ccs_domain_keeper_list);
285                            error = 0;
286                    }
287          }          }
288          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;  
289   out:   out:
290          mutex_unlock(&lock);          ccs_put_name(e.domainname);
291          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.program);
292          return error;          return error;
293  }  }
294    
# Line 449  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 list1_head *pos;          struct list_head *pos;
327          list1_for_each_cookie(pos, head->read_var2, &ccs_domain_keeper_list) {          bool done = true;
328            list_for_each_cookie(pos, head->read_var2,
329                                 &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 = "";
333                  const char *program = "";                  const char *program = "";
334                  ptr = list1_entry(pos, struct ccs_domain_keeper_entry, list);                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
335                  if (ptr->is_deleted)                  if (ptr->is_deleted)
336                          continue;                          continue;
337                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 466  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                  if (!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                          goto out;                  if (!done)
346                            break;
347          }          }
348          return true;          return done;
  out:  
         return false;  
349  }  }
350    
351  /**  /**
# Line 485  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 492  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          list1_for_each_entry(ptr, &ccs_domain_keeper_list, list) {          list_for_each_entry_rcu(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 504  static bool ccs_is_domain_keeper(const s Line 378  static bool ccs_is_domain_keeper(const s
378                  }                  }
379                  if (ptr->program && ccs_pathcmp(ptr->program, program))                  if (ptr->program && ccs_pathcmp(ptr->program, program))
380                          continue;                          continue;
381                  if (ptr->is_not)                  if (ptr->is_not) {
382                          return false;                          flag = false;
383                            break;
384                    }
385                  flag = true;                  flag = true;
386          }          }
387          return flag;          return flag;
388  }  }
389    
 /* 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);  
 }  
   
390  /* The list for "struct ccs_aggregator_entry". */  /* The list for "struct ccs_aggregator_entry". */
391  static LIST1_HEAD(ccs_aggregator_list);  LIST_HEAD(ccs_aggregator_list);
392    
393  /**  /**
394   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
# Line 624  static int ccs_update_aggregator_entry(c Line 403  static int ccs_update_aggregator_entry(c
403                                         const char *aggregated_name,                                         const char *aggregated_name,
404                                         const bool is_delete)                                         const bool is_delete)
405  {  {
         struct ccs_aggregator_entry *new_entry;  
406          struct ccs_aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
407          static DEFINE_MUTEX(lock);          struct ccs_aggregator_entry e = { };
408          const struct ccs_path_info *saved_original_name;          int error = is_delete ? -ENOENT : -ENOMEM;
409          const struct ccs_path_info *saved_aggregated_name;          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
410          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__))  
411                  return -EINVAL;                  return -EINVAL;
412          saved_original_name = ccs_save_name(original_name);          e.original_name = ccs_get_name(original_name);
413          saved_aggregated_name = ccs_save_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
414          if (!saved_original_name || !saved_aggregated_name)          if (!e.original_name || !e.aggregated_name)
415                  return -ENOMEM;                  goto out;
416          mutex_lock(&lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
417          list1_for_each_entry(ptr, &ccs_aggregator_list, list) {                  goto out;
418                  if (ptr->original_name != saved_original_name ||          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
419                      ptr->aggregated_name != saved_aggregated_name)                  if (!ccs_is_same_aggregator_entry(ptr, &e))
420                          continue;                          continue;
421                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
422                  error = 0;                  error = 0;
423                  goto out;                  break;
424          }          }
425          if (is_delete) {          if (!is_delete && error) {
426                  error = -ENOENT;                  struct ccs_aggregator_entry *entry =
427                  goto out;                          ccs_commit_ok(&e, sizeof(e));
428                    if (entry) {
429                            list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
430                            error = 0;
431                    }
432          }          }
433          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;  
434   out:   out:
435          mutex_unlock(&lock);          ccs_put_name(e.original_name);
436          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.aggregated_name);
437          return error;          return error;
438  }  }
439    
# Line 669  static int ccs_update_aggregator_entry(c Line 443  static int ccs_update_aggregator_entry(c
443   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
444   *   *
445   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
446     *
447     * Caller holds ccs_read_lock().
448   */   */
449  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
450  {  {
451          struct list1_head *pos;          struct list_head *pos;
452          list1_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {          bool done = true;
453            list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
454                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
455                  ptr = list1_entry(pos, struct ccs_aggregator_entry, list);                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);
456                  if (ptr->is_deleted)                  if (ptr->is_deleted)
457                          continue;                          continue;
458                  if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, CCS_KEYWORD_AGGREGATOR "%s %s\n",
459                                     ptr->original_name->name,                                       ptr->original_name->name,
460                                     ptr->aggregated_name->name))                                       ptr->aggregated_name->name);
461                          goto out;                  if (!done)
462                            break;
463          }          }
464          return true;          return done;
  out:  
         return false;  
465  }  }
466    
467  /**  /**
# Line 698  bool ccs_read_aggregator_policy(struct c Line 474  bool ccs_read_aggregator_policy(struct c
474   */   */
475  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator_policy(char *data, const bool is_delete)
476  {  {
477          char *cp = strchr(data, ' ');          char *w[2];
478          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
479                  return -EINVAL;                  return -EINVAL;
480          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return ccs_update_aggregator_entry(data, cp, is_delete);  
481  }  }
482    
483  /* Domain create/delete/undelete handler. */  /* Domain create/delete handler. */
   
 /* #define DEBUG_DOMAIN_UNDELETE */  
484    
485  /**  /**
486   * ccs_delete_domain - Delete a domain.   * ccs_delete_domain - Delete a domain.
# Line 722  int ccs_delete_domain(char *domainname) Line 495  int ccs_delete_domain(char *domainname)
495          struct ccs_path_info name;          struct ccs_path_info name;
496          name.name = domainname;          name.name = domainname;
497          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
498          mutex_lock(&ccs_domain_list_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
499  #ifdef DEBUG_DOMAIN_UNDELETE                  return 0;
         printk(KERN_DEBUG "ccs_delete_domain %s\n", domainname);  
         list1_for_each_entry(domain, &ccs_domain_list, list) {  
                 if (ccs_pathcmp(domain->domainname, &name))  
                         continue;  
                 printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);  
         }  
 #endif  
500          /* Is there an active domain? */          /* Is there an active domain? */
501          list1_for_each_entry(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
                 struct ccs_domain_info *domain2;  
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;
505                  if (domain->is_deleted ||                  if (domain->is_deleted ||
506                      ccs_pathcmp(domain->domainname, &name))                      ccs_pathcmp(domain->domainname, &name))
507                          continue;                          continue;
508                  /* Mark already deleted domains as non undeletable. */                  domain->is_deleted = true;
                 list1_for_each_entry(domain2, &ccs_domain_list, list) {  
                         if (!domain2->is_deleted ||  
                             ccs_pathcmp(domain2->domainname, &name))  
                                 continue;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                         if (domain2->is_deleted != 255)  
                                 printk(KERN_DEBUG  
                                        "Marked %p as non undeletable\n",  
                                        domain2);  
 #endif  
                         domain2->is_deleted = 255;  
                 }  
                 /* Delete and mark active domain as undeletable. */  
                 domain->is_deleted = 1;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk(KERN_DEBUG "Marked %p as undeletable\n", domain);  
 #endif  
509                  break;                  break;
510          }          }
511          mutex_unlock(&ccs_domain_list_lock);          mutex_unlock(&ccs_policy_lock);
512          return 0;          return 0;
513  }  }
514    
515  /**  /**
  * ccs_undelete_domain - Undelete a domain.  
  *  
  * @domainname: The name of domain.  
  *  
  * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.  
  */  
 struct ccs_domain_info *ccs_undelete_domain(const char *domainname)  
 {  
         struct ccs_domain_info *domain;  
         struct ccs_domain_info *candidate_domain = NULL;  
         struct ccs_path_info name;  
         name.name = domainname;  
         ccs_fill_path_info(&name);  
         mutex_lock(&ccs_domain_list_lock);  
 #ifdef DEBUG_DOMAIN_UNDELETE  
         printk(KERN_DEBUG "ccs_undelete_domain %s\n", domainname);  
         list1_for_each_entry(domain, &ccs_domain_list, list) {  
                 if (ccs_pathcmp(domain->domainname, &name))  
                         continue;  
                 printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);  
         }  
 #endif  
         list1_for_each_entry(domain, &ccs_domain_list, list) {  
                 if (ccs_pathcmp(&name, domain->domainname))  
                         continue;  
                 if (!domain->is_deleted) {  
                         /* This domain is active. I can't undelete. */  
                         candidate_domain = NULL;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                         printk(KERN_DEBUG "%p is active. I can't undelete.\n",  
                                domain);  
 #endif  
                         break;  
                 }  
                 /* Is this domain undeletable? */  
                 if (domain->is_deleted == 1)  
                         candidate_domain = domain;  
         }  
         if (candidate_domain) {  
                 candidate_domain->is_deleted = 0;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk(KERN_DEBUG "%p was undeleted.\n", candidate_domain);  
 #endif  
         }  
         mutex_unlock(&ccs_domain_list_lock);  
         return candidate_domain;  
 }  
   
 /**  
516   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_find_or_assign_new_domain - Create a domain.
517   *   *
518   * @domainname: The name of domain.   * @domainname: The name of domain.
# Line 822  struct ccs_domain_info *ccs_undelete_dom Line 521  struct ccs_domain_info *ccs_undelete_dom
521   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
522   */   */
523  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,
524                                                    const u8 profile)                                                        const u8 profile)
525  {  {
526            struct ccs_domain_info *entry;
527          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
528          const struct ccs_path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
529          mutex_lock(&ccs_domain_list_lock);          bool found = false;
530          domain = ccs_find_domain(domainname);  
531          if (domain)          if (!ccs_is_correct_domain(domainname))
532                  goto out;                  return NULL;
533          if (!ccs_is_correct_domain(domainname, __func__))          saved_domainname = ccs_get_name(domainname);
                 goto out;  
         saved_domainname = ccs_save_name(domainname);  
534          if (!saved_domainname)          if (!saved_domainname)
535                    return NULL;
536            entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
537            if (mutex_lock_interruptible(&ccs_policy_lock))
538                  goto out;                  goto out;
539          /* Can I reuse memory of deleted domain? */          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
540          list1_for_each_entry(domain, &ccs_domain_list, list) {                  if (domain->is_deleted ||
541                  struct task_struct *p;                      ccs_pathcmp(saved_domainname, domain->domainname))
                 struct ccs_acl_info *ptr;  
                 bool flag;  
                 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)  
542                          continue;                          continue;
543  #ifdef DEBUG_DOMAIN_UNDELETE                  found = true;
544                  printk(KERN_DEBUG "Reusing %p %s\n", domain,                  break;
                        domain->domainname->name);  
 #endif  
                 list1_for_each_entry(ptr, &domain->acl_info_list, list) {  
                         ptr->type |= ACL_DELETED;  
                 }  
                 ccs_set_domain_flag(domain, true, domain->flags);  
                 domain->profile = profile;  
                 domain->quota_warned = false;  
                 mb(); /* Avoid out-of-order execution. */  
                 domain->is_deleted = 0;  
                 goto out;  
545          }          }
546          /* No memory reusable. Create using new memory. */          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
547          domain = ccs_alloc_element(sizeof(*domain));                  INIT_LIST_HEAD(&entry->acl_info_list);
548          if (domain) {                  entry->domainname = saved_domainname;
549                  INIT_LIST1_HEAD(&domain->acl_info_list);                  saved_domainname = NULL;
550                  domain->domainname = saved_domainname;                  entry->profile = profile;
551                  domain->profile = profile;                  list_add_tail_rcu(&entry->list, &ccs_domain_list);
552                  list1_add_tail_mb(&domain->list, &ccs_domain_list);                  domain = entry;
553                    entry = NULL;
554                    found = true;
555          }          }
556            mutex_unlock(&ccs_policy_lock);
557   out:   out:
558          mutex_unlock(&ccs_domain_list_lock);          ccs_put_name(saved_domainname);
559          return domain;          kfree(entry);
560  }          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;  
561  }  }
562    
563  /**  /**
# Line 944  static bool ccs_get_argv0(struct ccs_exe Line 566  static bool ccs_get_argv0(struct ccs_exe
566   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
567   *   *
568   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
569     *
570     * Caller holds ccs_read_lock().
571   */   */
572  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve_entry *ee)
573  {  {
# Line 952  static int ccs_find_next_domain(struct c Line 576  static int ccs_find_next_domain(struct c
576          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
577          const char *old_domain_name = r->domain->domainname->name;          const char *old_domain_name = r->domain->domainname->name;
578          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
         const u8 mode = r->mode;  
         const bool is_enforce = (mode == 3);  
579          const u32 ccs_flags = current->ccs_flags;          const u32 ccs_flags = current->ccs_flags;
580          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 */  
581          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
582          int retval;          int retval;
583            bool need_kfree = false;
584            ln.name = ccs_last_word(old_domain_name);
585            ccs_fill_path_info(&ln);
586   retry:   retry:
587          current->ccs_flags = ccs_flags;          current->ccs_flags = ccs_flags;
588          r->cond = NULL;          r->cond = NULL;
589          /* Get realpath of program and symbolic link. */          if (need_kfree) {
590          retval = ccs_realpath_both(bprm->filename, ee);                  kfree(rn.name);
591                    need_kfree = false;
592            }
593    
594            /* Get symlink's pathname of program. */
595            retval = ccs_symlink_path(bprm->filename, &rn);
596          if (retval < 0)          if (retval < 0)
597                  goto out;                  goto out;
598            need_kfree = true;
         rn.name = ee->program_path;  
         ccs_fill_path_info(&rn);  
         sn.name = ee->tmp;  
         ccs_fill_path_info(&sn);  
         ln.name = ccs_get_last_name(r->domain);  
         ccs_fill_path_info(&ln);  
599    
600          if (handler) {          if (handler) {
601                  if (ccs_pathcmp(&rn, handler)) {                  if (ccs_pathcmp(&rn, handler)) {
# Line 986  static int ccs_find_next_domain(struct c Line 608  static int ccs_find_next_domain(struct c
608                          }                          }
609                          goto out;                          goto out;
610                  }                  }
611                  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? */  
                 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;  
                 }  
         }  
   
         /* Check 'aggregator' directive. */  
         {  
612                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
613                  /* Is this program allowed to be aggregated? */                  /* Check 'aggregator' directive. */
614                  list1_for_each_entry(ptr, &ccs_aggregator_list, list) {                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
615                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
616                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
617                                  continue;                                  continue;
618                          strncpy(ee->program_path, ptr->aggregated_name->name,                          kfree(rn.name);
619                                  CCS_MAX_PATHNAME_LEN - 1);                          need_kfree = false;
620                          ccs_fill_path_info(&rn);                          /* This is OK because it is read only. */
621                            rn = *ptr->aggregated_name;
622                          break;                          break;
623                  }                  }
         }  
624    
625          /* Check execute permission. */                  /* Check execute permission. */
626          r->mode = mode;                  retval = ccs_exec_perm(r, &rn);
627          retval = ccs_check_exec_perm(r, &rn);                  if (retval == CCS_RETRY_REQUEST)
628          if (retval == 1)                          goto retry;
629                  goto retry;                  if (retval < 0)
630          if (retval < 0)                          goto out;
631                  goto out;          }
632    
633   calculate_domain:          /* Calculate domain to transit to. */
         new_domain_name = ee->tmp;  
634          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
635                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
636                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
637                           ROOT_NAME " " "%s", ee->program_path);                           rn.name);
638          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
639                  /*                  /*
640                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
# Line 1069  static int ccs_find_next_domain(struct c Line 647  static int ccs_find_next_domain(struct c
647                  domain = r->domain;                  domain = r->domain;
648          } else {          } else {
649                  /* Normal domain transition. */                  /* Normal domain transition. */
650                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
651                           "%s %s", old_domain_name, ee->program_path);                           old_domain_name, rn.name);
652          }          }
653          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
654                  goto done;                  goto done;
655          domain = ccs_find_domain(new_domain_name);          domain = ccs_find_domain(ee->tmp);
656          if (domain)          if (domain)
657                  goto done;                  goto done;
658          if (is_enforce) {          if (r->mode == CCS_CONFIG_ENFORCING) {
659                  int error = ccs_check_supervisor(r,                  int error = ccs_supervisor(r, "# wants to create domain\n"
660                                                   "# wants to create domain\n"                                             "%s\n", ee->tmp);
661                                                   "%s\n", new_domain_name);                  if (error == CCS_RETRY_REQUEST)
                 if (error == 1)  
662                          goto retry;                          goto retry;
663                  if (error < 0)                  if (error < 0)
664                          goto done;                          goto done;
665          }          }
666          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);
667          if (domain)          if (domain)
668                  ccs_audit_domain_creation_log(domain);                  ccs_audit_domain_creation_log(domain);
669   done:   done:
670          if (!domain) {          if (!domain) {
671                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
672                         new_domain_name);                  if (!r->domain->domain_transition_failed) {
673                  if (is_enforce)                          r->domain->domain_transition_failed = true;
674                          retval = -EPERM;                          ccs_write_audit_log(false, r,
675                  else {                                              CCS_KEYWORD_TRANSITION_FAILED
676                          retval = 0;                                              "\n");
677                          ccs_set_domain_flag(r->domain, false,                          printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
678                                              DOMAIN_FLAGS_TRANSITION_FAILED);                                 ee->tmp);
679                  }                  }
680          } else {          } else {
681                  retval = 0;                  retval = 0;
# Line 1106  static int ccs_find_next_domain(struct c Line 683  static int ccs_find_next_domain(struct c
683   out:   out:
684          if (domain)          if (domain)
685                  r->domain = domain;                  r->domain = domain;
686            if (need_kfree)
687                    kfree(rn.name);
688          return retval;          return retval;
689  }  }
690    
691  /**  /**
692   * ccs_check_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
693   *   *
694   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve_entry".
695   *   *
696   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
697   */   */
698  static int ccs_check_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve_entry *ee)
699  {  {
700          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
701          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
702          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
703            struct ccs_page_dump env_page = { };
704            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
705          int arg_len = 0;          int arg_len = 0;
706          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
707          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 1130  static int ccs_check_environ(struct ccs_ Line 711  static int ccs_check_environ(struct ccs_
711          int error = -ENOMEM;          int error = -ENOMEM;
712          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
713                  return 0;                  return 0;
714            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
715            if (!arg_ptr)
716                    goto out;
717          while (error == -ENOMEM) {          while (error == -ENOMEM) {
718                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
719                          goto out;                          goto out;
720                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
721                  /* Read. */                  /* Read. */
722                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
723                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
724                                  argv_count--;                                  argv_count--;
725                  }                  }
726                  if (argv_count) {                  if (argv_count) {
# Line 1145  static int ccs_check_environ(struct ccs_ Line 728  static int ccs_check_environ(struct ccs_
728                          continue;                          continue;
729                  }                  }
730                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
731                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
732                          const unsigned char c = kaddr[offset++];                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
                         if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {  
733                                  if (c == '=') {                                  if (c == '=') {
734                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
735                                  } else if (c == '\\') {                                  } else if (c == '\\') {
# Line 1167  static int ccs_check_environ(struct ccs_ Line 749  static int ccs_check_environ(struct ccs_
749                          }                          }
750                          if (c)                          if (c)
751                                  continue;                                  continue;
752                          if (ccs_check_env_perm(r, arg_ptr)) {                          if (ccs_env_perm(r, arg_ptr)) {
753                                  error = -EPERM;                                  error = -EPERM;
754                                  break;                                  break;
755                          }                          }
# Line 1182  static int ccs_check_environ(struct ccs_ Line 764  static int ccs_check_environ(struct ccs_
764   out:   out:
765          if (r->mode != 3)          if (r->mode != 3)
766                  error = 0;                  error = 0;
767            kfree(env_page.data);
768            kfree(arg_ptr);
769          return error;          return error;
770  }  }
771    
# Line 1232  static void ccs_unescape(unsigned char * Line 816  static void ccs_unescape(unsigned char *
816   *   *
817   * Returns number of directories to strip.   * Returns number of directories to strip.
818   */   */
819  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
820  {  {
821          int depth = 0;          int depth = 0;
         /***** CRITICAL SECTION START *****/  
822          ccs_realpath_lock();          ccs_realpath_lock();
823          for (;;) {          for (;;) {
824                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
# Line 1250  static inline int ccs_root_depth(struct Line 833  static inline int ccs_root_depth(struct
833                  depth++;                  depth++;
834          }          }
835          ccs_realpath_unlock();          ccs_realpath_unlock();
         /***** CRITICAL SECTION END *****/  
836          return depth;          return depth;
837  }  }
838    
# Line 1267  static int ccs_get_root_depth(void) Line 849  static int ccs_get_root_depth(void)
849  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
850          struct path root;          struct path root;
851  #endif  #endif
         /***** CRITICAL SECTION START *****/  
852          read_lock(&current->fs->lock);          read_lock(&current->fs->lock);
853  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
854          root = current->fs->root;          root = current->fs->root;
# Line 1279  static int ccs_get_root_depth(void) Line 860  static int ccs_get_root_depth(void)
860          vfsmnt = mntget(current->fs->rootmnt);          vfsmnt = mntget(current->fs->rootmnt);
861  #endif  #endif
862          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
         /***** CRITICAL SECTION END *****/  
863          depth = ccs_root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
864  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
865          path_put(&root);          path_put(&root);
# Line 1290  static int ccs_get_root_depth(void) Line 870  static int ccs_get_root_depth(void)
870          return depth;          return depth;
871  }  }
872    
 static LIST_HEAD(ccs_execve_list);  
 static DEFINE_SPINLOCK(ccs_execve_list_lock);  
   
 /**  
  * ccs_allocate_execve_entry - Allocate memory for execve().  
  *  
  * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.  
  */  
 static struct ccs_execve_entry *ccs_allocate_execve_entry(void)  
 {  
         struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);  
         if (!ee)  
                 return NULL;  
         memset(ee, 0, sizeof(*ee));  
         ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);  
         ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);  
         if (!ee->program_path || !ee->tmp) {  
                 ccs_free(ee->program_path);  
                 ccs_free(ee->tmp);  
                 ccs_free(ee);  
                 return NULL;  
         }  
         /* ee->dump->data is allocated by ccs_dump_page(). */  
         ee->task = current;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_add(&ee->list, &ccs_execve_list);  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         return ee;  
 }  
   
 /**  
  * ccs_find_execve_entry - Find ccs_execve_entry of current process.  
  *  
  * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.  
  */  
 static struct ccs_execve_entry *ccs_find_execve_entry(void)  
 {  
         struct task_struct *task = current;  
         struct ccs_execve_entry *ee = NULL;  
         struct ccs_execve_entry *p;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_for_each_entry(p, &ccs_execve_list, list) {  
                 if (p->task != task)  
                         continue;  
                 ee = p;  
                 break;  
         }  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         return ee;  
 }  
   
 /**  
  * ccs_free_execve_entry - Free memory for execve().  
  *  
  * @ee: Pointer to "struct ccs_execve_entry".  
  */  
 static void ccs_free_execve_entry(struct ccs_execve_entry *ee)  
 {  
         if (!ee)  
                 return;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_del(&ee->list);  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         ccs_free(ee->program_path);  
         ccs_free(ee->tmp);  
         kfree(ee->dump.data);  
         ccs_free(ee);  
 }  
   
873  /**  /**
874   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
875   *   *
# Line 1418  static int ccs_try_alt_exec(struct ccs_e Line 923  static int ccs_try_alt_exec(struct ccs_e
923          struct task_struct *task = current;          struct task_struct *task = current;
924    
925          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
926            ee->obj.path1.dentry = NULL;
927            ee->obj.path1.mnt = NULL;
928            ee->obj.validate_done = false;
929          allow_write_access(bprm->file);          allow_write_access(bprm->file);
930          fput(bprm->file);          fput(bprm->file);
931          bprm->file = NULL;          bprm->file = NULL;
# Line 1465  static int ccs_try_alt_exec(struct ccs_e Line 973  static int ccs_try_alt_exec(struct ccs_e
973                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
974                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
975                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
976                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           (pid_t) ccsecurity_exports.sys_getpid(),
977                           current_euid(), current_egid(), current_suid(),                           current_uid(), current_gid(), current_euid(),
978                           current_sgid(), current_fsuid(), current_fsgid(),                           current_egid(), current_suid(), current_sgid(),
979                             current_fsuid(), current_fsgid(),
980                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
981                           (u8) (ccs_flags >> 8));                           (u8) (ccs_flags >> 8));
982                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
# Line 1481  static int ccs_try_alt_exec(struct ccs_e Line 990  static int ccs_try_alt_exec(struct ccs_e
990                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
991                  if (exe) {                  if (exe) {
992                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
993                          ccs_free(exe);                          kfree(exe);
994                  } else {                  } else {
995                          exe = ee->tmp;                          exe = ee->tmp;
996                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
997                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
998                  }                  }
999                  if (retval < 0)                  if (retval < 0)
# Line 1495  static int ccs_try_alt_exec(struct ccs_e Line 1004  static int ccs_try_alt_exec(struct ccs_e
1004          /* Set argv[1] */          /* Set argv[1] */
1005          {          {
1006                  char *cp = ee->tmp;                  char *cp = ee->tmp;
1007                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1008                          CCS_EXEC_TMPSIZE - 1);                           ccs_current_domain()->domainname->name);
1009                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1010                  if (retval < 0)                  if (retval < 0)
1011                          goto out;                          goto out;
# Line 1506  static int ccs_try_alt_exec(struct ccs_e Line 1015  static int ccs_try_alt_exec(struct ccs_e
1015          /* Set argv[0] */          /* Set argv[0] */
1016          {          {
1017                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
1018                  char *cp = ee->program_path;                  int len = ee->handler->total_len + 1;
1019                  strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);                  char *cp = kmalloc(len, CCS_GFP_FLAGS);
1020                    if (!cp) {
1021                            retval = -ENOMEM;
1022                            goto out;
1023                    }
1024                    ee->handler_path = cp;
1025                    memmove(cp, ee->handler->name, len);
1026                  ccs_unescape(cp);                  ccs_unescape(cp);
1027                  retval = -ENOENT;                  retval = -ENOENT;
1028                  if (!*cp || *cp != '/')                  if (!*cp || *cp != '/')
# Line 1519  static int ccs_try_alt_exec(struct ccs_e Line 1034  static int ccs_try_alt_exec(struct ccs_e
1034                                  goto out;                                  goto out;
1035                          depth--;                          depth--;
1036                  }                  }
1037                  memmove(ee->program_path, cp, strlen(cp) + 1);                  memmove(ee->handler_path, cp, strlen(cp) + 1);
1038                  cp = ee->program_path;                  cp = ee->handler_path;
1039                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1040                  if (retval < 0)                  if (retval < 0)
1041                          goto out;                          goto out;
# Line 1532  static int ccs_try_alt_exec(struct ccs_e Line 1047  static int ccs_try_alt_exec(struct ccs_e
1047  #endif  #endif
1048  #endif  #endif
1049    
1050          /* OK, now restart the process with execute handler program's dentry. */          /*
1051          filp = open_exec(ee->program_path);           * OK, now restart the process with execute handler program's dentry.
1052             */
1053            filp = open_exec(ee->handler_path);
1054          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1055                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1056                  goto out;                  goto out;
1057          }          }
1058            ee->obj.path1.dentry = filp->f_dentry;
1059            ee->obj.path1.mnt = filp->f_vfsmnt;
1060          bprm->file = filp;          bprm->file = filp;
1061          bprm->filename = ee->program_path;          bprm->filename = ee->handler_path;
1062  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1063          bprm->interp = bprm->filename;          bprm->interp = bprm->filename;
1064  #endif  #endif
1065          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1066          if (retval < 0)          if (retval < 0)
1067                  goto out;                  goto out;
1068          {          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1069                  /*          retval = ccs_find_next_domain(ee);
1070                   * 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);  
         }  
1071   out:   out:
1072          return retval;          return retval;
1073  }  }
# Line 1584  static int ccs_try_alt_exec(struct ccs_e Line 1079  static int ccs_try_alt_exec(struct ccs_e
1079   * @type: Type of execute handler.   * @type: Type of execute handler.
1080   *   *
1081   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1082     *
1083     * Caller holds ccs_read_lock().
1084   */   */
1085  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1086                                       const u8 type)                                       const u8 type)
# Line 1591  static bool ccs_find_execute_handler(str Line 1088  static bool ccs_find_execute_handler(str
1088          struct task_struct *task = current;          struct task_struct *task = current;
1089          const struct ccs_domain_info *domain = ccs_current_domain();          const struct ccs_domain_info *domain = ccs_current_domain();
1090          struct ccs_acl_info *ptr;          struct ccs_acl_info *ptr;
1091            bool found = false;
1092          /*          /*
1093           * Don't use execute handler if the current process is           * Don't use execute handler if the current process is
1094           * marked as execute handler to avoid infinite execute handler loop.           * marked as execute handler to avoid infinite execute handler loop.
1095           */           */
1096          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1097                  return false;                  return false;
1098          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry(ptr, &domain->acl_info_list, list) {
1099                  struct ccs_execute_handler_record *acl;                  struct ccs_execute_handler_record *acl;
1100                  if (ptr->type != type)                  if (ptr->type != type)
1101                          continue;                          continue;
1102                  acl = container_of(ptr, struct ccs_execute_handler_record,                  acl = container_of(ptr, struct ccs_execute_handler_record,
1103                                     head);                                     head);
1104                  ee->handler = acl->handler;                  ee->handler = acl->handler;
1105                  return true;                  found = true;
1106                    break;
1107          }          }
1108          return false;          return found;
1109  }  }
1110    
1111  /**  /**
# Line 1622  bool ccs_dump_page(struct linux_binprm * Line 1121  bool ccs_dump_page(struct linux_binprm *
1121                     struct ccs_page_dump *dump)                     struct ccs_page_dump *dump)
1122  {  {
1123          struct page *page;          struct page *page;
1124          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_finish_execve(). */
1125          if (!dump->data) {          if (!dump->data) {
1126                  dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1127                  if (!dump->data)                  if (!dump->data)
1128                          return false;                          return false;
1129          }          }
# Line 1632  bool ccs_dump_page(struct linux_binprm * Line 1131  bool ccs_dump_page(struct linux_binprm *
1131  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1132          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1133                  return false;                  return false;
1134  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1135            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1136                    return false;
1137    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1138          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1139                  return false;                  return false;
1140  #else  #else
# Line 1647  bool ccs_dump_page(struct linux_binprm * Line 1149  bool ccs_dump_page(struct linux_binprm *
1149                   */                   */
1150                  char *kaddr = kmap_atomic(page, KM_USER0);                  char *kaddr = kmap_atomic(page, KM_USER0);
1151                  dump->page = page;                  dump->page = page;
1152                  memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);                  memcpy(dump->data + offset, kaddr + offset,
1153                           PAGE_SIZE - offset);
1154                  kunmap_atomic(kaddr, KM_USER0);                  kunmap_atomic(kaddr, KM_USER0);
1155          }          }
1156          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1157  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1158          put_page(page);          put_page(page);
1159  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1160            put_page(page);
1161    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1162          put_page(page);          put_page(page);
1163  #endif  #endif
1164          return true;          return true;
1165  }  }
1166    
1167  /**  /**
  * ccs_fetch_next_domain - Fetch next_domain from the list.  
  *  
  * Returns pointer to "struct ccs_domain_info" which will be used if execve()  
  * succeeds. This function does not return NULL.  
  */  
 struct ccs_domain_info *ccs_fetch_next_domain(void)  
 {  
         struct ccs_execve_entry *ee = ccs_find_execve_entry();  
         struct ccs_domain_info *next_domain = NULL;  
         if (ee)  
                 next_domain = ee->next_domain;  
         if (!next_domain)  
                 next_domain = ccs_current_domain();  
         return next_domain;  
 }  
   
 /**  
1168   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1169   *   *
1170   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1171     * @eep:  Pointer to "struct ccs_execve_entry *".
1172   *   *
1173   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1174   */   */
1175  int ccs_start_execve(struct linux_binprm *bprm)  static int ccs_start_execve(struct linux_binprm *bprm,
1176                                struct ccs_execve_entry **eep)
1177  {  {
1178          int retval;          int retval;
1179          struct task_struct *task = current;          struct task_struct *task = current;
1180          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();          struct ccs_execve_entry *ee;
1181          if (!ccs_policy_loaded)          *eep = NULL;
1182                  ccs_load_policy(bprm->filename);          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1183          if (!ee)          if (!ee)
1184                  return -ENOMEM;                  return -ENOMEM;
1185          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1186            if (!ee->tmp) {
1187                    kfree(ee);
1188                    return -ENOMEM;
1189            }
1190            ee->reader_idx = ccs_read_lock();
1191            /* ee->dump->data is allocated by ccs_dump_page(). */
1192            ee->previous_domain = task->ccs_domain_info;
1193            /* Clear manager flag. */
1194            task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1195            *eep = ee;
1196            ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);
1197          ee->r.ee = ee;          ee->r.ee = ee;
1198          ee->bprm = bprm;          ee->bprm = bprm;
1199          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1200          ee->obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1201          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1202          /* Clear manager flag. */          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {
         task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;  
         if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {  
1203                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1204                  if (!retval)                  if (!retval)
1205                          ccs_audit_execute_handler_log(ee, true);                          ccs_audit_execute_handler_log(ee, true);
# Line 1709  int ccs_start_execve(struct linux_binprm Line 1208  int ccs_start_execve(struct linux_binprm
1208          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1209          if (retval != -EPERM)          if (retval != -EPERM)
1210                  goto ok;                  goto ok;
1211          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1212                  retval = ccs_try_alt_exec(ee);                  retval = ccs_try_alt_exec(ee);
1213                  if (!retval)                  if (!retval)
1214                          ccs_audit_execute_handler_log(ee, false);                          ccs_audit_execute_handler_log(ee, false);
# Line 1717  int ccs_start_execve(struct linux_binprm Line 1216  int ccs_start_execve(struct linux_binprm
1216   ok:   ok:
1217          if (retval < 0)          if (retval < 0)
1218                  goto out;                  goto out;
1219          ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);          /*
1220          retval = ccs_check_environ(ee);           * Tell GC that I started execve().
1221             * Also, tell open_exec() to check read permission.
1222             */
1223            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
1224            /*
1225             * Make task->ccs_flags visible to GC before changing
1226             * task->ccs_domain_info .
1227             */
1228            smp_mb();
1229            /*
1230             * Proceed to the next domain in order to allow reaching via PID.
1231             * It will be reverted if execve() failed. Reverting is not good.
1232             * But it is better than being unable to reach via PID in interactive
1233             * enforcing mode.
1234             */
1235            task->ccs_domain_info = ee->r.domain;
1236            ee->r.type = CCS_MAC_ENVIRON;
1237            ee->r.mode = ccs_get_mode(ee->r.domain->profile, CCS_MAC_ENVIRON);
1238            retval = ccs_environ(ee);
1239          if (retval < 0)          if (retval < 0)
1240                  goto out;                  goto out;
         ee->next_domain = ee->r.domain;  
         task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;  
1241          retval = 0;          retval = 0;
1242   out:   out:
         if (retval)  
                 ccs_finish_execve(retval);  
1243          return retval;          return retval;
1244  }  }
1245    
# Line 1734  int ccs_start_execve(struct linux_binprm Line 1247  int ccs_start_execve(struct linux_binprm
1247   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1248   *   *
1249   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1250     * @ee:     Pointer to "struct ccs_execve_entry".
1251     *
1252     * Caller holds ccs_read_lock().
1253   */   */
1254  void ccs_finish_execve(int retval)  static void ccs_finish_execve(int retval, struct ccs_execve_entry *ee)
1255  {  {
1256          struct task_struct *task = current;          struct task_struct *task = current;
         struct ccs_execve_entry *ee = ccs_find_execve_entry();  
         task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;  
1257          if (!ee)          if (!ee)
1258                  return;                  return;
1259          if (retval < 0)          if (retval < 0) {
1260                  goto out;                  task->ccs_domain_info = ee->previous_domain;
1261          /* Proceed to next domain if execution suceeded. */                  /*
1262          task->ccs_domain_info = ee->r.domain;                   * Make task->ccs_domain_info visible to GC before changing
1263          mb(); /* Make domain transition visible to other CPUs. */                   * task->ccs_flags .
1264          /* Mark the current process as execute handler. */                   */
1265          if (ee->handler)                  smp_mb();
1266                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;          } else {
1267          /* Mark the current process as normal process. */                  /* Mark the current process as execute handler. */
1268          else                  if (ee->handler)
1269                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                          task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1270   out:                  /* Mark the current process as normal process. */
1271          ccs_free_execve_entry(ee);                  else
1272                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1273            }
1274            /* Tell GC that I finished execve(). */
1275            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1276            ccs_read_unlock(ee->reader_idx);
1277            kfree(ee->handler_path);
1278            kfree(ee->tmp);
1279            kfree(ee->dump.data);
1280            kfree(ee);
1281  }  }
1282    
 #else  
   
1283  /**  /**
1284   * ccs_start_execve - Prepare for execve() operation.   * ccs_may_transit - Check permission and do domain transition without execve().
1285   *   *
1286   * @bprm: Pointer to "struct linux_binprm".   * @domainname: Domainname to transit to.
1287     * @pathname: Pathname to check.
1288   *   *
1289   * Returns 0.   * Returns 0 on success, negative value otherwise.
1290     *
1291     * Caller holds ccs_read_lock().
1292   */   */
1293  int ccs_start_execve(struct linux_binprm *bprm)  int ccs_may_transit(const char *domainname, const char *pathname)
1294  {  {
1295  #ifdef CONFIG_SAKURA          struct ccs_path_info name;
1296          /* Clear manager flag. */          struct ccs_request_info r;
1297          current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          struct ccs_domain_info *domain;
1298          if (!ccs_policy_loaded)          int error;
1299                  ccs_load_policy(bprm->filename);          name.name = pathname;
1300  #endif          ccs_fill_path_info(&name);
1301          return 0;          /* Check allow_transit permission. */
1302            ccs_init_request_info(&r, NULL, CCS_MAC_FILE_TRANSIT);
1303            error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1304            if (error)
1305                    return error;
1306            /* Check destination domain. */
1307            domain = ccs_find_domain(domainname);
1308            if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1309                strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1310                    domain = ccs_find_or_assign_new_domain(domainname, r.profile);
1311                    if (domain)
1312                            ccs_audit_domain_creation_log(domain);
1313            }
1314            if (domain) {
1315                    error = 0;
1316                    current->ccs_domain_info = domain;
1317            } else {
1318                    error = -ENOENT;
1319            }
1320            return error;
1321  }  }
1322    
1323  /**  static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1324   * ccs_finish_execve - Clean up execve() operation.                                         struct pt_regs *regs)
  */  
 void ccs_finish_execve(int retval)  
1325  {  {
1326            struct ccs_execve_entry *ee;
1327            int retval;
1328            if (!ccs_policy_loaded)
1329                    ccsecurity_exports.load_policy(bprm->filename);
1330            retval = ccs_start_execve(bprm, &ee);
1331            if (!retval)
1332                    retval = search_binary_handler(bprm, regs);
1333            ccs_finish_execve(retval, ee);
1334            return retval;
1335  }  }
1336    
1337  #endif  void __init ccs_domain_init(void)
1338    {
1339            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1340    }

Legend:
Removed from v.2346  
changed lines
  Added in v.3626

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