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

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 1719 by kumaneko, Mon Oct 20 05:22:50 2008 UTC branches/ccs-patch/fs/tomoyo_domain.c revision 2779 by kumaneko, Sun Jul 19 07:00:09 2009 UTC
# Line 3  Line 3 
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Implementation of the Domain-Based Mandatory Access Control.
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Copyright (C) 2005-2009  NTT DATA CORPORATION
7   *   *
8   * Version: 1.6.5-pre   2008/10/20   * Version: 1.7.0-pre   2009/07/03
9   *   *
10   * 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.
11   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
12   *   *
13   */   */
14    
15  #include <linux/ccs_common.h>  #include <linux/slab.h>
 #include <linux/tomoyo.h>  
 #include <linux/realpath.h>  
16  #include <linux/highmem.h>  #include <linux/highmem.h>
17  #include <linux/binfmts.h>  #include <linux/version.h>
18  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
19  #include <linux/namei.h>  #include <linux/namei.h>
20  #include <linux/mount.h>  #include <linux/mount.h>
21  #endif  #endif
22    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
23    #include <linux/fs_struct.h>
24    #endif
25    #include <linux/ccs_common.h>
26    #include <linux/tomoyo.h>
27    
28  /* For compatibility with older kernels. */  /* For compatibility with older kernels. */
29  #ifndef for_each_process  #ifndef for_each_process
# Line 30  Line 33 
33  /* Variables definitions.*/  /* Variables definitions.*/
34    
35  /* The initial domain. */  /* The initial domain. */
36  struct domain_info KERNEL_DOMAIN;  struct ccs_domain_info ccs_kernel_domain;
   
 /* The list for "struct domain_info". */  
 LIST1_HEAD(domain_list);  
37    
38  #ifdef CONFIG_TOMOYO  /* The list for "struct ccs_domain_info". */
39    LIST_HEAD(ccs_domain_list);
 /* Domain creation lock. */  
 static DEFINE_MUTEX(domain_list_lock);  
   
 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */  
 struct domain_initializer_entry {  
         struct list1_head list;  
         const struct path_info *domainname;    /* This may be NULL */  
         const struct 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 domain_keeper_entry {  
         struct list1_head list;  
         const struct path_info *domainname;  
         const struct 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 aggregator_entry {  
         struct list1_head list;  
         const struct path_info *original_name;  
         const struct path_info *aggregated_name;  
         bool is_deleted;  
 };  
   
 /* Structure for "alias" keyword. */  
 struct alias_entry {  
         struct list1_head list;  
         const struct path_info *original_name;  
         const struct path_info *aliased_name;  
         bool is_deleted;  
 };  
   
 /**  
  * ccs_set_domain_flag - Set or clear domain's attribute flags.  
  *  
  * @domain:    Pointer to "struct 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 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 *****/  
 }  
40    
41  /**  /**
42   * ccs_get_last_name - Get last component of a domainname.   * ccs_get_last_name - Get last component of a domainname.
43   *   *
44   * @domain: Pointer to "struct domain_info".   * @domain: Pointer to "struct ccs_domain_info".
45   *   *
46   * Returns the last component of the domainname.   * Returns the last component of the domainname.
47   */   */
48  const char *ccs_get_last_name(const struct domain_info *domain)  const char *ccs_get_last_name(const struct ccs_domain_info *domain)
49  {  {
50          const char *cp0 = domain->domainname->name;          const char *cp0 = domain->domainname->name;
51          const char *cp1 = strrchr(cp0, ' ');          const char *cp1 = strrchr(cp0, ' ');
# Line 119  const char *ccs_get_last_name(const stru Line 57  const char *ccs_get_last_name(const stru
57  /**  /**
58   * ccs_add_domain_acl - Add the given ACL to the given domain.   * ccs_add_domain_acl - Add the given ACL to the given domain.
59   *   *
60   * @domain: Pointer to "struct domain_info". May be NULL.   * @domain: Pointer to "struct ccs_domain_info". May be NULL.
61   * @acl:    Pointer to "struct acl_info".   * @acl:    Pointer to "struct ccs_acl_info".
62   *   *
63   * Returns 0.   * Returns 0.
64   */   */
65  int ccs_add_domain_acl(struct domain_info *domain, struct acl_info *acl)  int ccs_add_domain_acl(struct ccs_domain_info *domain, struct ccs_acl_info *acl)
66  {  {
67          if (domain) {          if (domain) {
68                  /*                  if (acl->cond)
69                   * We need to serialize because this function is called by                          atomic_inc(&acl->cond->users);
70                   * various update functions.                  list_add_tail_rcu(&acl->list, &domain->acl_info_list);
                  */  
                 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 *****/  
71          } else {          } else {
72                  acl->type &= ~ACL_DELETED;                  acl->type &= ~ACL_DELETED;
73          }          }
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
74          return 0;          return 0;
75  }  }
76    
77  /**  /**
78   * ccs_del_domain_acl - Delete the given ACL from the domain.   * ccs_del_domain_acl - Delete the given ACL from the domain.
79   *   *
80   * @acl: Pointer to "struct acl_info". May be NULL.   * @acl: Pointer to "struct ccs_acl_info". May be NULL.
81   *   *
82   * Returns 0.   * Returns 0.
83   */   */
84  int ccs_del_domain_acl(struct acl_info *acl)  int ccs_del_domain_acl(struct ccs_acl_info *acl)
85  {  {
86          if (acl)          if (acl)
87                  acl->type |= ACL_DELETED;                  acl->type |= ACL_DELETED;
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
88          return 0;          return 0;
89  }  }
90    
91  /**  /**
92   * audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
93   *   *
94     * @ee:         Pointer to "struct ccs_execve_entry".
95   * @is_default: True if it is "execute_handler" log.   * @is_default: True if it is "execute_handler" log.
  * @handler:    The realpath of the handler.  
  * @bprm:       Pointer to "struct linux_binprm".  
96   *   *
97   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
98   */   */
99  static int audit_execute_handler_log(const bool is_default,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
100                                       const char *handler,                                           const bool is_default)
                                      struct linux_binprm *bprm)  
101  {  {
102          struct ccs_request_info r;          struct ccs_request_info *r = &ee->r;
103          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);          const char *handler = ee->handler->name;
104          r.bprm = bprm;          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);
105          return ccs_write_audit_log(true, &r, "%s %s\n",          return ccs_write_audit_log(true, r, "%s %s\n",
106                                     is_default ? KEYWORD_EXECUTE_HANDLER :                                     is_default ? KEYWORD_EXECUTE_HANDLER :
107                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);
108  }  }
109    
110  /**  /**
111   * audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
112   *   *
113   * @domain:  Pointer to "struct domain_info".   * @domain:  Pointer to "struct ccs_domain_info".
114   *   *
115   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
116   */   */
117  static int audit_domain_creation_log(struct domain_info *domain)  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
118  {  {
119            int error;
120          struct ccs_request_info r;          struct ccs_request_info r;
121          ccs_init_request_info(&r, domain, CCS_TOMOYO_MAC_FOR_FILE);          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);
122          return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
123            return error;
124  }  }
125    
126  /* The list for "struct domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
127  static LIST1_HEAD(domain_initializer_list);  LIST_HEAD(ccs_domain_initializer_list);
128    
129  /**  /**
130   * update_domain_initializer_entry - Update "struct domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
131   *   *
132   * @domainname: The name of domain. May be NULL.   * @domainname: The name of domain. May be NULL.
133   * @program:    The name of program.   * @program:    The name of program.
# Line 207  static LIST1_HEAD(domain_initializer_lis Line 136  static LIST1_HEAD(domain_initializer_lis
136   *   *
137   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
138   */   */
139  static int update_domain_initializer_entry(const char *domainname,  static int ccs_update_domain_initializer_entry(const char *domainname,
140                                             const char *program,                                                 const char *program,
141                                             const bool is_not,                                                 const bool is_not,
142                                             const bool is_delete)                                                 const bool is_delete)
143  {  {
144          struct domain_initializer_entry *new_entry;          struct ccs_domain_initializer_entry *entry = NULL;
145          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
146          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_program;
147          const struct path_info *saved_program;          const struct ccs_path_info *saved_domainname = NULL;
148          const struct path_info *saved_domainname = NULL;          int error = is_delete ? -ENOENT : -ENOMEM;
         int error = -ENOMEM;  
149          bool is_last_name = false;          bool is_last_name = false;
150          if (!ccs_is_correct_path(program, 1, -1, -1, __func__))          if (!ccs_is_correct_path(program, 1, -1, -1))
151                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
152          if (domainname) {          if (domainname) {
153                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
154                      ccs_is_correct_path(domainname, 1, -1, -1, __func__))                      ccs_is_correct_path(domainname, 1, -1, -1))
155                          is_last_name = true;                          is_last_name = true;
156                  else if (!ccs_is_correct_domain(domainname, __func__))                  else if (!ccs_is_correct_domain(domainname))
157                          return -EINVAL;                          return -EINVAL;
158                  saved_domainname = ccs_save_name(domainname);                  saved_domainname = ccs_get_name(domainname);
159                  if (!saved_domainname)                  if (!saved_domainname)
160                          return -ENOMEM;                          return -ENOMEM;
161          }          }
162          saved_program = ccs_save_name(program);          saved_program = ccs_get_name(program);
163          if (!saved_program)          if (!saved_program) {
164                    ccs_put_name(saved_domainname);
165                  return -ENOMEM;                  return -ENOMEM;
166          mutex_lock(&lock);          }
167          list1_for_each_entry(ptr, &domain_initializer_list, list) {          if (!is_delete)
168                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
169            mutex_lock(&ccs_policy_lock);
170            list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
171                  if (ptr->is_not != is_not ||                  if (ptr->is_not != is_not ||
172                      ptr->domainname != saved_domainname ||                      ptr->domainname != saved_domainname ||
173                      ptr->program != saved_program)                      ptr->program != saved_program)
174                          continue;                          continue;
175                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
176                  error = 0;                  error = 0;
177                  goto out;                  break;
178          }          }
179          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {
180                  error = -ENOENT;                  entry->domainname = saved_domainname;
181                  goto out;                  saved_domainname = NULL;
182                    entry->program = saved_program;
183                    saved_program = NULL;
184                    entry->is_not = is_not;
185                    entry->is_last_name = is_last_name;
186                    list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);
187                    entry = NULL;
188                    error = 0;
189          }          }
190          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
191          if (!new_entry)          ccs_put_name(saved_domainname);
192                  goto out;          ccs_put_name(saved_program);
193          new_entry->domainname = saved_domainname;          kfree(entry);
         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, &domain_initializer_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
194          return error;          return error;
195  }  }
196    
197  /**  /**
198   * ccs_read_domain_initializer_policy - Read "struct domain_initializer_entry" list.   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.
199   *   *
200   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
201   *   *
202   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
203     *
204     * Caller holds srcu_read_lock(&ccs_ss).
205   */   */
206  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
207  {  {
208          struct list1_head *pos;          struct list_head *pos;
209          list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) {          bool done = true;
210            list_for_each_cookie(pos, head->read_var2,
211                                 &ccs_domain_initializer_list) {
212                  const char *no;                  const char *no;
213                  const char *from = "";                  const char *from = "";
214                  const char *domain = "";                  const char *domain = "";
215                  struct domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
216                  ptr = list1_entry(pos, struct domain_initializer_entry, list);                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
217                                      list);
218                  if (ptr->is_deleted)                  if (ptr->is_deleted)
219                          continue;                          continue;
220                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 286  bool ccs_read_domain_initializer_policy( Line 222  bool ccs_read_domain_initializer_policy(
222                          from = " from ";                          from = " from ";
223                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
224                  }                  }
225                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
226                                     "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",
227                                     no, ptr->program->name, from, domain))                                       no, ptr->program->name, from, domain);
228                                  goto out;                  if (!done)
229                            break;
230          }          }
231          return true;          return done;
  out:  
         return false;  
232  }  }
233    
234  /**  /**
235   * ccs_write_domain_initializer_policy - Write "struct domain_initializer_entry" list.   * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.
236   *   *
237   * @data:      String to parse.   * @data:      String to parse.
238   * @is_not:    True if it is "no_initialize_domain" entry.   * @is_not:    True if it is "no_initialize_domain" entry.
# Line 311  int ccs_write_domain_initializer_policy( Line 246  int ccs_write_domain_initializer_policy(
246          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
247          if (cp) {          if (cp) {
248                  *cp = '\0';                  *cp = '\0';
249                  return update_domain_initializer_entry(cp + 6, data, is_not,                  return ccs_update_domain_initializer_entry(cp + 6, data,
250                                                         is_delete);                                                             is_not, is_delete);
251          }          }
252          return update_domain_initializer_entry(NULL, data, is_not, is_delete);          return ccs_update_domain_initializer_entry(NULL, data, is_not,
253                                                       is_delete);
254  }  }
255    
256  /**  /**
257   * is_domain_initializer - Check whether the given program causes domainname reinitialization.   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.
258   *   *
259   * @domainname: The name of domain.   * @domainname: The name of domain.
260   * @program:    The name of program.   * @program:    The name of program.
# Line 326  int ccs_write_domain_initializer_policy( Line 262  int ccs_write_domain_initializer_policy(
262   *   *
263   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
264   * false otherwise.   * false otherwise.
265     *
266     * Caller holds srcu_read_lock(&ccs_ss).
267   */   */
268  static bool is_domain_initializer(const struct path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
269                                    const struct path_info *program,                                        const struct ccs_path_info *program,
270                                    const struct path_info *last_name)                                        const struct ccs_path_info *last_name)
271  {  {
272          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
273          bool flag = false;          bool flag = false;
274          list1_for_each_entry(ptr,  &domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
275                  if (ptr->is_deleted)                  if (ptr->is_deleted)
276                          continue;                          continue;
277                  if (ptr->domainname) {                  if (ptr->domainname) {
# Line 347  static bool is_domain_initializer(const Line 285  static bool is_domain_initializer(const
285                  }                  }
286                  if (ccs_pathcmp(ptr->program, program))                  if (ccs_pathcmp(ptr->program, program))
287                          continue;                          continue;
288                  if (ptr->is_not)                  if (ptr->is_not) {
289                          return false;                          flag = false;
290                            break;
291                    }
292                  flag = true;                  flag = true;
293          }          }
294          return flag;          return flag;
295  }  }
296    
297  /* The list for "struct domain_keeper_entry". */  /* The list for "struct ccs_domain_keeper_entry". */
298  static LIST1_HEAD(domain_keeper_list);  LIST_HEAD(ccs_domain_keeper_list);
299    
300  /**  /**
301   * update_domain_keeper_entry - Update "struct domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
302   *   *
303   * @domainname: The name of domain.   * @domainname: The name of domain.
304   * @program:    The name of program. May be NULL.   * @program:    The name of program. May be NULL.
# Line 367  static LIST1_HEAD(domain_keeper_list); Line 307  static LIST1_HEAD(domain_keeper_list);
307   *   *
308   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
309   */   */
310  static int update_domain_keeper_entry(const char *domainname,  static int ccs_update_domain_keeper_entry(const char *domainname,
311                                        const char *program,                                            const char *program,
312                                        const bool is_not, const bool is_delete)                                            const bool is_not,
313  {                                            const bool is_delete)
314          struct domain_keeper_entry *new_entry;  {
315          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *entry = NULL;
316          const struct path_info *saved_domainname;          struct ccs_domain_keeper_entry *ptr;
317          const struct path_info *saved_program = NULL;          const struct ccs_path_info *saved_domainname;
318          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_program = NULL;
319          int error = -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
320          bool is_last_name = false;          bool is_last_name = false;
321          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
322              ccs_is_correct_path(domainname, 1, -1, -1, __func__))              ccs_is_correct_path(domainname, 1, -1, -1))
323                  is_last_name = true;                  is_last_name = true;
324          else if (!ccs_is_correct_domain(domainname, __func__))          else if (!ccs_is_correct_domain(domainname))
325                  return -EINVAL;                  return -EINVAL;
326          if (program) {          if (program) {
327                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))                  if (!ccs_is_correct_path(program, 1, -1, -1))
328                          return -EINVAL;                          return -EINVAL;
329                  saved_program = ccs_save_name(program);                  saved_program = ccs_get_name(program);
330                  if (!saved_program)                  if (!saved_program)
331                          return -ENOMEM;                          return -ENOMEM;
332          }          }
333          saved_domainname = ccs_save_name(domainname);          saved_domainname = ccs_get_name(domainname);
334          if (!saved_domainname)          if (!saved_domainname) {
335                    ccs_put_name(saved_program);
336                  return -ENOMEM;                  return -ENOMEM;
337          mutex_lock(&lock);          }
338          list1_for_each_entry(ptr, &domain_keeper_list, list) {          if (!is_delete)
339                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
340            mutex_lock(&ccs_policy_lock);
341            list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
342                  if (ptr->is_not != is_not ||                  if (ptr->is_not != is_not ||
343                      ptr->domainname != saved_domainname ||                      ptr->domainname != saved_domainname ||
344                      ptr->program != saved_program)                      ptr->program != saved_program)
345                          continue;                          continue;
346                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
347                  error = 0;                  error = 0;
348                  goto out;                  break;
349          }          }
350          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {
351                  error = -ENOENT;                  entry->domainname = saved_domainname;
352                  goto out;                  saved_domainname = NULL;
353                    entry->program = saved_program;
354                    saved_program = NULL;
355                    entry->is_not = is_not;
356                    entry->is_last_name = is_last_name;
357                    list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);
358                    entry = NULL;
359                    error = 0;
360          }          }
361          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
362          if (!new_entry)          ccs_put_name(saved_domainname);
363                  goto out;          ccs_put_name(saved_program);
364          new_entry->domainname = saved_domainname;          kfree(entry);
         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, &domain_keeper_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
365          return error;          return error;
366  }  }
367    
368  /**  /**
369   * ccs_write_domain_keeper_policy - Write "struct domain_keeper_entry" list.   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.
370   *   *
371   * @data:      String to parse.   * @data:      String to parse.
372   * @is_not:    True if it is "no_keep_domain" entry.   * @is_not:    True if it is "no_keep_domain" entry.
# Line 436  int ccs_write_domain_keeper_policy(char Line 379  int ccs_write_domain_keeper_policy(char
379          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
380          if (cp) {          if (cp) {
381                  *cp = '\0';                  *cp = '\0';
382                  return update_domain_keeper_entry(cp + 6, data,                  return ccs_update_domain_keeper_entry(cp + 6, data,
383                                                    is_not, is_delete);                                                        is_not, is_delete);
384          }          }
385          return update_domain_keeper_entry(data, NULL, is_not, is_delete);          return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);
386  }  }
387    
388  /**  /**
389   * ccs_read_domain_keeper_policy - Read "struct domain_keeper_entry" list.   * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.
390   *   *
391   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
392   *   *
393   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
394     *
395     * Caller holds srcu_read_lock(&ccs_ss).
396   */   */
397  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
398  {  {
399          struct list1_head *pos;          struct list_head *pos;
400          list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) {          bool done = true;
401                  struct domain_keeper_entry *ptr;          list_for_each_cookie(pos, head->read_var2,
402                                 &ccs_domain_keeper_list) {
403                    struct ccs_domain_keeper_entry *ptr;
404                  const char *no;                  const char *no;
405                  const char *from = "";                  const char *from = "";
406                  const char *program = "";                  const char *program = "";
407                  ptr = list1_entry(pos, struct domain_keeper_entry, list);                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
408                  if (ptr->is_deleted)                  if (ptr->is_deleted)
409                          continue;                          continue;
410                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 465  bool ccs_read_domain_keeper_policy(struc Line 412  bool ccs_read_domain_keeper_policy(struc
412                          from = " from ";                          from = " from ";
413                          program = ptr->program->name;                          program = ptr->program->name;
414                  }                  }
415                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
416                                     "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,
417                                     program, from, ptr->domainname->name))                                       program, from, ptr->domainname->name);
418                                  goto out;                  if (!done)
419                            break;
420          }          }
421          return true;          return done;
  out:  
         return false;  
422  }  }
423    
424  /**  /**
425   * is_domain_keeper - Check whether the given program causes domain transition suppression.   * ccs_is_domain_keeper - Check whether the given program causes domain transition suppression.
426   *   *
427   * @domainname: The name of domain.   * @domainname: The name of domain.
428   * @program:    The name of program.   * @program:    The name of program.
# Line 484  bool ccs_read_domain_keeper_policy(struc Line 430  bool ccs_read_domain_keeper_policy(struc
430   *   *
431   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
432   * false otherwise.   * false otherwise.
433     *
434     * Caller holds srcu_read_lock(&ccs_ss).
435   */   */
436  static bool is_domain_keeper(const struct path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
437                               const struct path_info *program,                                   const struct ccs_path_info *program,
438                               const struct path_info *last_name)                                   const struct ccs_path_info *last_name)
439  {  {
440          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
441          bool flag = false;          bool flag = false;
442          list1_for_each_entry(ptr, &domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
443                  if (ptr->is_deleted)                  if (ptr->is_deleted)
444                          continue;                          continue;
445                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
# Line 503  static bool is_domain_keeper(const struc Line 451  static bool is_domain_keeper(const struc
451                  }                  }
452                  if (ptr->program && ccs_pathcmp(ptr->program, program))                  if (ptr->program && ccs_pathcmp(ptr->program, program))
453                          continue;                          continue;
454                  if (ptr->is_not)                  if (ptr->is_not) {
455                          return false;                          flag = false;
456                            break;
457                    }
458                  flag = true;                  flag = true;
459          }          }
460          return flag;          return flag;
461  }  }
462    
463  /* The list for "struct alias_entry". */  /* The list for "struct ccs_aggregator_entry". */
464  static LIST1_HEAD(alias_list);  LIST_HEAD(ccs_aggregator_list);
   
 /**  
  * update_alias_entry - Update "struct 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 update_alias_entry(const char *original_name,  
                               const char *aliased_name,  
                               const bool is_delete)  
 {  
         struct alias_entry *new_entry;  
         struct alias_entry *ptr;  
         static DEFINE_MUTEX(lock);  
         const struct path_info *saved_original_name;  
         const struct 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, &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, &alias_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
         return error;  
 }  
465    
466  /**  /**
467   * ccs_read_alias_policy - Read "struct alias_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_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, &alias_list) {  
                 struct alias_entry *ptr;  
                 ptr = list1_entry(pos, struct 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 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 update_alias_entry(data, cp, is_delete);  
 }  
   
 /* The list for "struct aggregator_entry". */  
 static LIST1_HEAD(aggregator_list);  
   
 /**  
  * update_aggregator_entry - Update "struct aggregator_entry" list.  
468   *   *
469   * @original_name:   The original program's name.   * @original_name:   The original program's name.
470   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 619  static LIST1_HEAD(aggregator_list); Line 472  static LIST1_HEAD(aggregator_list);
472   *   *
473   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
474   */   */
475  static int update_aggregator_entry(const char *original_name,  static int ccs_update_aggregator_entry(const char *original_name,
476                                     const char *aggregated_name,                                         const char *aggregated_name,
477                                     const bool is_delete)                                         const bool is_delete)
478  {  {
479          struct aggregator_entry *new_entry;          struct ccs_aggregator_entry *entry = NULL;
480          struct aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
481          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_original_name;
482          const struct path_info *saved_original_name;          const struct ccs_path_info *saved_aggregated_name;
483          const struct path_info *saved_aggregated_name;          int error = is_delete ? -ENOENT : -ENOMEM;
484          int error = -ENOMEM;          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
485          if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) ||              !ccs_is_correct_path(aggregated_name, 1, -1, -1))
             !ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__))  
486                  return -EINVAL;                  return -EINVAL;
487          saved_original_name = ccs_save_name(original_name);          saved_original_name = ccs_get_name(original_name);
488          saved_aggregated_name = ccs_save_name(aggregated_name);          saved_aggregated_name = ccs_get_name(aggregated_name);
489          if (!saved_original_name || !saved_aggregated_name)          if (!saved_original_name || !saved_aggregated_name) {
490                    ccs_put_name(saved_original_name);
491                    ccs_put_name(saved_aggregated_name);
492                  return -ENOMEM;                  return -ENOMEM;
493          mutex_lock(&lock);          }
494          list1_for_each_entry(ptr, &aggregator_list, list) {          if (!is_delete)
495                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
496            mutex_lock(&ccs_policy_lock);
497            list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
498                  if (ptr->original_name != saved_original_name ||                  if (ptr->original_name != saved_original_name ||
499                      ptr->aggregated_name != saved_aggregated_name)                      ptr->aggregated_name != saved_aggregated_name)
500                          continue;                          continue;
501                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
502                  error = 0;                  error = 0;
503                  goto out;                  break;
504          }          }
505          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {
506                  error = -ENOENT;                  entry->original_name = saved_original_name;
507                  goto out;                  saved_original_name = NULL;
508                    entry->aggregated_name = saved_aggregated_name;
509                    saved_aggregated_name = NULL;
510                    list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
511                    entry = NULL;
512                    error = 0;
513          }          }
514          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
515          if (!new_entry)          ccs_put_name(saved_original_name);
516                  goto out;          ccs_put_name(saved_aggregated_name);
517          new_entry->original_name = saved_original_name;          kfree(entry);
         new_entry->aggregated_name = saved_aggregated_name;  
         list1_add_tail_mb(&new_entry->list, &aggregator_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
518          return error;          return error;
519  }  }
520    
521  /**  /**
522   * ccs_read_aggregator_policy - Read "struct aggregator_entry" list.   * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.
523   *   *
524   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
525   *   *
526   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
527     *
528     * Caller holds srcu_read_lock(&ccs_ss).
529   */   */
530  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
531  {  {
532          struct list1_head *pos;          struct list_head *pos;
533          list1_for_each_cookie(pos, head->read_var2, &aggregator_list) {          bool done = true;
534                  struct aggregator_entry *ptr;          list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
535                  ptr = list1_entry(pos, struct aggregator_entry, list);                  struct ccs_aggregator_entry *ptr;
536                    ptr = list_entry(pos, struct ccs_aggregator_entry, list);
537                  if (ptr->is_deleted)                  if (ptr->is_deleted)
538                          continue;                          continue;
539                  if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",
540                                     ptr->original_name->name,                                       ptr->original_name->name,
541                                     ptr->aggregated_name->name))                                       ptr->aggregated_name->name);
542                          goto out;                  if (!done)
543                            break;
544          }          }
545          return true;          return done;
  out:  
         return false;  
546  }  }
547    
548  /**  /**
549   * ccs_write_aggregator_policy - Write "struct aggregator_entry" list.   * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.
550   *   *
551   * @data:      String to parse.   * @data:      String to parse.
552   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
# Line 697  bool ccs_read_aggregator_policy(struct c Line 555  bool ccs_read_aggregator_policy(struct c
555   */   */
556  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator_policy(char *data, const bool is_delete)
557  {  {
558          char *cp = strchr(data, ' ');          char *w[2];
559          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
560                  return -EINVAL;                  return -EINVAL;
561          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return update_aggregator_entry(data, cp, is_delete);  
562  }  }
563    
564  /* Domain create/delete/undelete handler. */  /* Domain create/delete handler. */
   
 /* #define DEBUG_DOMAIN_UNDELETE */  
565    
566  /**  /**
567   * ccs_delete_domain - Delete a domain.   * ccs_delete_domain - Delete a domain.
# Line 717  int ccs_write_aggregator_policy(char *da Line 572  int ccs_write_aggregator_policy(char *da
572   */   */
573  int ccs_delete_domain(char *domainname)  int ccs_delete_domain(char *domainname)
574  {  {
575          struct domain_info *domain;          struct ccs_domain_info *domain;
576          struct path_info name;          struct ccs_path_info name;
577          name.name = domainname;          name.name = domainname;
578          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
579          mutex_lock(&domain_list_lock);          mutex_lock(&ccs_policy_lock);
 #ifdef DEBUG_DOMAIN_UNDELETE  
         printk(KERN_DEBUG "ccs_delete_domain %s\n", domainname);  
         list1_for_each_entry(domain, &domain_list, list) {  
                 if (ccs_pathcmp(domain->domainname, &name))  
                         continue;  
                 printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);  
         }  
 #endif  
580          /* Is there an active domain? */          /* Is there an active domain? */
581          list1_for_each_entry(domain, &domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
582                  struct domain_info *domain2;                  /* Never delete ccs_kernel_domain */
583                  /* Never delete KERNEL_DOMAIN */                  if (domain == &ccs_kernel_domain)
                 if (domain == &KERNEL_DOMAIN)  
584                          continue;                          continue;
585                  if (domain->is_deleted ||                  if (domain->is_deleted ||
586                      ccs_pathcmp(domain->domainname, &name))                      ccs_pathcmp(domain->domainname, &name))
587                          continue;                          continue;
588                  /* Mark already deleted domains as non undeletable. */                  domain->is_deleted = true;
                 list1_for_each_entry(domain2, &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  
589                  break;                  break;
590          }          }
591          mutex_unlock(&domain_list_lock);          mutex_unlock(&ccs_policy_lock);
592          return 0;          return 0;
593  }  }
594    
595  /**  /**
  * ccs_undelete_domain - Undelete a domain.  
  *  
  * @domainname: The name of domain.  
  *  
  * Returns pointer to "struct domain_info" on success, NULL otherwise.  
  */  
 struct domain_info *ccs_undelete_domain(const char *domainname)  
 {  
         struct domain_info *domain;  
         struct domain_info *candidate_domain = NULL;  
         struct path_info name;  
         name.name = domainname;  
         ccs_fill_path_info(&name);  
         mutex_lock(&domain_list_lock);  
 #ifdef DEBUG_DOMAIN_UNDELETE  
         printk(KERN_DEBUG "ccs_undelete_domain %s\n", domainname);  
         list1_for_each_entry(domain, &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, &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(&domain_list_lock);  
         return candidate_domain;  
 }  
   
 /**  
596   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_find_or_assign_new_domain - Create a domain.
597   *   *
598   * @domainname: The name of domain.   * @domainname: The name of domain.
599   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
600   *   *
601   * Returns pointer to "struct domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
602   */   */
603  struct domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
604                                                    const u8 profile)                                                        const u8 profile)
605  {  {
606          struct domain_info *domain = NULL;          struct ccs_domain_info *entry;
607          const struct path_info *saved_domainname;          struct ccs_domain_info *domain;
608          mutex_lock(&domain_list_lock);          const struct ccs_path_info *saved_domainname;
609          domain = ccs_find_domain(domainname);          bool found = false;
610          if (domain)  
611                  goto out;          if (!ccs_is_correct_domain(domainname))
612          if (!ccs_is_correct_domain(domainname, __func__))                  return NULL;
613                  goto out;          saved_domainname = ccs_get_name(domainname);
         saved_domainname = ccs_save_name(domainname);  
614          if (!saved_domainname)          if (!saved_domainname)
615                  goto out;                  return NULL;
616          /* Can I reuse memory of deleted domain? */          entry = kzalloc(sizeof(*entry), GFP_KERNEL);
617          list1_for_each_entry(domain, &domain_list, list) {          mutex_lock(&ccs_policy_lock);
618                  struct task_struct *p;          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
619                  struct acl_info *ptr;                  if (domain->is_deleted ||
620                  bool flag;                      ccs_pathcmp(saved_domainname, domain->domainname))
                 if (!domain->is_deleted ||  
                     domain->domainname != saved_domainname)  
                         continue;  
                 flag = false;  
                 /***** CRITICAL SECTION START *****/  
                 read_lock(&tasklist_lock);  
                 for_each_process(p) {  
                         if (p->domain_info != domain)  
                                 continue;  
                         flag = true;  
                         break;  
                 }  
                 read_unlock(&tasklist_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (flag)  
621                          continue;                          continue;
622  #ifdef DEBUG_DOMAIN_UNDELETE                  found = true;
623                  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;  
         }  
         /* No memory reusable. Create using new memory. */  
         domain = ccs_alloc_element(sizeof(*domain));  
         if (domain) {  
                 INIT_LIST1_HEAD(&domain->acl_info_list);  
                 domain->domainname = saved_domainname;  
                 domain->profile = profile;  
                 list1_add_tail_mb(&domain->list, &domain_list);  
624          }          }
625   out:          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
626          mutex_unlock(&domain_list_lock);                  INIT_LIST_HEAD(&entry->acl_info_list);
627          return domain;                  entry->domainname = saved_domainname;
628                    saved_domainname = NULL;
629                    entry->profile = profile;
630                    list_add_tail_rcu(&entry->list, &ccs_domain_list);
631                    domain = entry;
632                    entry = NULL;
633                    found = true;
634            }
635            mutex_unlock(&ccs_policy_lock);
636            ccs_put_name(saved_domainname);
637            kfree(entry);
638            return found ? domain : NULL;
639  }  }
640    
641  /**  /**
642   * get_argv0 - Get argv[0].   * ccs_get_argv0 - Get argv[0].
643   *   *
644   * @bprm: Pointer to "struct linux_binprm".   * @ee: Pointer to "struct ccs_execve_entry".
  * @tmp:  Buffer for temporal use.  
645   *   *
646   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
647   */   */
648  static bool get_argv0(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)  static bool ccs_get_argv0(struct ccs_execve_entry *ee)
649  {  {
650          char *arg_ptr = tmp->buffer;          struct linux_binprm *bprm = ee->bprm;
651            char *arg_ptr = ee->tmp;
652          int arg_len = 0;          int arg_len = 0;
653          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
654          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
655          bool done = false;          bool done = false;
656          if (!bprm->argc)          if (!bprm->argc)
657                  goto out;                  goto out;
658          while (1) {          while (1) {
659                  struct page *page;                  if (!ccs_dump_page(bprm, pos, &ee->dump))
                 const char *kaddr;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,  
                                    NULL) <= 0)  
660                          goto out;                          goto out;
661                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
 #else  
                 page = bprm->page[i];  
 #endif  
                 /* Map. */  
                 kaddr = kmap(page);  
                 if (!kaddr) { /* Mapping failed. */  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                         put_page(page);  
 #endif  
                         goto out;  
                 }  
662                  /* Read. */                  /* Read. */
663                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
664                            const char *kaddr = ee->dump.data;
665                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
666                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
667                                  if (c == '\\') {                                  if (c == '\\') {
# Line 943  static bool get_argv0(struct linux_binpr Line 684  static bool get_argv0(struct linux_binpr
684                                  break;                                  break;
685                          }                          }
686                  }                  }
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
687                  offset = 0;                  offset = 0;
688                  if (done)                  if (done)
689                          break;                          break;
# Line 959  static bool get_argv0(struct linux_binpr Line 694  static bool get_argv0(struct linux_binpr
694  }  }
695    
696  /**  /**
697   * find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
698   *   *
699   * @r:       Pointer to "struct ccs_request_info".   * @ee: Pointer to "struct ccs_execve_entry".
  * @handler: Pathname to verify. May be NULL.  
700   *   *
701   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
702     *
703     * Caller holds srcu_read_lock(&ccs_ss).
704   */   */
705  static int find_next_domain(struct ccs_request_info *r,  static int ccs_find_next_domain(struct ccs_execve_entry *ee)
                             const struct path_info *handler)  
706  {  {
707          /*          struct ccs_request_info *r = &ee->r;
708           * This function assumes that the size of buffer returned by          const struct ccs_path_info *handler = ee->handler;
709           * ccs_realpath() = CCS_MAX_PATHNAME_LEN.          struct ccs_domain_info *domain = NULL;
          */  
         struct domain_info *domain = NULL;  
710          const char *old_domain_name = r->domain->domainname->name;          const char *old_domain_name = r->domain->domainname->name;
711          struct linux_binprm *bprm = r->bprm;          struct linux_binprm *bprm = ee->bprm;
         struct ccs_page_buffer *tmp = r->obj->tmp;  
         const char *original_name = bprm->filename;  
712          const u8 mode = r->mode;          const u8 mode = r->mode;
713          const bool is_enforce = (mode == 3);          const bool is_enforce = (mode == 3);
714          const u32 tomoyo_flags = r->tomoyo_flags;          const u32 ccs_flags = current->ccs_flags;
715          char *new_domain_name = NULL;          char *new_domain_name = NULL;
716          char *real_program_name = NULL;          struct ccs_path_info rn; /* real name */
717          char *symlink_program_name = NULL;          struct ccs_path_info ln; /* last name */
         struct path_info rn; /* real name */  
         struct path_info sn; /* symlink name */  
         struct path_info ln; /* last name */  
718          int retval;          int retval;
   
         {  
                 /*  
                  * Built-in initializers. This is needed because policies are  
                  * not loaded until starting /sbin/init.  
                  */  
                 static bool first = true;  
                 if (first) {  
                         update_domain_initializer_entry(NULL, "/sbin/hotplug",  
                                                         false, false);  
                         update_domain_initializer_entry(NULL, "/sbin/modprobe",  
                                                         false, false);  
                         first = false;  
                 }  
         }  
   
719   retry:   retry:
720          current->tomoyo_flags = tomoyo_flags;          current->ccs_flags = ccs_flags;
721          r->tomoyo_flags = tomoyo_flags;          r->cond = NULL;
722          /* Get ccs_realpath of program. */          /* Get symlink's pathname of program. */
723          retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */          retval = ccs_symlink_path(bprm->filename, ee);
724          ccs_free(real_program_name);          if (retval < 0)
         real_program_name = ccs_realpath(original_name);  
         if (!real_program_name)  
                 goto out;  
         /* Get ccs_realpath of symbolic link. */  
         ccs_free(symlink_program_name);  
         symlink_program_name = ccs_realpath_nofollow(original_name);  
         if (!symlink_program_name)  
725                  goto out;                  goto out;
726    
727          rn.name = real_program_name;          rn.name = ee->program_path;
728          ccs_fill_path_info(&rn);          ccs_fill_path_info(&rn);
         sn.name = symlink_program_name;  
         ccs_fill_path_info(&sn);  
729          ln.name = ccs_get_last_name(r->domain);          ln.name = ccs_get_last_name(r->domain);
730          ccs_fill_path_info(&ln);          ccs_fill_path_info(&ln);
731    
# Line 1040  static int find_next_domain(struct ccs_r Line 743  static int find_next_domain(struct ccs_r
743                  goto calculate_domain;                  goto calculate_domain;
744          }          }
745    
746          /* Check 'alias' directive. */          /* Compare basename of program_path and argv[0] */
747          if (ccs_pathcmp(&rn, &sn)) {          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);
                 struct alias_entry *ptr;  
                 /* Is this program allowed to be called via symbolic links? */  
                 list1_for_each_entry(ptr, &alias_list, list) {  
                         if (ptr->is_deleted ||  
                             ccs_pathcmp(&rn, ptr->original_name) ||  
                             ccs_pathcmp(&sn, ptr->aliased_name))  
                                 continue;  
                         memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);  
                         strncpy(real_program_name, ptr->aliased_name->name,  
                                 CCS_MAX_PATHNAME_LEN - 1);  
                         ccs_fill_path_info(&rn);  
                         break;  
                 }  
         }  
   
         /* Compare basename of real_program_name and argv[0] */  
         r->mode = ccs_check_flags(r->domain, CCS_TOMOYO_MAC_FOR_ARGV0);  
748          if (bprm->argc > 0 && r->mode) {          if (bprm->argc > 0 && r->mode) {
749                  char *base_argv0 = tmp->buffer;                  char *base_argv0 = ee->tmp;
750                  const char *base_filename;                  const char *base_filename;
751                  retval = -ENOMEM;                  retval = -ENOMEM;
752                  if (!get_argv0(bprm, tmp))                  if (!ccs_get_argv0(ee))
753                          goto out;                          goto out;
754                  base_filename = strrchr(real_program_name, '/');                  base_filename = strrchr(ee->program_path, '/');
755                  if (!base_filename)                  if (!base_filename)
756                          base_filename = real_program_name;                          base_filename = ee->program_path;
757                  else                  else
758                          base_filename++;                          base_filename++;
759                  if (strcmp(base_argv0, base_filename)) {                  if (strcmp(base_argv0, base_filename)) {
760                          retval = ccs_check_argv0_perm(r, &rn, base_argv0);                          retval = ccs_check_argv0_perm(r, &rn, base_argv0);
761                          if (retval == 1) {                          if (retval == 1)
                                 r->retry++;  
762                                  goto retry;                                  goto retry;
                         }  
                         r->retry = 0;  
                         r->tomoyo_flags = current->tomoyo_flags;  
763                          if (retval < 0)                          if (retval < 0)
764                                  goto out;                                  goto out;
765                  }                  }
# Line 1085  static int find_next_domain(struct ccs_r Line 767  static int find_next_domain(struct ccs_r
767    
768          /* Check 'aggregator' directive. */          /* Check 'aggregator' directive. */
769          {          {
770                  struct aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
771                  /* Is this program allowed to be aggregated? */                  /* Is this program allowed to be aggregated? */
772                  list1_for_each_entry(ptr, &aggregator_list, list) {                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
773                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
774                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
775                                  continue;                                  continue;
776                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                          strncpy(ee->program_path, ptr->aggregated_name->name,
                         strncpy(real_program_name, ptr->aggregated_name->name,  
777                                  CCS_MAX_PATHNAME_LEN - 1);                                  CCS_MAX_PATHNAME_LEN - 1);
778                          ccs_fill_path_info(&rn);                          ccs_fill_path_info(&rn);
779                          break;                          break;
# Line 1102  static int find_next_domain(struct ccs_r Line 783  static int find_next_domain(struct ccs_r
783          /* Check execute permission. */          /* Check execute permission. */
784          r->mode = mode;          r->mode = mode;
785          retval = ccs_check_exec_perm(r, &rn);          retval = ccs_check_exec_perm(r, &rn);
786          if (retval == 1) {          if (retval == 1)
                 r->retry++;  
787                  goto retry;                  goto retry;
         }  
         r->retry = 0;  
         r->tomoyo_flags = current->tomoyo_flags;  
788          if (retval < 0)          if (retval < 0)
789                  goto out;                  goto out;
790    
791   calculate_domain:   calculate_domain:
792          new_domain_name = tmp->buffer;          new_domain_name = ee->tmp;
793          if (is_domain_initializer(r->domain->domainname, &rn, &ln)) {          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
794                  /* Transit to the child of KERNEL_DOMAIN domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
795                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
796                           ROOT_NAME " " "%s", real_program_name);                           ROOT_NAME " " "%s", ee->program_path);
797          } else if (r->domain == &KERNEL_DOMAIN && !sbin_init_started) {          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
798                  /*                  /*
799                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
800                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
801                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
802                   */                   */
803                  domain = r->domain;                  domain = r->domain;
804          } else if (is_domain_keeper(r->domain->domainname, &rn, &ln)) {          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
805                  /* Keep current domain. */                  /* Keep current domain. */
806                  domain = r->domain;                  domain = r->domain;
807          } else {          } else {
808                  /* Normal domain transition. */                  /* Normal domain transition. */
809                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
810                           "%s %s", old_domain_name, real_program_name);                           "%s %s", old_domain_name, ee->program_path);
811          }          }
812          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
813                  goto done;                  goto done;
# Line 1141  static int find_next_domain(struct ccs_r Line 818  static int find_next_domain(struct ccs_r
818                  int error = ccs_check_supervisor(r,                  int error = ccs_check_supervisor(r,
819                                                   "# wants to create domain\n"                                                   "# wants to create domain\n"
820                                                   "%s\n", new_domain_name);                                                   "%s\n", new_domain_name);
821                  if (error == 1) {                  if (error == 1)
                         r->retry++;  
822                          goto retry;                          goto retry;
                 }  
                 r->retry = 0;  
823                  if (error < 0)                  if (error < 0)
824                          goto done;                          goto done;
825          }          }
826          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
827          if (domain)          if (domain)
828                  audit_domain_creation_log(domain);                  ccs_audit_domain_creation_log(r->domain);
829   done:   done:
830          if (!domain) {          if (!domain) {
831                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
# Line 1160  static int find_next_domain(struct ccs_r Line 834  static int find_next_domain(struct ccs_r
834                          retval = -EPERM;                          retval = -EPERM;
835                  else {                  else {
836                          retval = 0;                          retval = 0;
837                          ccs_set_domain_flag(r->domain, false,                          r->domain->domain_transition_failed = true;
                                             DOMAIN_FLAGS_TRANSITION_FAILED);  
838                  }                  }
839          } else {          } else {
840                  retval = 0;                  retval = 0;
841          }          }
842   out:   out:
         ccs_free(real_program_name);  
         ccs_free(symlink_program_name);  
843          if (domain)          if (domain)
844                  r->domain = domain;                  r->domain = domain;
845          return retval;          return retval;
846  }  }
847    
848  /**  /**
849   * check_environ - Check permission for environment variable names.   * ccs_check_environ - Check permission for environment variable names.
850   *   *
851   * @r: Pointer to "struct ccs_request_info".   * @ee: Pointer to "struct ccs_execve_entry".
852   *   *
853   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
854   */   */
855  static int check_environ(struct ccs_request_info *r)  static int ccs_check_environ(struct ccs_execve_entry *ee)
856  {  {
857          struct linux_binprm *bprm = r->bprm;          struct ccs_request_info *r = &ee->r;
858          struct ccs_page_buffer *tmp = r->obj->tmp;          struct linux_binprm *bprm = ee->bprm;
859          char *arg_ptr = tmp->buffer;          char *arg_ptr = ee->tmp;
860          int arg_len = 0;          int arg_len = 0;
861          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
862          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
863          int argv_count = bprm->argc;          int argv_count = bprm->argc;
864          int envp_count = bprm->envc;          int envp_count = bprm->envc;
# Line 1197  static int check_environ(struct ccs_requ Line 867  static int check_environ(struct ccs_requ
867          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
868                  return 0;                  return 0;
869          while (error == -ENOMEM) {          while (error == -ENOMEM) {
870                  struct page *page;                  if (!ccs_dump_page(bprm, pos, &ee->dump))
                 const char *kaddr;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,  
                                    NULL) <= 0)  
871                          goto out;                          goto out;
872                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
 #else  
                 page = bprm->page[i];  
 #endif  
                 /* Map. */  
                 kaddr = kmap(page);  
                 if (!kaddr) { /* Mapping failed. */  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                         put_page(page);  
 #endif  
                         goto out;  
                 }  
873                  /* Read. */                  /* Read. */
874                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
875                            const char *kaddr = ee->dump.data;
876                          if (!kaddr[offset++])                          if (!kaddr[offset++])
877                                  argv_count--;                                  argv_count--;
878                  }                  }
879                  if (argv_count)                  if (argv_count) {
880                          goto unmap_page;                          offset = 0;
881                            continue;
882                    }
883                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
884                            const char *kaddr = ee->dump.data;
885                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
886                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
887                                  if (c == '=') {                                  if (c == '=') {
# Line 1254  static int check_environ(struct ccs_requ Line 913  static int check_environ(struct ccs_requ
913                          }                          }
914                          arg_len = 0;                          arg_len = 0;
915                  }                  }
  unmap_page:  
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
916                  offset = 0;                  offset = 0;
917          }          }
918   out:   out:
# Line 1270  static int check_environ(struct ccs_requ Line 922  static int check_environ(struct ccs_requ
922  }  }
923    
924  /**  /**
925   * unescape - Unescape escaped string.   * ccs_unescape - Unescape escaped string.
926   *   *
927   * @dest: String to unescape.   * @dest: String to unescape.
928   *   *
929   * Returns nothing.   * Returns nothing.
930   */   */
931  static void unescape(unsigned char *dest)  static void ccs_unescape(unsigned char *dest)
932  {  {
933          unsigned char *src = dest;          unsigned char *src = dest;
934          unsigned char c;          unsigned char c;
935          unsigned char d;          unsigned char d;
936          unsigned char e;          unsigned char e;
937          while ((c = *src++) != '\0') {          while (1) {
938                    c = *src++;
939                    if (!c)
940                            break;
941                  if (c != '\\') {                  if (c != '\\') {
942                          *dest++ = c;                          *dest++ = c;
943                          continue;                          continue;
# Line 1306  static void unescape(unsigned char *dest Line 961  static void unescape(unsigned char *dest
961  }  }
962    
963  /**  /**
964   * root_depth - Get number of directories to strip.   * ccs_root_depth - Get number of directories to strip.
965   *   *
966   * @dentry: Pointer to "struct dentry".   * @dentry: Pointer to "struct dentry".
967   * @vfsmnt: Pointer to "struct vfsmount".   * @vfsmnt: Pointer to "struct vfsmount".
968   *   *
969   * Returns number of directories to strip.   * Returns number of directories to strip.
970   */   */
971  static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
972  {  {
973          int depth = 0;          int depth = 0;
974          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
# Line 1336  static inline int root_depth(struct dent Line 991  static inline int root_depth(struct dent
991  }  }
992    
993  /**  /**
994   * get_root_depth - return the depth of root directory.   * ccs_get_root_depth - return the depth of root directory.
995   *   *
996   * Returns number of directories to strip.   * Returns number of directories to strip.
997   */   */
998  static int get_root_depth(void)  static int ccs_get_root_depth(void)
999  {  {
1000          int depth;          int depth;
1001          struct dentry *dentry;          struct dentry *dentry;
# Line 1361  static int get_root_depth(void) Line 1016  static int get_root_depth(void)
1016  #endif  #endif
1017          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
1018          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
1019          depth = root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
1020  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1021          path_put(&root);          path_put(&root);
1022  #else  #else
# Line 1371  static int get_root_depth(void) Line 1026  static int get_root_depth(void)
1026          return depth;          return depth;
1027  }  }
1028    
1029    static LIST_HEAD(ccs_execve_list);
1030    static DEFINE_SPINLOCK(ccs_execve_list_lock);
1031    
1032  /**  /**
1033   * try_alt_exec - Try to start execute handler.   * ccs_allocate_execve_entry - Allocate memory for execve().
1034   *   *
1035   * @r:           Pointer to "struct ccs_request_info".   * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1036   * @handler:     Pointer to the name of execute handler.   */
1037   * @eh_path:     Pointer to pointer to the name of execute handler.  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1038    {
1039            struct ccs_execve_entry *ee = kzalloc(sizeof(*ee), GFP_KERNEL);
1040            if (!ee)
1041                    return NULL;
1042            ee->program_path = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);
1043            ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);
1044            if (!ee->program_path || !ee->tmp) {
1045                    kfree(ee->program_path);
1046                    kfree(ee->tmp);
1047                    kfree(ee);
1048                    return NULL;
1049            }
1050            ee->srcu_idx = srcu_read_lock(&ccs_ss);
1051            /* ee->dump->data is allocated by ccs_dump_page(). */
1052            ee->task = current;
1053            /***** CRITICAL SECTION START *****/
1054            spin_lock(&ccs_execve_list_lock);
1055            list_add(&ee->list, &ccs_execve_list);
1056            spin_unlock(&ccs_execve_list_lock);
1057            /***** CRITICAL SECTION END *****/
1058            return ee;
1059    }
1060    
1061    /**
1062     * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1063     *
1064     * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1065     */
1066    static struct ccs_execve_entry *ccs_find_execve_entry(void)
1067    {
1068            struct task_struct *task = current;
1069            struct ccs_execve_entry *ee = NULL;
1070            struct ccs_execve_entry *p;
1071            /***** CRITICAL SECTION START *****/
1072            spin_lock(&ccs_execve_list_lock);
1073            list_for_each_entry(p, &ccs_execve_list, list) {
1074                    if (p->task != task)
1075                            continue;
1076                    ee = p;
1077                    break;
1078            }
1079            spin_unlock(&ccs_execve_list_lock);
1080            /***** CRITICAL SECTION END *****/
1081            return ee;
1082    }
1083    
1084    /**
1085     * ccs_free_execve_entry - Free memory for execve().
1086     *
1087     * @ee: Pointer to "struct ccs_execve_entry".
1088     */
1089    static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1090    {
1091            if (!ee)
1092                    return;
1093            /***** CRITICAL SECTION START *****/
1094            spin_lock(&ccs_execve_list_lock);
1095            list_del(&ee->list);
1096            spin_unlock(&ccs_execve_list_lock);
1097            /***** CRITICAL SECTION END *****/
1098            kfree(ee->program_path);
1099            kfree(ee->tmp);
1100            kfree(ee->dump.data);
1101            srcu_read_unlock(&ccs_ss, ee->srcu_idx);
1102            kfree(ee);
1103    }
1104    
1105    /**
1106     * ccs_try_alt_exec - Try to start execute handler.
1107     *
1108     * @ee: Pointer to "struct ccs_execve_entry".
1109   *   *
1110   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1111   */   */
1112  static int try_alt_exec(struct ccs_request_info *r,  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
                         const struct path_info *handler, char **eh_path)  
1113  {  {
1114          /*          /*
1115           * Contents of modified bprm.           * Contents of modified bprm.
# Line 1397  static int try_alt_exec(struct ccs_reque Line 1125  static int try_alt_exec(struct ccs_reque
1125           * modified bprm->argv[0]           * modified bprm->argv[0]
1126           *    = the program's name specified by execute_handler           *    = the program's name specified by execute_handler
1127           * modified bprm->argv[1]           * modified bprm->argv[1]
1128           *    = current->domain_info->domainname->name           *    = ccs_current_domain()->domainname->name
1129           * modified bprm->argv[2]           * modified bprm->argv[2]
1130           *    = the current process's name           *    = the current process's name
1131           * modified bprm->argv[3]           * modified bprm->argv[3]
# Line 1419  static int try_alt_exec(struct ccs_reque Line 1147  static int try_alt_exec(struct ccs_reque
1147           * modified bprm->argv[bprm->envc + bprm->argc + 6]           * modified bprm->argv[bprm->envc + bprm->argc + 6]
1148           *     = original bprm->envp[bprm->envc - 1]           *     = original bprm->envp[bprm->envc - 1]
1149           */           */
1150          struct linux_binprm *bprm = r->bprm;          struct linux_binprm *bprm = ee->bprm;
1151          struct file *filp;          struct file *filp;
1152          int retval;          int retval;
1153          const int original_argc = bprm->argc;          const int original_argc = bprm->argc;
1154          const int original_envc = bprm->envc;          const int original_envc = bprm->envc;
1155          struct task_struct *task = current;          struct task_struct *task = current;
         char *buffer = r->obj->tmp->buffer;  
         /* Allocate memory for execute handler's pathname. */  
         char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));  
         *eh_path = execute_handler;  
         if (!execute_handler)  
                 return -ENOMEM;  
         strncpy(execute_handler, handler->name,  
                 sizeof(struct ccs_page_buffer) - 1);  
         unescape(execute_handler);  
1156    
1157          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
1158          allow_write_access(bprm->file);          allow_write_access(bprm->file);
1159          fput(bprm->file);          fput(bprm->file);
1160          bprm->file = NULL;          bprm->file = NULL;
1161    
1162          { /* Adjust root directory for open_exec(). */          /* Invalidate page dump cache. */
1163                  int depth = get_root_depth();          ee->dump.page = NULL;
                 char *cp = execute_handler;  
                 if (!*cp || *cp != '/')  
                         return -ENOENT;  
                 while (depth) {  
                         cp = strchr(cp + 1, '/');  
                         if (!cp)  
                                 return -ENOENT;  
                         depth--;  
                 }  
                 memmove(execute_handler, cp, strlen(cp) + 1);  
         }  
1164    
1165          /* Move envp[] to argv[] */          /* Move envp[] to argv[] */
1166          bprm->argc += bprm->envc;          bprm->argc += bprm->envc;
# Line 1460  static int try_alt_exec(struct ccs_reque Line 1168  static int try_alt_exec(struct ccs_reque
1168    
1169          /* Set argv[6] */          /* Set argv[6] */
1170          {          {
1171                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
1172                           original_envc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1173                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1174                  if (retval < 0)                  if (retval < 0)
1175                          goto out;                          goto out;
1176                  bprm->argc++;                  bprm->argc++;
# Line 1470  static int try_alt_exec(struct ccs_reque Line 1178  static int try_alt_exec(struct ccs_reque
1178    
1179          /* Set argv[5] */          /* Set argv[5] */
1180          {          {
1181                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
1182                           original_argc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1183                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1184                  if (retval < 0)                  if (retval < 0)
1185                          goto out;                          goto out;
1186                  bprm->argc++;                  bprm->argc++;
# Line 1488  static int try_alt_exec(struct ccs_reque Line 1196  static int try_alt_exec(struct ccs_reque
1196    
1197          /* Set argv[3] */          /* Set argv[3] */
1198          {          {
1199                  const u32 tomoyo_flags = task->tomoyo_flags;                  char *cp = ee->tmp;
1200                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                  const u32 ccs_flags = task->ccs_flags;
1201                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1202                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1203                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1204                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
1205                           task->pid, task->uid, task->gid, task->euid,                           (pid_t) sys_getpid(), current_uid(), current_gid(),
1206                           task->egid, task->suid, task->sgid, task->fsuid,                           current_euid(), current_egid(), current_suid(),
1207                           task->fsgid, (u8) (tomoyo_flags >> 24),                           current_sgid(), current_fsuid(), current_fsgid(),
1208                           (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1209                  retval = copy_strings_kernel(1, &buffer, bprm);                           (u8) (ccs_flags >> 8));
1210                    retval = copy_strings_kernel(1, &cp, bprm);
1211                  if (retval < 0)                  if (retval < 0)
1212                          goto out;                          goto out;
1213                  bprm->argc++;                  bprm->argc++;
# Line 1508  static int try_alt_exec(struct ccs_reque Line 1218  static int try_alt_exec(struct ccs_reque
1218                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
1219                  if (exe) {                  if (exe) {
1220                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1221                          ccs_free(exe);                          kfree(exe);
1222                  } else {                  } else {
1223                          snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                          exe = ee->tmp;
1224                                   "<unknown>");                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
1225                          retval = copy_strings_kernel(1, &buffer, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1226                  }                  }
1227                  if (retval < 0)                  if (retval < 0)
1228                          goto out;                          goto out;
# Line 1521  static int try_alt_exec(struct ccs_reque Line 1231  static int try_alt_exec(struct ccs_reque
1231    
1232          /* Set argv[1] */          /* Set argv[1] */
1233          {          {
1234                  strncpy(buffer, task->domain_info->domainname->name,                  char *cp = ee->tmp;
1235                          sizeof(struct ccs_page_buffer) - 1);                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,
1236                  retval = copy_strings_kernel(1, &buffer, bprm);                          CCS_EXEC_TMPSIZE - 1);
1237                    retval = copy_strings_kernel(1, &cp, bprm);
1238                  if (retval < 0)                  if (retval < 0)
1239                          goto out;                          goto out;
1240                  bprm->argc++;                  bprm->argc++;
# Line 1531  static int try_alt_exec(struct ccs_reque Line 1242  static int try_alt_exec(struct ccs_reque
1242    
1243          /* Set argv[0] */          /* Set argv[0] */
1244          {          {
1245                  retval = copy_strings_kernel(1, &execute_handler, bprm);                  int depth = ccs_get_root_depth();
1246                    char *cp = ee->program_path;
1247                    strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);
1248                    ccs_unescape(cp);
1249                    retval = -ENOENT;
1250                    if (!*cp || *cp != '/')
1251                            goto out;
1252                    /* Adjust root directory for open_exec(). */
1253                    while (depth) {
1254                            cp = strchr(cp + 1, '/');
1255                            if (!cp)
1256                                    goto out;
1257                            depth--;
1258                    }
1259                    memmove(ee->program_path, cp, strlen(cp) + 1);
1260                    cp = ee->program_path;
1261                    retval = copy_strings_kernel(1, &cp, bprm);
1262                  if (retval < 0)                  if (retval < 0)
1263                          goto out;                          goto out;
1264                  bprm->argc++;                  bprm->argc++;
# Line 1543  static int try_alt_exec(struct ccs_reque Line 1270  static int try_alt_exec(struct ccs_reque
1270  #endif  #endif
1271    
1272          /* OK, now restart the process with execute handler program's dentry. */          /* OK, now restart the process with execute handler program's dentry. */
1273          filp = open_exec(execute_handler);          filp = open_exec(ee->program_path);
1274          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1275                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1276                  goto out;                  goto out;
1277          }          }
1278          bprm->file = filp;          bprm->file = filp;
1279          bprm->filename = execute_handler;          bprm->filename = ee->program_path;
1280  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1281          bprm->interp = execute_handler;          bprm->interp = bprm->filename;
1282  #endif  #endif
1283          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1284          if (retval < 0)          if (retval < 0)
1285                  goto out;                  goto out;
1286          task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          {
1287          retval = find_next_domain(r, handler);                  /*
1288          task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;                   * Backup ee->program_path because ccs_find_next_domain() will
1289                     * overwrite ee->program_path and ee->tmp.
1290                     */
1291                    const int len = strlen(ee->program_path) + 1;
1292                    char *cp = kzalloc(len, GFP_KERNEL);
1293                    if (!cp) {
1294                            retval = -ENOMEM;
1295                            goto out;
1296                    }
1297                    memmove(cp, ee->program_path, len);
1298                    bprm->filename = cp;
1299    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1300                    bprm->interp = bprm->filename;
1301    #endif
1302                    task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1303                    retval = ccs_find_next_domain(ee);
1304                    task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1305                    /* Restore ee->program_path for search_binary_handler(). */
1306                    memmove(ee->program_path, cp, len);
1307                    bprm->filename = ee->program_path;
1308    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1309                    bprm->interp = bprm->filename;
1310    #endif
1311                    kfree(cp);
1312            }
1313   out:   out:
1314          return retval;          return retval;
1315  }  }
1316    
1317  /**  /**
1318   * find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1319   *   *
1320     * @ee:   Pointer to "struct ccs_execve_entry".
1321   * @type: Type of execute handler.   * @type: Type of execute handler.
1322   *   *
1323   * Returns pointer to "struct path_info" if found, NULL otherwise.   * Returns true if found, false otherwise.
1324     *
1325     * Caller holds srcu_read_lock(&ccs_ss).
1326   */   */
1327  static const struct path_info *find_execute_handler(const u8 type)  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1328                                         const u8 type)
1329  {  {
1330          struct task_struct *task = current;          struct task_struct *task = current;
1331          const struct domain_info *domain = task->domain_info;          const struct ccs_domain_info *domain = ccs_current_domain();
1332          struct acl_info *ptr;          struct ccs_acl_info *ptr;
1333            bool found = false;
1334          /*          /*
1335           * Don't use execute handler if the current process is           * Don't use execute handler if the current process is
1336           * marked as execute handler to avoid infinite execute handler loop.           * marked as execute handler to avoid infinite execute handler loop.
1337           */           */
1338          if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1339                  return NULL;                  return false;
1340          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry(ptr, &domain->acl_info_list, list) {
1341                  struct execute_handler_record *acl;                  struct ccs_execute_handler_record *acl;
1342                  if (ptr->type != type)                  if (ptr->type != type)
1343                          continue;                          continue;
1344                  acl = container_of(ptr, struct execute_handler_record, head);                  acl = container_of(ptr, struct ccs_execute_handler_record,
1345                  return acl->handler;                                     head);
1346                    ee->handler = acl->handler;
1347                    found = true;
1348                    break;
1349          }          }
1350          return NULL;          return found;
1351  }  }
1352    
 /* List of next_domain which is used for checking interpreter's permissions. */  
 struct execve_entry {  
         struct list_head list;  
         struct task_struct *task;  
         struct domain_info *next_domain;  
 };  
   
 static LIST_HEAD(execve_list);  
 static DEFINE_SPINLOCK(execve_list_lock);  
   
1353  /**  /**
1354   * ccs_register_next_domain - Remember next_domain.   * ccs_dump_page - Dump a page to buffer.
1355   *   *
1356   * @next_domain: Pointer to "struct domain_info".   * @bprm: Pointer to "struct linux_binprm".
1357     * @pos:  Location to dump.
1358     * @dump: Poiner to "struct ccs_page_dump".
1359   *   *
1360   * Returns 0 on success, -ENOMEM otherwise.   * Returns true on success, false otherwise.
1361   */   */
1362  static int ccs_register_next_domain(struct domain_info *next_domain)  bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1363                       struct ccs_page_dump *dump)
1364  {  {
1365          struct execve_entry *ee = kmalloc(sizeof(*ee), GFP_KERNEL);          struct page *page;
1366          if (!ee)          /* dump->data is released by ccs_free_execve_entry(). */
1367                  return -ENOMEM;          if (!dump->data) {
1368          ee->task = current;                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);
1369          ee->next_domain = next_domain;                  if (!dump->data)
1370          /***** CRITICAL SECTION START *****/                          return false;
1371          spin_lock(&execve_list_lock);          }
1372          list_add(&ee->list, &execve_list);          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1373          spin_unlock(&execve_list_lock);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1374          /***** CRITICAL SECTION END *****/          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1375          return 0;                  return false;
1376    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1377            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1378                    return false;
1379    #else
1380            page = bprm->page[pos / PAGE_SIZE];
1381    #endif
1382            if (page != dump->page) {
1383                    const unsigned int offset = pos % PAGE_SIZE;
1384                    /*
1385                     * Maybe kmap()/kunmap() should be used here.
1386                     * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1387                     * So do I.
1388                     */
1389                    char *kaddr = kmap_atomic(page, KM_USER0);
1390                    dump->page = page;
1391                    memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1392                    kunmap_atomic(kaddr, KM_USER0);
1393            }
1394            /* Same with put_arg_page(page) in fs/exec.c */
1395    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1396            put_page(page);
1397    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1398            put_page(page);
1399    #endif
1400            return true;
1401  }  }
1402    
1403  /**  /**
1404   * ccs_fetch_next_domain - Fetch next_domain from the list.   * ccs_fetch_next_domain - Fetch next_domain from the list.
1405   *   *
1406   * Returns pointer to "struct domain_info" which will be used if execve()   * Returns pointer to "struct ccs_domain_info" which will be used if execve()
1407   * succeeds. This function does not return NULL.   * succeeds. This function does not return NULL.
1408   */   */
1409  struct domain_info *ccs_fetch_next_domain(void)  struct ccs_domain_info *ccs_fetch_next_domain(void)
1410  {  {
1411          struct task_struct *task = current;          struct ccs_execve_entry *ee = ccs_find_execve_entry();
1412          struct domain_info *next_domain = task->domain_info;          struct ccs_domain_info *next_domain = NULL;
1413          struct execve_entry *p;          if (ee)
1414          /***** CRITICAL SECTION START *****/                  next_domain = ee->r.domain;
1415          spin_lock(&execve_list_lock);          if (!next_domain)
1416          list_for_each_entry(p, &execve_list, list) {                  next_domain = ccs_current_domain();
                 if (p->task != task)  
                         continue;  
                 next_domain = p->next_domain;  
                 break;  
         }  
         spin_unlock(&execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
1417          return next_domain;          return next_domain;
1418  }  }
1419    
1420  /**  /**
1421   * ccs_unregister_next_domain - Forget next_domain.   * ccs_start_execve - Prepare for execve() operation.
  */  
 static void ccs_unregister_next_domain(void)  
 {  
         struct task_struct *task = current;  
         struct execve_entry *p;  
         struct execve_entry *ee = NULL;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&execve_list_lock);  
         list_for_each_entry(p, &execve_list, list) {  
                 if (p->task != task)  
                         continue;  
                 list_del(&p->list);  
                 ee = p;  
                 break;  
         }  
         spin_unlock(&execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         kfree(ee);  
 }  
   
 /**  
  * search_binary_handler_with_transition - Perform domain transition.  
1422   *   *
1423   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
  * @regs: Pointer to "struct pt_regs".  
1424   *   *
1425   * Returns result of search_binary_handler() on success,   * Returns 0 on success, negative value otherwise.
  * negative value otherwise.  
1426   */   */
1427  int search_binary_handler_with_transition(struct linux_binprm *bprm,  int ccs_start_execve(struct linux_binprm *bprm)
                                           struct pt_regs *regs)  
1428  {  {
1429          int retval;          int retval;
1430          struct task_struct *task = current;          struct task_struct *task = current;
1431          const struct path_info *handler;          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1432          struct ccs_request_info r;          if (!ccs_policy_loaded)
         struct obj_info obj;  
         /*  
          * "eh_path" holds path to execute handler program.  
          * Thus, keep valid until search_binary_handler() finishes.  
          */  
         char *eh_path = NULL;  
         struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));  
         memset(&obj, 0, sizeof(obj));  
         if (!sbin_init_started)  
1433                  ccs_load_policy(bprm->filename);                  ccs_load_policy(bprm->filename);
1434          if (!tmp)          if (!ee)
1435                  return -ENOMEM;                  return -ENOMEM;
1436            ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);
1437          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);          ee->r.ee = ee;
1438          r.bprm = bprm;          ee->bprm = bprm;
1439          r.obj = &obj;          ee->r.obj = &ee->obj;
1440          obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1_dentry = bprm->file->f_dentry;
1441          obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;
         obj.tmp = tmp;  
   
1442          /* Clear manager flag. */          /* Clear manager flag. */
1443          task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1444          handler = find_execute_handler(TYPE_EXECUTE_HANDLER);          if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {
1445          if (handler) {                  retval = ccs_try_alt_exec(ee);
                 retval = try_alt_exec(&r, handler, &eh_path);  
1446                  if (!retval)                  if (!retval)
1447                          audit_execute_handler_log(true, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, true);
1448                  goto ok;                  goto ok;
1449          }          }
1450          retval = find_next_domain(&r, NULL);          retval = ccs_find_next_domain(ee);
1451          if (retval != -EPERM)          if (retval != -EPERM)
1452                  goto ok;                  goto ok;
1453          handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {
1454          if (handler) {                  retval = ccs_try_alt_exec(ee);
                 retval = try_alt_exec(&r, handler, &eh_path);  
1455                  if (!retval)                  if (!retval)
1456                          audit_execute_handler_log(false, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, false);
1457          }          }
1458   ok:   ok:
1459          if (retval < 0)          if (retval < 0)
1460                  goto out;                  goto out;
1461          r.mode = ccs_check_flags(r.domain, CCS_TOMOYO_MAC_FOR_ENV);          ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);
1462          retval = check_environ(&r);          retval = ccs_check_environ(ee);
         if (retval < 0)  
                 goto out;  
         retval = ccs_register_next_domain(r.domain);  
1463          if (retval < 0)          if (retval < 0)
1464                  goto out;                  goto out;
1465          task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1466          retval = search_binary_handler(bprm, regs);          retval = 0;
         task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;  
         if (retval < 0)  
                 goto out;  
         /* Proceed to next domain if execution suceeded. */  
         task->domain_info = r.domain;  
         mb(); /* Make domain transition visible to other CPUs. */  
         /* Mark the current process as execute handler. */  
         if (handler)  
                 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;  
         /* Mark the current process as normal process. */  
         else  
                 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;  
1467   out:   out:
1468          ccs_unregister_next_domain();          if (retval)
1469          ccs_free(eh_path);                  ccs_finish_execve(retval);
         ccs_free(tmp);  
1470          return retval;          return retval;
1471  }  }
1472    
 #else  
   
1473  /**  /**
1474   * search_binary_handler_with_transition - Wrapper for search_binary_handler().   * ccs_finish_execve - Clean up execve() operation.
1475   *   *
1476   * @bprm: Pointer to "struct linux_binprm".   * @retval: Return code of an execve() operation.
  * @regs: Pointer to "struct pt_regs".  
1477   *   *
1478   * Returns the result of search_binary_handler().   * Caller holds srcu_read_lock(&ccs_ss).
1479   */   */
1480  int search_binary_handler_with_transition(struct linux_binprm *bprm,  void ccs_finish_execve(int retval)
                                           struct pt_regs *regs)  
1481  {  {
1482  #ifdef CONFIG_SAKURA          struct task_struct *task = current;
1483          /* Clear manager flag. */          struct ccs_execve_entry *ee = ccs_find_execve_entry();
1484          current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1485          ccs_load_policy(bprm->filename);          if (!ee)
1486  #endif                  return;
1487          return search_binary_handler(bprm, regs);          if (retval < 0)
1488                    goto out;
1489            /* Proceed to next domain if execution suceeded. */
1490            task->ccs_domain_info = ee->r.domain;
1491            /* Mark the current process as execute handler. */
1492            if (ee->handler)
1493                    task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1494            /* Mark the current process as normal process. */
1495            else
1496                    task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1497     out:
1498            ccs_free_execve_entry(ee);
1499  }  }
   
 #endif  

Legend:
Removed from v.1719  
changed lines
  Added in v.2779

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