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

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 2691 by kumaneko, Wed Jun 24 05:16:15 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.6.8   2009/05/28
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.
# Line 16  Line 16 
16  #include <linux/tomoyo.h>  #include <linux/tomoyo.h>
17  #include <linux/realpath.h>  #include <linux/realpath.h>
18  #include <linux/highmem.h>  #include <linux/highmem.h>
 #include <linux/binfmts.h>  
19  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
20  #include <linux/namei.h>  #include <linux/namei.h>
21  #include <linux/mount.h>  #include <linux/mount.h>
22  #endif  #endif
23    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
24    #include <linux/fs_struct.h>
25    #endif
26    
27  /* For compatibility with older kernels. */  /* For compatibility with older kernels. */
28  #ifndef for_each_process  #ifndef for_each_process
# Line 30  Line 32 
32  /* Variables definitions.*/  /* Variables definitions.*/
33    
34  /* The initial domain. */  /* The initial domain. */
35  struct domain_info KERNEL_DOMAIN;  struct ccs_domain_info ccs_kernel_domain;
36    
37  /* The list for "struct domain_info". */  /* The list for "struct ccs_domain_info". */
38  LIST1_HEAD(domain_list);  LIST_HEAD(ccs_domain_list);
39    
40  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
41    
 /* 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 *****/  
 }  
   
42  /**  /**
43   * ccs_get_last_name - Get last component of a domainname.   * ccs_get_last_name - Get last component of a domainname.
44   *   *
45   * @domain: Pointer to "struct domain_info".   * @domain: Pointer to "struct ccs_domain_info".
46   *   *
47   * Returns the last component of the domainname.   * Returns the last component of the domainname.
48   */   */
49  const char *ccs_get_last_name(const struct domain_info *domain)  const char *ccs_get_last_name(const struct ccs_domain_info *domain)
50  {  {
51          const char *cp0 = domain->domainname->name;          const char *cp0 = domain->domainname->name;
52          const char *cp1 = strrchr(cp0, ' ');          const char *cp1 = strrchr(cp0, ' ');
# Line 119  const char *ccs_get_last_name(const stru Line 58  const char *ccs_get_last_name(const stru
58  /**  /**
59   * ccs_add_domain_acl - Add the given ACL to the given domain.   * ccs_add_domain_acl - Add the given ACL to the given domain.
60   *   *
61   * @domain: Pointer to "struct domain_info". May be NULL.   * @domain: Pointer to "struct ccs_domain_info". May be NULL.
62   * @acl:    Pointer to "struct acl_info".   * @acl:    Pointer to "struct ccs_acl_info".
63   *   *
64   * Returns 0.   * Returns 0.
65   */   */
66  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)
67  {  {
68          if (domain) {          if (domain) {
69                  /*                  if (acl->cond)
70                   * We need to serialize because this function is called by                          atomic_inc(&acl->cond->users);
71                   * 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 *****/  
72          } else {          } else {
73                  acl->type &= ~ACL_DELETED;                  acl->type &= ~ACL_DELETED;
74          }          }
# Line 147  int ccs_add_domain_acl(struct domain_inf Line 79  int ccs_add_domain_acl(struct domain_inf
79  /**  /**
80   * ccs_del_domain_acl - Delete the given ACL from the domain.   * ccs_del_domain_acl - Delete the given ACL from the domain.
81   *   *
82   * @acl: Pointer to "struct acl_info". May be NULL.   * @acl: Pointer to "struct ccs_acl_info". May be NULL.
83   *   *
84   * Returns 0.   * Returns 0.
85   */   */
86  int ccs_del_domain_acl(struct acl_info *acl)  int ccs_del_domain_acl(struct ccs_acl_info *acl)
87  {  {
88          if (acl)          if (acl)
89                  acl->type |= ACL_DELETED;                  acl->type |= ACL_DELETED;
# Line 160  int ccs_del_domain_acl(struct acl_info * Line 92  int ccs_del_domain_acl(struct acl_info *
92  }  }
93    
94  /**  /**
95   * audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
96   *   *
97     * @ee:         Pointer to "struct ccs_execve_entry".
98   * @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".  
99   *   *
100   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
101   */   */
102  static int audit_execute_handler_log(const bool is_default,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
103                                       const char *handler,                                           const bool is_default)
                                      struct linux_binprm *bprm)  
104  {  {
105          struct ccs_request_info r;          struct ccs_request_info *r = &ee->r;
106          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);          const char *handler = ee->handler->name;
107          r.bprm = bprm;          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);
108          return ccs_write_audit_log(true, &r, "%s %s\n",          return ccs_write_audit_log(true, r, "%s %s\n",
109                                     is_default ? KEYWORD_EXECUTE_HANDLER :                                     is_default ? KEYWORD_EXECUTE_HANDLER :
110                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);
111  }  }
112    
113  /**  /**
114   * audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
115   *   *
116   * @domain:  Pointer to "struct domain_info".   * @domain:  Pointer to "struct ccs_domain_info".
117   *   *
118   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
119   */   */
120  static int audit_domain_creation_log(struct domain_info *domain)  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
121  {  {
122            int error;
123          struct ccs_request_info r;          struct ccs_request_info r;
124          ccs_init_request_info(&r, domain, CCS_TOMOYO_MAC_FOR_FILE);          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);
125          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);
126            ccs_exit_request_info(&r);
127            return error;
128  }  }
129    
130  /* The list for "struct domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
131  static LIST1_HEAD(domain_initializer_list);  LIST_HEAD(ccs_domain_initializer_list);
132    
133  /**  /**
134   * update_domain_initializer_entry - Update "struct domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
135   *   *
136   * @domainname: The name of domain. May be NULL.   * @domainname: The name of domain. May be NULL.
137   * @program:    The name of program.   * @program:    The name of program.
# Line 207  static LIST1_HEAD(domain_initializer_lis Line 140  static LIST1_HEAD(domain_initializer_lis
140   *   *
141   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
142   */   */
143  static int update_domain_initializer_entry(const char *domainname,  static int ccs_update_domain_initializer_entry(const char *domainname,
144                                             const char *program,                                                 const char *program,
145                                             const bool is_not,                                                 const bool is_not,
146                                             const bool is_delete)                                                 const bool is_delete)
147  {  {
148          struct domain_initializer_entry *new_entry;          struct ccs_domain_initializer_entry *entry = NULL;
149          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
150          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_program;
151          const struct path_info *saved_program;          const struct ccs_path_info *saved_domainname = NULL;
152          const struct path_info *saved_domainname = NULL;          int error = is_delete ? -ENOENT : -ENOMEM;
         int error = -ENOMEM;  
153          bool is_last_name = false;          bool is_last_name = false;
154          if (!ccs_is_correct_path(program, 1, -1, -1, __func__))          if (!ccs_is_correct_path(program, 1, -1, -1))
155                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
156          if (domainname) {          if (domainname) {
157                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
158                      ccs_is_correct_path(domainname, 1, -1, -1, __func__))                      ccs_is_correct_path(domainname, 1, -1, -1))
159                          is_last_name = true;                          is_last_name = true;
160                  else if (!ccs_is_correct_domain(domainname, __func__))                  else if (!ccs_is_correct_domain(domainname))
161                          return -EINVAL;                          return -EINVAL;
162                  saved_domainname = ccs_save_name(domainname);                  saved_domainname = ccs_get_name(domainname);
163                  if (!saved_domainname)                  if (!saved_domainname)
164                          return -ENOMEM;                          return -ENOMEM;
165          }          }
166          saved_program = ccs_save_name(program);          saved_program = ccs_get_name(program);
167          if (!saved_program)          if (!saved_program) {
168                    ccs_put_name(saved_domainname);
169                  return -ENOMEM;                  return -ENOMEM;
170          mutex_lock(&lock);          }
171          list1_for_each_entry(ptr, &domain_initializer_list, list) {          if (!is_delete)
172                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
173            mutex_lock(&ccs_policy_lock);
174            list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
175                  if (ptr->is_not != is_not ||                  if (ptr->is_not != is_not ||
176                      ptr->domainname != saved_domainname ||                      ptr->domainname != saved_domainname ||
177                      ptr->program != saved_program)                      ptr->program != saved_program)
178                          continue;                          continue;
179                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
180                  error = 0;                  error = 0;
181                  goto out;                  break;
182          }          }
183          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
184                  error = -ENOENT;                  entry->domainname = saved_domainname;
185                  goto out;                  saved_domainname = NULL;
186                    entry->program = saved_program;
187                    saved_program = NULL;
188                    entry->is_not = is_not;
189                    entry->is_last_name = is_last_name;
190                    list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);
191                    entry = NULL;
192                    error = 0;
193          }          }
194          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
195          if (!new_entry)          ccs_put_name(saved_domainname);
196                  goto out;          ccs_put_name(saved_program);
197          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);  
198          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
199          return error;          return error;
200  }  }
201    
202  /**  /**
203   * ccs_read_domain_initializer_policy - Read "struct domain_initializer_entry" list.   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.
204   *   *
205   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
206   *   *
207   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
208     *
209     * Caller holds srcu_read_lock(&ccs_ss).
210   */   */
211  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
212  {  {
213          struct list1_head *pos;          struct list_head *pos;
214          list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) {          bool done = true;
215            list_for_each_cookie(pos, head->read_var2,
216                                 &ccs_domain_initializer_list) {
217                  const char *no;                  const char *no;
218                  const char *from = "";                  const char *from = "";
219                  const char *domain = "";                  const char *domain = "";
220                  struct domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
221                  ptr = list1_entry(pos, struct domain_initializer_entry, list);                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
222                                      list);
223                  if (ptr->is_deleted)                  if (ptr->is_deleted)
224                          continue;                          continue;
225                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 286  bool ccs_read_domain_initializer_policy( Line 227  bool ccs_read_domain_initializer_policy(
227                          from = " from ";                          from = " from ";
228                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
229                  }                  }
230                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
231                                     "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",
232                                     no, ptr->program->name, from, domain))                                       no, ptr->program->name, from, domain);
233                                  goto out;                  if (!done)
234                            break;
235          }          }
236          return true;          return done;
  out:  
         return false;  
237  }  }
238    
239  /**  /**
240   * ccs_write_domain_initializer_policy - Write "struct domain_initializer_entry" list.   * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.
241   *   *
242   * @data:      String to parse.   * @data:      String to parse.
243   * @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 251  int ccs_write_domain_initializer_policy(
251          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
252          if (cp) {          if (cp) {
253                  *cp = '\0';                  *cp = '\0';
254                  return update_domain_initializer_entry(cp + 6, data, is_not,                  return ccs_update_domain_initializer_entry(cp + 6, data,
255                                                         is_delete);                                                             is_not, is_delete);
256          }          }
257          return update_domain_initializer_entry(NULL, data, is_not, is_delete);          return ccs_update_domain_initializer_entry(NULL, data, is_not,
258                                                       is_delete);
259  }  }
260    
261  /**  /**
262   * is_domain_initializer - Check whether the given program causes domainname reinitialization.   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.
263   *   *
264   * @domainname: The name of domain.   * @domainname: The name of domain.
265   * @program:    The name of program.   * @program:    The name of program.
# Line 326  int ccs_write_domain_initializer_policy( Line 267  int ccs_write_domain_initializer_policy(
267   *   *
268   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
269   * false otherwise.   * false otherwise.
270     *
271     * Caller holds srcu_read_lock(&ccs_ss).
272   */   */
273  static bool is_domain_initializer(const struct path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
274                                    const struct path_info *program,                                        const struct ccs_path_info *program,
275                                    const struct path_info *last_name)                                        const struct ccs_path_info *last_name)
276  {  {
277          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
278          bool flag = false;          bool flag = false;
279          list1_for_each_entry(ptr,  &domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
280                  if (ptr->is_deleted)                  if (ptr->is_deleted)
281                          continue;                          continue;
282                  if (ptr->domainname) {                  if (ptr->domainname) {
# Line 347  static bool is_domain_initializer(const Line 290  static bool is_domain_initializer(const
290                  }                  }
291                  if (ccs_pathcmp(ptr->program, program))                  if (ccs_pathcmp(ptr->program, program))
292                          continue;                          continue;
293                  if (ptr->is_not)                  if (ptr->is_not) {
294                          return false;                          flag = false;
295                            break;
296                    }
297                  flag = true;                  flag = true;
298          }          }
299          return flag;          return flag;
300  }  }
301    
302  /* The list for "struct domain_keeper_entry". */  /* The list for "struct ccs_domain_keeper_entry". */
303  static LIST1_HEAD(domain_keeper_list);  LIST_HEAD(ccs_domain_keeper_list);
304    
305  /**  /**
306   * update_domain_keeper_entry - Update "struct domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
307   *   *
308   * @domainname: The name of domain.   * @domainname: The name of domain.
309   * @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 312  static LIST1_HEAD(domain_keeper_list);
312   *   *
313   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
314   */   */
315  static int update_domain_keeper_entry(const char *domainname,  static int ccs_update_domain_keeper_entry(const char *domainname,
316                                        const char *program,                                            const char *program,
317                                        const bool is_not, const bool is_delete)                                            const bool is_not,
318  {                                            const bool is_delete)
319          struct domain_keeper_entry *new_entry;  {
320          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *entry = NULL;
321          const struct path_info *saved_domainname;          struct ccs_domain_keeper_entry *ptr;
322          const struct path_info *saved_program = NULL;          const struct ccs_path_info *saved_domainname;
323          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_program = NULL;
324          int error = -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
325          bool is_last_name = false;          bool is_last_name = false;
326          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
327              ccs_is_correct_path(domainname, 1, -1, -1, __func__))              ccs_is_correct_path(domainname, 1, -1, -1))
328                  is_last_name = true;                  is_last_name = true;
329          else if (!ccs_is_correct_domain(domainname, __func__))          else if (!ccs_is_correct_domain(domainname))
330                  return -EINVAL;                  return -EINVAL;
331          if (program) {          if (program) {
332                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))                  if (!ccs_is_correct_path(program, 1, -1, -1))
333                          return -EINVAL;                          return -EINVAL;
334                  saved_program = ccs_save_name(program);                  saved_program = ccs_get_name(program);
335                  if (!saved_program)                  if (!saved_program)
336                          return -ENOMEM;                          return -ENOMEM;
337          }          }
338          saved_domainname = ccs_save_name(domainname);          saved_domainname = ccs_get_name(domainname);
339          if (!saved_domainname)          if (!saved_domainname) {
340                    ccs_put_name(saved_program);
341                  return -ENOMEM;                  return -ENOMEM;
342          mutex_lock(&lock);          }
343          list1_for_each_entry(ptr, &domain_keeper_list, list) {          if (!is_delete)
344                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
345            mutex_lock(&ccs_policy_lock);
346            list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
347                  if (ptr->is_not != is_not ||                  if (ptr->is_not != is_not ||
348                      ptr->domainname != saved_domainname ||                      ptr->domainname != saved_domainname ||
349                      ptr->program != saved_program)                      ptr->program != saved_program)
350                          continue;                          continue;
351                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
352                  error = 0;                  error = 0;
353                  goto out;                  break;
354          }          }
355          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
356                  error = -ENOENT;                  entry->domainname = saved_domainname;
357                  goto out;                  saved_domainname = NULL;
358                    entry->program = saved_program;
359                    saved_program = NULL;
360                    entry->is_not = is_not;
361                    entry->is_last_name = is_last_name;
362                    list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);
363                    entry = NULL;
364                    error = 0;
365          }          }
366          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
367          if (!new_entry)          ccs_put_name(saved_domainname);
368                  goto out;          ccs_put_name(saved_program);
369          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);  
370          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
371          return error;          return error;
372  }  }
373    
374  /**  /**
375   * ccs_write_domain_keeper_policy - Write "struct domain_keeper_entry" list.   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.
376   *   *
377   * @data:      String to parse.   * @data:      String to parse.
378   * @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 385  int ccs_write_domain_keeper_policy(char
385          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
386          if (cp) {          if (cp) {
387                  *cp = '\0';                  *cp = '\0';
388                  return update_domain_keeper_entry(cp + 6, data,                  return ccs_update_domain_keeper_entry(cp + 6, data,
389                                                    is_not, is_delete);                                                        is_not, is_delete);
390          }          }
391          return update_domain_keeper_entry(data, NULL, is_not, is_delete);          return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);
392  }  }
393    
394  /**  /**
395   * ccs_read_domain_keeper_policy - Read "struct domain_keeper_entry" list.   * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.
396   *   *
397   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
398   *   *
399   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
400     *
401     * Caller holds srcu_read_lock(&ccs_ss).
402   */   */
403  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
404  {  {
405          struct list1_head *pos;          struct list_head *pos;
406          list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) {          bool done = true;
407                  struct domain_keeper_entry *ptr;          list_for_each_cookie(pos, head->read_var2,
408                                 &ccs_domain_keeper_list) {
409                    struct ccs_domain_keeper_entry *ptr;
410                  const char *no;                  const char *no;
411                  const char *from = "";                  const char *from = "";
412                  const char *program = "";                  const char *program = "";
413                  ptr = list1_entry(pos, struct domain_keeper_entry, list);                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
414                  if (ptr->is_deleted)                  if (ptr->is_deleted)
415                          continue;                          continue;
416                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 465  bool ccs_read_domain_keeper_policy(struc Line 418  bool ccs_read_domain_keeper_policy(struc
418                          from = " from ";                          from = " from ";
419                          program = ptr->program->name;                          program = ptr->program->name;
420                  }                  }
421                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
422                                     "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,
423                                     program, from, ptr->domainname->name))                                       program, from, ptr->domainname->name);
424                                  goto out;                  if (!done)
425                            break;
426          }          }
427          return true;          return done;
  out:  
         return false;  
428  }  }
429    
430  /**  /**
431   * 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.
432   *   *
433   * @domainname: The name of domain.   * @domainname: The name of domain.
434   * @program:    The name of program.   * @program:    The name of program.
# Line 484  bool ccs_read_domain_keeper_policy(struc Line 436  bool ccs_read_domain_keeper_policy(struc
436   *   *
437   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
438   * false otherwise.   * false otherwise.
439     *
440     * Caller holds srcu_read_lock(&ccs_ss).
441   */   */
442  static bool is_domain_keeper(const struct path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
443                               const struct path_info *program,                                   const struct ccs_path_info *program,
444                               const struct path_info *last_name)                                   const struct ccs_path_info *last_name)
445  {  {
446          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
447          bool flag = false;          bool flag = false;
448          list1_for_each_entry(ptr, &domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
449                  if (ptr->is_deleted)                  if (ptr->is_deleted)
450                          continue;                          continue;
451                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
# Line 503  static bool is_domain_keeper(const struc Line 457  static bool is_domain_keeper(const struc
457                  }                  }
458                  if (ptr->program && ccs_pathcmp(ptr->program, program))                  if (ptr->program && ccs_pathcmp(ptr->program, program))
459                          continue;                          continue;
460                  if (ptr->is_not)                  if (ptr->is_not) {
461                          return false;                          flag = false;
462                            break;
463                    }
464                  flag = true;                  flag = true;
465          }          }
466          return flag;          return flag;
467  }  }
468    
469  /* The list for "struct alias_entry". */  /* The list for "struct ccs_alias_entry". */
470  static LIST1_HEAD(alias_list);  LIST_HEAD(ccs_alias_list);
471    
472  /**  /**
473   * update_alias_entry - Update "struct alias_entry" list.   * ccs_update_alias_entry - Update "struct ccs_alias_entry" list.
474   *   *
475   * @original_name: The original program's real name.   * @original_name: The original program's real name.
476   * @aliased_name:  The symbolic program's symbolic link's name.   * @aliased_name:  The symbolic program's symbolic link's name.
# Line 522  static LIST1_HEAD(alias_list); Line 478  static LIST1_HEAD(alias_list);
478   *   *
479   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
480   */   */
481  static int update_alias_entry(const char *original_name,  static int ccs_update_alias_entry(const char *original_name,
482                                const char *aliased_name,                                    const char *aliased_name,
483                                const bool is_delete)                                    const bool is_delete)
484  {  {
485          struct alias_entry *new_entry;          struct ccs_alias_entry *entry = NULL;
486          struct alias_entry *ptr;          struct ccs_alias_entry *ptr;
487          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_original_name;
488          const struct path_info *saved_original_name;          const struct ccs_path_info *saved_aliased_name;
489          const struct path_info *saved_aliased_name;          int error = is_delete ? -ENOENT : -ENOMEM;
490          int error = -ENOMEM;          if (!ccs_is_correct_path(original_name, 1, -1, -1) ||
491          if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) ||              !ccs_is_correct_path(aliased_name, 1, -1, -1))
             !ccs_is_correct_path(aliased_name, 1, -1, -1, __func__))  
492                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
493          saved_original_name = ccs_save_name(original_name);          saved_original_name = ccs_get_name(original_name);
494          saved_aliased_name = ccs_save_name(aliased_name);          saved_aliased_name = ccs_get_name(aliased_name);
495          if (!saved_original_name || !saved_aliased_name)          if (!saved_original_name || !saved_aliased_name) {
496                    ccs_put_name(saved_original_name);
497                    ccs_put_name(saved_aliased_name);
498                  return -ENOMEM;                  return -ENOMEM;
499          mutex_lock(&lock);          }
500          list1_for_each_entry(ptr, &alias_list, list) {          if (!is_delete)
501                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
502            mutex_lock(&ccs_policy_lock);
503            list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {
504                  if (ptr->original_name != saved_original_name ||                  if (ptr->original_name != saved_original_name ||
505                      ptr->aliased_name != saved_aliased_name)                      ptr->aliased_name != saved_aliased_name)
506                          continue;                          continue;
507                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
508                  error = 0;                  error = 0;
509                  goto out;                  break;
510          }          }
511          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
512                  error = -ENOENT;                  entry->original_name = saved_original_name;
513                  goto out;                  saved_original_name = NULL;
514                    entry->aliased_name = saved_aliased_name;
515                    saved_aliased_name = NULL;
516                    list_add_tail_rcu(&entry->list, &ccs_alias_list);
517                    entry = NULL;
518                    error = 0;
519          }          }
520          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
521          if (!new_entry)          ccs_put_name(saved_original_name);
522                  goto out;          ccs_put_name(saved_aliased_name);
523          new_entry->original_name = saved_original_name;          kfree(entry);
         new_entry->aliased_name = saved_aliased_name;  
         list1_add_tail_mb(&new_entry->list, &alias_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
524          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
525          return error;          return error;
526  }  }
527    
528  /**  /**
529   * ccs_read_alias_policy - Read "struct alias_entry" list.   * ccs_read_alias_policy - Read "struct ccs_alias_entry" list.
530   *   *
531   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
532   *   *
533   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
534     *
535     * Caller holds srcu_read_lock(&ccs_ss).
536   */   */
537  bool ccs_read_alias_policy(struct ccs_io_buffer *head)  bool ccs_read_alias_policy(struct ccs_io_buffer *head)
538  {  {
539          struct list1_head *pos;          struct list_head *pos;
540          list1_for_each_cookie(pos, head->read_var2, &alias_list) {          bool done = true;
541                  struct alias_entry *ptr;          list_for_each_cookie(pos, head->read_var2, &ccs_alias_list) {
542                  ptr = list1_entry(pos, struct alias_entry, list);                  struct ccs_alias_entry *ptr;
543                    ptr = list_entry(pos, struct ccs_alias_entry, list);
544                  if (ptr->is_deleted)                  if (ptr->is_deleted)
545                          continue;                          continue;
546                  if (!ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",                  done = ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",
547                                     ptr->original_name->name,                                       ptr->original_name->name,
548                                     ptr->aliased_name->name))                                       ptr->aliased_name->name);
549                          goto out;                  if (!done)
550                            break;
551          }          }
552          return true;          return done;
  out:  
         return false;  
553  }  }
554    
555  /**  /**
556   * ccs_write_alias_policy - Write "struct alias_entry" list.   * ccs_write_alias_policy - Write "struct ccs_alias_entry" list.
557   *   *
558   * @data:      String to parse.   * @data:      String to parse.
559   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
# Line 604  int ccs_write_alias_policy(char *data, c Line 566  int ccs_write_alias_policy(char *data, c
566          if (!cp)          if (!cp)
567                  return -EINVAL;                  return -EINVAL;
568          *cp++ = '\0';          *cp++ = '\0';
569          return update_alias_entry(data, cp, is_delete);          return ccs_update_alias_entry(data, cp, is_delete);
570  }  }
571    
572  /* The list for "struct aggregator_entry". */  /* The list for "struct ccs_aggregator_entry". */
573  static LIST1_HEAD(aggregator_list);  LIST_HEAD(ccs_aggregator_list);
574    
575  /**  /**
576   * update_aggregator_entry - Update "struct aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
577   *   *
578   * @original_name:   The original program's name.   * @original_name:   The original program's name.
579   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 619  static LIST1_HEAD(aggregator_list); Line 581  static LIST1_HEAD(aggregator_list);
581   *   *
582   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
583   */   */
584  static int update_aggregator_entry(const char *original_name,  static int ccs_update_aggregator_entry(const char *original_name,
585                                     const char *aggregated_name,                                         const char *aggregated_name,
586                                     const bool is_delete)                                         const bool is_delete)
587  {  {
588          struct aggregator_entry *new_entry;          struct ccs_aggregator_entry *entry = NULL;
589          struct aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
590          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_original_name;
591          const struct path_info *saved_original_name;          const struct ccs_path_info *saved_aggregated_name;
592          const struct path_info *saved_aggregated_name;          int error = is_delete ? -ENOENT : -ENOMEM;
593          int error = -ENOMEM;          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
594          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__))  
595                  return -EINVAL;                  return -EINVAL;
596          saved_original_name = ccs_save_name(original_name);          saved_original_name = ccs_get_name(original_name);
597          saved_aggregated_name = ccs_save_name(aggregated_name);          saved_aggregated_name = ccs_get_name(aggregated_name);
598          if (!saved_original_name || !saved_aggregated_name)          if (!saved_original_name || !saved_aggregated_name) {
599                    ccs_put_name(saved_original_name);
600                    ccs_put_name(saved_aggregated_name);
601                  return -ENOMEM;                  return -ENOMEM;
602          mutex_lock(&lock);          }
603          list1_for_each_entry(ptr, &aggregator_list, list) {          if (!is_delete)
604                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
605            mutex_lock(&ccs_policy_lock);
606            list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
607                  if (ptr->original_name != saved_original_name ||                  if (ptr->original_name != saved_original_name ||
608                      ptr->aggregated_name != saved_aggregated_name)                      ptr->aggregated_name != saved_aggregated_name)
609                          continue;                          continue;
610                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
611                  error = 0;                  error = 0;
612                  goto out;                  break;
613          }          }
614          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
615                  error = -ENOENT;                  entry->original_name = saved_original_name;
616                  goto out;                  saved_original_name = NULL;
617                    entry->aggregated_name = saved_aggregated_name;
618                    saved_aggregated_name = NULL;
619                    list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
620                    entry = NULL;
621                    error = 0;
622          }          }
623          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
624          if (!new_entry)          ccs_put_name(saved_original_name);
625                  goto out;          ccs_put_name(saved_aggregated_name);
626          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);  
627          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
628          return error;          return error;
629  }  }
630    
631  /**  /**
632   * ccs_read_aggregator_policy - Read "struct aggregator_entry" list.   * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.
633   *   *
634   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
635   *   *
636   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
637     *
638     * Caller holds srcu_read_lock(&ccs_ss).
639   */   */
640  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
641  {  {
642          struct list1_head *pos;          struct list_head *pos;
643          list1_for_each_cookie(pos, head->read_var2, &aggregator_list) {          bool done = true;
644                  struct aggregator_entry *ptr;          list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
645                  ptr = list1_entry(pos, struct aggregator_entry, list);                  struct ccs_aggregator_entry *ptr;
646                    ptr = list_entry(pos, struct ccs_aggregator_entry, list);
647                  if (ptr->is_deleted)                  if (ptr->is_deleted)
648                          continue;                          continue;
649                  if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",
650                                     ptr->original_name->name,                                       ptr->original_name->name,
651                                     ptr->aggregated_name->name))                                       ptr->aggregated_name->name);
652                          goto out;                  if (!done)
653                            break;
654          }          }
655          return true;          return done;
  out:  
         return false;  
656  }  }
657    
658  /**  /**
659   * ccs_write_aggregator_policy - Write "struct aggregator_entry" list.   * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.
660   *   *
661   * @data:      String to parse.   * @data:      String to parse.
662   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
# Line 701  int ccs_write_aggregator_policy(char *da Line 669  int ccs_write_aggregator_policy(char *da
669          if (!cp)          if (!cp)
670                  return -EINVAL;                  return -EINVAL;
671          *cp++ = '\0';          *cp++ = '\0';
672          return update_aggregator_entry(data, cp, is_delete);          return ccs_update_aggregator_entry(data, cp, is_delete);
673  }  }
674    
675  /* Domain create/delete/undelete handler. */  /* Domain create/delete handler. */
   
 /* #define DEBUG_DOMAIN_UNDELETE */  
676    
677  /**  /**
678   * ccs_delete_domain - Delete a domain.   * ccs_delete_domain - Delete a domain.
# Line 717  int ccs_write_aggregator_policy(char *da Line 683  int ccs_write_aggregator_policy(char *da
683   */   */
684  int ccs_delete_domain(char *domainname)  int ccs_delete_domain(char *domainname)
685  {  {
686          struct domain_info *domain;          struct ccs_domain_info *domain;
687          struct path_info name;          struct ccs_path_info name;
688          name.name = domainname;          name.name = domainname;
689          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
690          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  
691          /* Is there an active domain? */          /* Is there an active domain? */
692          list1_for_each_entry(domain, &domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
693                  struct domain_info *domain2;                  /* Never delete ccs_kernel_domain */
694                  /* Never delete KERNEL_DOMAIN */                  if (domain == &ccs_kernel_domain)
                 if (domain == &KERNEL_DOMAIN)  
695                          continue;                          continue;
696                  if (domain->is_deleted ||                  if (domain->is_deleted ||
697                      ccs_pathcmp(domain->domainname, &name))                      ccs_pathcmp(domain->domainname, &name))
698                          continue;                          continue;
699                  /* 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  
700                  break;                  break;
701          }          }
702          mutex_unlock(&domain_list_lock);          mutex_unlock(&ccs_policy_lock);
703          return 0;          return 0;
704  }  }
705    
706  /**  /**
  * 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;  
 }  
   
 /**  
707   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_find_or_assign_new_domain - Create a domain.
708   *   *
709   * @domainname: The name of domain.   * @domainname: The name of domain.
710   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
711   *   *
712   * Returns pointer to "struct domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
713   */   */
714  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,
715                                                    const u8 profile)                                                        const u8 profile)
716  {  {
717          struct domain_info *domain = NULL;          struct ccs_domain_info *entry;
718          const struct path_info *saved_domainname;          struct ccs_domain_info *domain;
719          mutex_lock(&domain_list_lock);          const struct ccs_path_info *saved_domainname;
720          domain = ccs_find_domain(domainname);          bool found = false;
721          if (domain)  
722                  goto out;          if (!ccs_is_correct_domain(domainname))
723          if (!ccs_is_correct_domain(domainname, __func__))                  return NULL;
724                  goto out;          saved_domainname = ccs_get_name(domainname);
         saved_domainname = ccs_save_name(domainname);  
725          if (!saved_domainname)          if (!saved_domainname)
726                  goto out;                  return NULL;
727          /* Can I reuse memory of deleted domain? */          entry = kzalloc(sizeof(*entry), GFP_KERNEL);
728          list1_for_each_entry(domain, &domain_list, list) {          mutex_lock(&ccs_policy_lock);
729                  struct task_struct *p;          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
730                  struct acl_info *ptr;                  if (domain->is_deleted ||
731                  bool flag;                      ccs_pathcmp(saved_domainname, domain->domainname))
732                  if (!domain->is_deleted ||                          continue;
733                      domain->domainname != saved_domainname)                  found = true;
734                          continue;                  break;
                 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)  
                         continue;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk(KERN_DEBUG "Reusing %p %s\n", domain,  
                        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);  
735          }          }
736   out:          if (!found && ccs_memory_ok(entry)) {
737          mutex_unlock(&domain_list_lock);                  INIT_LIST_HEAD(&entry->acl_info_list);
738          return domain;                  entry->domainname = saved_domainname;
739                    saved_domainname = NULL;
740                    entry->profile = profile;
741                    list_add_tail_rcu(&entry->list, &ccs_domain_list);
742                    domain = entry;
743                    entry = NULL;
744                    found = true;
745            }
746            mutex_unlock(&ccs_policy_lock);
747            ccs_put_name(saved_domainname);
748            kfree(entry);
749            return found ? domain : NULL;
750  }  }
751    
752  /**  /**
753   * get_argv0 - Get argv[0].   * ccs_get_argv0 - Get argv[0].
754   *   *
755   * @bprm: Pointer to "struct linux_binprm".   * @ee: Pointer to "struct ccs_execve_entry".
  * @tmp:  Buffer for temporal use.  
756   *   *
757   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
758   */   */
759  static bool get_argv0(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)  static bool ccs_get_argv0(struct ccs_execve_entry *ee)
760  {  {
761          char *arg_ptr = tmp->buffer;          struct linux_binprm *bprm = ee->bprm;
762            char *arg_ptr = ee->tmp;
763          int arg_len = 0;          int arg_len = 0;
764          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
765          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
766          bool done = false;          bool done = false;
767          if (!bprm->argc)          if (!bprm->argc)
768                  goto out;                  goto out;
769          while (1) {          while (1) {
770                  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)  
771                          goto out;                          goto out;
772                  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;  
                 }  
773                  /* Read. */                  /* Read. */
774                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
775                            const char *kaddr = ee->dump.data;
776                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
777                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
778                                  if (c == '\\') {                                  if (c == '\\') {
# Line 943  static bool get_argv0(struct linux_binpr Line 795  static bool get_argv0(struct linux_binpr
795                                  break;                                  break;
796                          }                          }
797                  }                  }
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
798                  offset = 0;                  offset = 0;
799                  if (done)                  if (done)
800                          break;                          break;
# Line 959  static bool get_argv0(struct linux_binpr Line 805  static bool get_argv0(struct linux_binpr
805  }  }
806    
807  /**  /**
808   * find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
809   *   *
810   * @r:       Pointer to "struct ccs_request_info".   * @ee: Pointer to "struct ccs_execve_entry".
  * @handler: Pathname to verify. May be NULL.  
811   *   *
812   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
813     *
814     * Caller holds srcu_read_lock(&ccs_ss).
815   */   */
816  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)  
817  {  {
818          /*          struct ccs_request_info *r = &ee->r;
819           * This function assumes that the size of buffer returned by          const struct ccs_path_info *handler = ee->handler;
820           * ccs_realpath() = CCS_MAX_PATHNAME_LEN.          struct ccs_domain_info *domain = NULL;
          */  
         struct domain_info *domain = NULL;  
821          const char *old_domain_name = r->domain->domainname->name;          const char *old_domain_name = r->domain->domainname->name;
822          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;  
823          const u8 mode = r->mode;          const u8 mode = r->mode;
824          const bool is_enforce = (mode == 3);          const bool is_enforce = (mode == 3);
825          const u32 tomoyo_flags = r->tomoyo_flags;          const u32 ccs_flags = current->ccs_flags;
826          char *new_domain_name = NULL;          char *new_domain_name = NULL;
827          char *real_program_name = NULL;          struct ccs_path_info rn; /* real name */
828          char *symlink_program_name = NULL;          struct ccs_path_info sn; /* symlink name */
829          struct path_info rn; /* real name */          struct ccs_path_info ln; /* last name */
         struct path_info sn; /* symlink name */  
         struct path_info ln; /* last name */  
830          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;  
                 }  
         }  
   
831   retry:   retry:
832          current->tomoyo_flags = tomoyo_flags;          current->ccs_flags = ccs_flags;
833          r->tomoyo_flags = tomoyo_flags;          r->cond = NULL;
834          /* Get ccs_realpath of program. */          /* Get realpath of program and symbolic link. */
835          retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */          retval = ccs_realpath_both(bprm->filename, ee);
836          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)  
837                  goto out;                  goto out;
838    
839          rn.name = real_program_name;          rn.name = ee->program_path;
840          ccs_fill_path_info(&rn);          ccs_fill_path_info(&rn);
841          sn.name = symlink_program_name;          sn.name = ee->tmp;
842          ccs_fill_path_info(&sn);          ccs_fill_path_info(&sn);
843          ln.name = ccs_get_last_name(r->domain);          ln.name = ccs_get_last_name(r->domain);
844          ccs_fill_path_info(&ln);          ccs_fill_path_info(&ln);
# Line 1042  static int find_next_domain(struct ccs_r Line 859  static int find_next_domain(struct ccs_r
859    
860          /* Check 'alias' directive. */          /* Check 'alias' directive. */
861          if (ccs_pathcmp(&rn, &sn)) {          if (ccs_pathcmp(&rn, &sn)) {
862                  struct alias_entry *ptr;                  struct ccs_alias_entry *ptr;
863                  /* Is this program allowed to be called via symbolic links? */                  /* Is this program allowed to be called via symbolic links? */
864                  list1_for_each_entry(ptr, &alias_list, list) {                  list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {
865                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
866                              ccs_pathcmp(&rn, ptr->original_name) ||                              ccs_pathcmp(&rn, ptr->original_name) ||
867                              ccs_pathcmp(&sn, ptr->aliased_name))                              ccs_pathcmp(&sn, ptr->aliased_name))
868                                  continue;                                  continue;
869                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                          strncpy(ee->program_path, ptr->aliased_name->name,
                         strncpy(real_program_name, ptr->aliased_name->name,  
870                                  CCS_MAX_PATHNAME_LEN - 1);                                  CCS_MAX_PATHNAME_LEN - 1);
871                          ccs_fill_path_info(&rn);                          ccs_fill_path_info(&rn);
872                          break;                          break;
873                  }                  }
874          }          }
875            /* sn will be overwritten after here. */
876    
877          /* Compare basename of real_program_name and argv[0] */          /* Compare basename of program_path and argv[0] */
878          r->mode = ccs_check_flags(r->domain, CCS_TOMOYO_MAC_FOR_ARGV0);          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);
879          if (bprm->argc > 0 && r->mode) {          if (bprm->argc > 0 && r->mode) {
880                  char *base_argv0 = tmp->buffer;                  char *base_argv0 = ee->tmp;
881                  const char *base_filename;                  const char *base_filename;
882                  retval = -ENOMEM;                  retval = -ENOMEM;
883                  if (!get_argv0(bprm, tmp))                  if (!ccs_get_argv0(ee))
884                          goto out;                          goto out;
885                  base_filename = strrchr(real_program_name, '/');                  base_filename = strrchr(ee->program_path, '/');
886                  if (!base_filename)                  if (!base_filename)
887                          base_filename = real_program_name;                          base_filename = ee->program_path;
888                  else                  else
889                          base_filename++;                          base_filename++;
890                  if (strcmp(base_argv0, base_filename)) {                  if (strcmp(base_argv0, base_filename)) {
891                          retval = ccs_check_argv0_perm(r, &rn, base_argv0);                          retval = ccs_check_argv0_perm(r, &rn, base_argv0);
892                          if (retval == 1) {                          if (retval == 1)
                                 r->retry++;  
893                                  goto retry;                                  goto retry;
                         }  
                         r->retry = 0;  
                         r->tomoyo_flags = current->tomoyo_flags;  
894                          if (retval < 0)                          if (retval < 0)
895                                  goto out;                                  goto out;
896                  }                  }
# Line 1085  static int find_next_domain(struct ccs_r Line 898  static int find_next_domain(struct ccs_r
898    
899          /* Check 'aggregator' directive. */          /* Check 'aggregator' directive. */
900          {          {
901                  struct aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
902                  /* Is this program allowed to be aggregated? */                  /* Is this program allowed to be aggregated? */
903                  list1_for_each_entry(ptr, &aggregator_list, list) {                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
904                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
905                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
906                                  continue;                                  continue;
907                          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,  
908                                  CCS_MAX_PATHNAME_LEN - 1);                                  CCS_MAX_PATHNAME_LEN - 1);
909                          ccs_fill_path_info(&rn);                          ccs_fill_path_info(&rn);
910                          break;                          break;
# Line 1102  static int find_next_domain(struct ccs_r Line 914  static int find_next_domain(struct ccs_r
914          /* Check execute permission. */          /* Check execute permission. */
915          r->mode = mode;          r->mode = mode;
916          retval = ccs_check_exec_perm(r, &rn);          retval = ccs_check_exec_perm(r, &rn);
917          if (retval == 1) {          if (retval == 1)
                 r->retry++;  
918                  goto retry;                  goto retry;
         }  
         r->retry = 0;  
         r->tomoyo_flags = current->tomoyo_flags;  
919          if (retval < 0)          if (retval < 0)
920                  goto out;                  goto out;
921    
922   calculate_domain:   calculate_domain:
923          new_domain_name = tmp->buffer;          new_domain_name = ee->tmp;
924          if (is_domain_initializer(r->domain->domainname, &rn, &ln)) {          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
925                  /* Transit to the child of KERNEL_DOMAIN domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
926                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
927                           ROOT_NAME " " "%s", real_program_name);                           ROOT_NAME " " "%s", ee->program_path);
928          } else if (r->domain == &KERNEL_DOMAIN && !sbin_init_started) {          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
929                  /*                  /*
930                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
931                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
932                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
933                   */                   */
934                  domain = r->domain;                  domain = r->domain;
935          } else if (is_domain_keeper(r->domain->domainname, &rn, &ln)) {          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
936                  /* Keep current domain. */                  /* Keep current domain. */
937                  domain = r->domain;                  domain = r->domain;
938          } else {          } else {
939                  /* Normal domain transition. */                  /* Normal domain transition. */
940                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
941                           "%s %s", old_domain_name, real_program_name);                           "%s %s", old_domain_name, ee->program_path);
942          }          }
943          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
944                  goto done;                  goto done;
# Line 1141  static int find_next_domain(struct ccs_r Line 949  static int find_next_domain(struct ccs_r
949                  int error = ccs_check_supervisor(r,                  int error = ccs_check_supervisor(r,
950                                                   "# wants to create domain\n"                                                   "# wants to create domain\n"
951                                                   "%s\n", new_domain_name);                                                   "%s\n", new_domain_name);
952                  if (error == 1) {                  if (error == 1)
                         r->retry++;  
953                          goto retry;                          goto retry;
                 }  
                 r->retry = 0;  
954                  if (error < 0)                  if (error < 0)
955                          goto done;                          goto done;
956          }          }
957          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
958          if (domain)          if (domain)
959                  audit_domain_creation_log(domain);                  ccs_audit_domain_creation_log(r->domain);
960   done:   done:
961          if (!domain) {          if (!domain) {
962                  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 965  static int find_next_domain(struct ccs_r
965                          retval = -EPERM;                          retval = -EPERM;
966                  else {                  else {
967                          retval = 0;                          retval = 0;
968                          ccs_set_domain_flag(r->domain, false,                          r->domain->domain_transition_failed = true;
                                             DOMAIN_FLAGS_TRANSITION_FAILED);  
969                  }                  }
970          } else {          } else {
971                  retval = 0;                  retval = 0;
972          }          }
973   out:   out:
         ccs_free(real_program_name);  
         ccs_free(symlink_program_name);  
974          if (domain)          if (domain)
975                  r->domain = domain;                  r->domain = domain;
976          return retval;          return retval;
977  }  }
978    
979  /**  /**
980   * check_environ - Check permission for environment variable names.   * ccs_check_environ - Check permission for environment variable names.
981   *   *
982   * @r: Pointer to "struct ccs_request_info".   * @ee: Pointer to "struct ccs_execve_entry".
983   *   *
984   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
985   */   */
986  static int check_environ(struct ccs_request_info *r)  static int ccs_check_environ(struct ccs_execve_entry *ee)
987  {  {
988          struct linux_binprm *bprm = r->bprm;          struct ccs_request_info *r = &ee->r;
989          struct ccs_page_buffer *tmp = r->obj->tmp;          struct linux_binprm *bprm = ee->bprm;
990          char *arg_ptr = tmp->buffer;          char *arg_ptr = ee->tmp;
991          int arg_len = 0;          int arg_len = 0;
992          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
993          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
994          int argv_count = bprm->argc;          int argv_count = bprm->argc;
995          int envp_count = bprm->envc;          int envp_count = bprm->envc;
# Line 1197  static int check_environ(struct ccs_requ Line 998  static int check_environ(struct ccs_requ
998          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
999                  return 0;                  return 0;
1000          while (error == -ENOMEM) {          while (error == -ENOMEM) {
1001                  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)  
1002                          goto out;                          goto out;
1003                  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;  
                 }  
1004                  /* Read. */                  /* Read. */
1005                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
1006                            const char *kaddr = ee->dump.data;
1007                          if (!kaddr[offset++])                          if (!kaddr[offset++])
1008                                  argv_count--;                                  argv_count--;
1009                  }                  }
1010                  if (argv_count)                  if (argv_count) {
1011                          goto unmap_page;                          offset = 0;
1012                            continue;
1013                    }
1014                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
1015                            const char *kaddr = ee->dump.data;
1016                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
1017                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1018                                  if (c == '=') {                                  if (c == '=') {
# Line 1254  static int check_environ(struct ccs_requ Line 1044  static int check_environ(struct ccs_requ
1044                          }                          }
1045                          arg_len = 0;                          arg_len = 0;
1046                  }                  }
  unmap_page:  
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
1047                  offset = 0;                  offset = 0;
1048          }          }
1049   out:   out:
# Line 1270  static int check_environ(struct ccs_requ Line 1053  static int check_environ(struct ccs_requ
1053  }  }
1054    
1055  /**  /**
1056   * unescape - Unescape escaped string.   * ccs_unescape - Unescape escaped string.
1057   *   *
1058   * @dest: String to unescape.   * @dest: String to unescape.
1059   *   *
1060   * Returns nothing.   * Returns nothing.
1061   */   */
1062  static void unescape(unsigned char *dest)  static void ccs_unescape(unsigned char *dest)
1063  {  {
1064          unsigned char *src = dest;          unsigned char *src = dest;
1065          unsigned char c;          unsigned char c;
1066          unsigned char d;          unsigned char d;
1067          unsigned char e;          unsigned char e;
1068          while ((c = *src++) != '\0') {          while (1) {
1069                    c = *src++;
1070                    if (!c)
1071                            break;
1072                  if (c != '\\') {                  if (c != '\\') {
1073                          *dest++ = c;                          *dest++ = c;
1074                          continue;                          continue;
# Line 1306  static void unescape(unsigned char *dest Line 1092  static void unescape(unsigned char *dest
1092  }  }
1093    
1094  /**  /**
1095   * root_depth - Get number of directories to strip.   * ccs_root_depth - Get number of directories to strip.
1096   *   *
1097   * @dentry: Pointer to "struct dentry".   * @dentry: Pointer to "struct dentry".
1098   * @vfsmnt: Pointer to "struct vfsmount".   * @vfsmnt: Pointer to "struct vfsmount".
1099   *   *
1100   * Returns number of directories to strip.   * Returns number of directories to strip.
1101   */   */
1102  static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1103  {  {
1104          int depth = 0;          int depth = 0;
1105          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
# Line 1336  static inline int root_depth(struct dent Line 1122  static inline int root_depth(struct dent
1122  }  }
1123    
1124  /**  /**
1125   * get_root_depth - return the depth of root directory.   * ccs_get_root_depth - return the depth of root directory.
1126   *   *
1127   * Returns number of directories to strip.   * Returns number of directories to strip.
1128   */   */
1129  static int get_root_depth(void)  static int ccs_get_root_depth(void)
1130  {  {
1131          int depth;          int depth;
1132          struct dentry *dentry;          struct dentry *dentry;
# Line 1361  static int get_root_depth(void) Line 1147  static int get_root_depth(void)
1147  #endif  #endif
1148          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
1149          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
1150          depth = root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
1151  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1152          path_put(&root);          path_put(&root);
1153  #else  #else
# Line 1371  static int get_root_depth(void) Line 1157  static int get_root_depth(void)
1157          return depth;          return depth;
1158  }  }
1159    
1160    static LIST_HEAD(ccs_execve_list);
1161    static DEFINE_SPINLOCK(ccs_execve_list_lock);
1162    
1163  /**  /**
1164   * try_alt_exec - Try to start execute handler.   * ccs_allocate_execve_entry - Allocate memory for execve().
1165   *   *
1166   * @r:           Pointer to "struct ccs_request_info".   * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1167   * @handler:     Pointer to the name of execute handler.   */
1168   * @eh_path:     Pointer to pointer to the name of execute handler.  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1169    {
1170            struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);
1171            if (!ee)
1172                    return NULL;
1173            memset(ee, 0, sizeof(*ee));
1174            ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1175            ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1176            if (!ee->program_path || !ee->tmp) {
1177                    ccs_free(ee->program_path);
1178                    ccs_free(ee->tmp);
1179                    ccs_free(ee);
1180                    return NULL;
1181            }
1182            /* ee->dump->data is allocated by ccs_dump_page(). */
1183            ee->task = current;
1184            /***** CRITICAL SECTION START *****/
1185            spin_lock(&ccs_execve_list_lock);
1186            list_add(&ee->list, &ccs_execve_list);
1187            spin_unlock(&ccs_execve_list_lock);
1188            /***** CRITICAL SECTION END *****/
1189            return ee;
1190    }
1191    
1192    /**
1193     * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1194     *
1195     * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1196     */
1197    static struct ccs_execve_entry *ccs_find_execve_entry(void)
1198    {
1199            struct task_struct *task = current;
1200            struct ccs_execve_entry *ee = NULL;
1201            struct ccs_execve_entry *p;
1202            /***** CRITICAL SECTION START *****/
1203            spin_lock(&ccs_execve_list_lock);
1204            list_for_each_entry(p, &ccs_execve_list, list) {
1205                    if (p->task != task)
1206                            continue;
1207                    ee = p;
1208                    break;
1209            }
1210            spin_unlock(&ccs_execve_list_lock);
1211            /***** CRITICAL SECTION END *****/
1212            return ee;
1213    }
1214    
1215    /**
1216     * ccs_free_execve_entry - Free memory for execve().
1217     *
1218     * @ee: Pointer to "struct ccs_execve_entry".
1219     */
1220    static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1221    {
1222            if (!ee)
1223                    return;
1224            /***** CRITICAL SECTION START *****/
1225            spin_lock(&ccs_execve_list_lock);
1226            list_del(&ee->list);
1227            spin_unlock(&ccs_execve_list_lock);
1228            /***** CRITICAL SECTION END *****/
1229            ccs_free(ee->program_path);
1230            ccs_free(ee->tmp);
1231            kfree(ee->dump.data);
1232            ccs_free(ee);
1233    }
1234    
1235    /**
1236     * ccs_try_alt_exec - Try to start execute handler.
1237     *
1238     * @ee: Pointer to "struct ccs_execve_entry".
1239   *   *
1240   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1241   */   */
1242  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)  
1243  {  {
1244          /*          /*
1245           * Contents of modified bprm.           * Contents of modified bprm.
# Line 1397  static int try_alt_exec(struct ccs_reque Line 1255  static int try_alt_exec(struct ccs_reque
1255           * modified bprm->argv[0]           * modified bprm->argv[0]
1256           *    = the program's name specified by execute_handler           *    = the program's name specified by execute_handler
1257           * modified bprm->argv[1]           * modified bprm->argv[1]
1258           *    = current->domain_info->domainname->name           *    = ccs_current_domain()->domainname->name
1259           * modified bprm->argv[2]           * modified bprm->argv[2]
1260           *    = the current process's name           *    = the current process's name
1261           * modified bprm->argv[3]           * modified bprm->argv[3]
# Line 1419  static int try_alt_exec(struct ccs_reque Line 1277  static int try_alt_exec(struct ccs_reque
1277           * modified bprm->argv[bprm->envc + bprm->argc + 6]           * modified bprm->argv[bprm->envc + bprm->argc + 6]
1278           *     = original bprm->envp[bprm->envc - 1]           *     = original bprm->envp[bprm->envc - 1]
1279           */           */
1280          struct linux_binprm *bprm = r->bprm;          struct linux_binprm *bprm = ee->bprm;
1281          struct file *filp;          struct file *filp;
1282          int retval;          int retval;
1283          const int original_argc = bprm->argc;          const int original_argc = bprm->argc;
1284          const int original_envc = bprm->envc;          const int original_envc = bprm->envc;
1285          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);  
1286    
1287          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
1288          allow_write_access(bprm->file);          allow_write_access(bprm->file);
1289          fput(bprm->file);          fput(bprm->file);
1290          bprm->file = NULL;          bprm->file = NULL;
1291    
1292          { /* Adjust root directory for open_exec(). */          /* Invalidate page dump cache. */
1293                  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);  
         }  
1294    
1295          /* Move envp[] to argv[] */          /* Move envp[] to argv[] */
1296          bprm->argc += bprm->envc;          bprm->argc += bprm->envc;
# Line 1460  static int try_alt_exec(struct ccs_reque Line 1298  static int try_alt_exec(struct ccs_reque
1298    
1299          /* Set argv[6] */          /* Set argv[6] */
1300          {          {
1301                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
1302                           original_envc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1303                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1304                  if (retval < 0)                  if (retval < 0)
1305                          goto out;                          goto out;
1306                  bprm->argc++;                  bprm->argc++;
# Line 1470  static int try_alt_exec(struct ccs_reque Line 1308  static int try_alt_exec(struct ccs_reque
1308    
1309          /* Set argv[5] */          /* Set argv[5] */
1310          {          {
1311                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
1312                           original_argc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1313                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1314                  if (retval < 0)                  if (retval < 0)
1315                          goto out;                          goto out;
1316                  bprm->argc++;                  bprm->argc++;
# Line 1488  static int try_alt_exec(struct ccs_reque Line 1326  static int try_alt_exec(struct ccs_reque
1326    
1327          /* Set argv[3] */          /* Set argv[3] */
1328          {          {
1329                  const u32 tomoyo_flags = task->tomoyo_flags;                  char *cp = ee->tmp;
1330                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                  const u32 ccs_flags = task->ccs_flags;
1331                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1332                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1333                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1334                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
1335                           task->pid, task->uid, task->gid, task->euid,                           (pid_t) sys_getpid(), current_uid(), current_gid(),
1336                           task->egid, task->suid, task->sgid, task->fsuid,                           current_euid(), current_egid(), current_suid(),
1337                           task->fsgid, (u8) (tomoyo_flags >> 24),                           current_sgid(), current_fsuid(), current_fsgid(),
1338                           (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1339                  retval = copy_strings_kernel(1, &buffer, bprm);                           (u8) (ccs_flags >> 8));
1340                    retval = copy_strings_kernel(1, &cp, bprm);
1341                  if (retval < 0)                  if (retval < 0)
1342                          goto out;                          goto out;
1343                  bprm->argc++;                  bprm->argc++;
# Line 1510  static int try_alt_exec(struct ccs_reque Line 1350  static int try_alt_exec(struct ccs_reque
1350                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1351                          ccs_free(exe);                          ccs_free(exe);
1352                  } else {                  } else {
1353                          snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                          exe = ee->tmp;
1354                                   "<unknown>");                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
1355                          retval = copy_strings_kernel(1, &buffer, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1356                  }                  }
1357                  if (retval < 0)                  if (retval < 0)
1358                          goto out;                          goto out;
# Line 1521  static int try_alt_exec(struct ccs_reque Line 1361  static int try_alt_exec(struct ccs_reque
1361    
1362          /* Set argv[1] */          /* Set argv[1] */
1363          {          {
1364                  strncpy(buffer, task->domain_info->domainname->name,                  char *cp = ee->tmp;
1365                          sizeof(struct ccs_page_buffer) - 1);                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,
1366                  retval = copy_strings_kernel(1, &buffer, bprm);                          CCS_EXEC_TMPSIZE - 1);
1367                    retval = copy_strings_kernel(1, &cp, bprm);
1368                  if (retval < 0)                  if (retval < 0)
1369                          goto out;                          goto out;
1370                  bprm->argc++;                  bprm->argc++;
# Line 1531  static int try_alt_exec(struct ccs_reque Line 1372  static int try_alt_exec(struct ccs_reque
1372    
1373          /* Set argv[0] */          /* Set argv[0] */
1374          {          {
1375                  retval = copy_strings_kernel(1, &execute_handler, bprm);                  int depth = ccs_get_root_depth();
1376                    char *cp = ee->program_path;
1377                    strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);
1378                    ccs_unescape(cp);
1379                    retval = -ENOENT;
1380                    if (!*cp || *cp != '/')
1381                            goto out;
1382                    /* Adjust root directory for open_exec(). */
1383                    while (depth) {
1384                            cp = strchr(cp + 1, '/');
1385                            if (!cp)
1386                                    goto out;
1387                            depth--;
1388                    }
1389                    memmove(ee->program_path, cp, strlen(cp) + 1);
1390                    cp = ee->program_path;
1391                    retval = copy_strings_kernel(1, &cp, bprm);
1392                  if (retval < 0)                  if (retval < 0)
1393                          goto out;                          goto out;
1394                  bprm->argc++;                  bprm->argc++;
# Line 1543  static int try_alt_exec(struct ccs_reque Line 1400  static int try_alt_exec(struct ccs_reque
1400  #endif  #endif
1401    
1402          /* OK, now restart the process with execute handler program's dentry. */          /* OK, now restart the process with execute handler program's dentry. */
1403          filp = open_exec(execute_handler);          filp = open_exec(ee->program_path);
1404          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1405                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1406                  goto out;                  goto out;
1407          }          }
1408          bprm->file = filp;          bprm->file = filp;
1409          bprm->filename = execute_handler;          bprm->filename = ee->program_path;
1410  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1411          bprm->interp = execute_handler;          bprm->interp = bprm->filename;
1412  #endif  #endif
1413          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1414          if (retval < 0)          if (retval < 0)
1415                  goto out;                  goto out;
1416          task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          {
1417          retval = find_next_domain(r, handler);                  /*
1418          task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;                   * Backup ee->program_path because ccs_find_next_domain() will
1419                     * overwrite ee->program_path and ee->tmp.
1420                     */
1421                    const int len = strlen(ee->program_path) + 1;
1422                    char *cp = kmalloc(len, GFP_KERNEL);
1423                    if (!cp) {
1424                            retval = -ENOMEM;
1425                            goto out;
1426                    }
1427                    memmove(cp, ee->program_path, len);
1428                    bprm->filename = cp;
1429    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1430                    bprm->interp = bprm->filename;
1431    #endif
1432                    task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1433                    retval = ccs_find_next_domain(ee);
1434                    task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1435                    /* Restore ee->program_path for search_binary_handler(). */
1436                    memmove(ee->program_path, cp, len);
1437                    bprm->filename = ee->program_path;
1438    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1439                    bprm->interp = bprm->filename;
1440    #endif
1441                    kfree(cp);
1442            }
1443   out:   out:
1444          return retval;          return retval;
1445  }  }
1446    
1447  /**  /**
1448   * find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1449   *   *
1450     * @ee:   Pointer to "struct ccs_execve_entry".
1451   * @type: Type of execute handler.   * @type: Type of execute handler.
1452   *   *
1453   * Returns pointer to "struct path_info" if found, NULL otherwise.   * Returns true if found, false otherwise.
1454     *
1455     * Caller holds srcu_read_lock(&ccs_ss).
1456   */   */
1457  static const struct path_info *find_execute_handler(const u8 type)  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1458                                         const u8 type)
1459  {  {
1460          struct task_struct *task = current;          struct task_struct *task = current;
1461          const struct domain_info *domain = task->domain_info;          const struct ccs_domain_info *domain = ccs_current_domain();
1462          struct acl_info *ptr;          struct ccs_acl_info *ptr;
1463            bool found = false;
1464          /*          /*
1465           * Don't use execute handler if the current process is           * Don't use execute handler if the current process is
1466           * marked as execute handler to avoid infinite execute handler loop.           * marked as execute handler to avoid infinite execute handler loop.
1467           */           */
1468          if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1469                  return NULL;                  return false;
1470          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry(ptr, &domain->acl_info_list, list) {
1471                  struct execute_handler_record *acl;                  struct ccs_execute_handler_record *acl;
1472                  if (ptr->type != type)                  if (ptr->type != type)
1473                          continue;                          continue;
1474                  acl = container_of(ptr, struct execute_handler_record, head);                  acl = container_of(ptr, struct ccs_execute_handler_record,
1475                  return acl->handler;                                     head);
1476                    ee->handler = acl->handler;
1477                    found = true;
1478                    break;
1479          }          }
1480          return NULL;          return found;
1481  }  }
1482    
 /* 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);  
   
1483  /**  /**
1484   * ccs_register_next_domain - Remember next_domain.   * ccs_dump_page - Dump a page to buffer.
1485   *   *
1486   * @next_domain: Pointer to "struct domain_info".   * @bprm: Pointer to "struct linux_binprm".
1487     * @pos:  Location to dump.
1488     * @dump: Poiner to "struct ccs_page_dump".
1489   *   *
1490   * Returns 0 on success, -ENOMEM otherwise.   * Returns true on success, false otherwise.
1491   */   */
1492  static int ccs_register_next_domain(struct domain_info *next_domain)  bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1493                       struct ccs_page_dump *dump)
1494  {  {
1495          struct execve_entry *ee = kmalloc(sizeof(*ee), GFP_KERNEL);          struct page *page;
1496          if (!ee)          /* dump->data is released by ccs_free_execve_entry(). */
1497                  return -ENOMEM;          if (!dump->data) {
1498          ee->task = current;                  dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
1499          ee->next_domain = next_domain;                  if (!dump->data)
1500          /***** CRITICAL SECTION START *****/                          return false;
1501          spin_lock(&execve_list_lock);          }
1502          list_add(&ee->list, &execve_list);          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1503          spin_unlock(&execve_list_lock);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1504          /***** CRITICAL SECTION END *****/          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1505          return 0;                  return false;
1506    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1507            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1508                    return false;
1509    #else
1510            page = bprm->page[pos / PAGE_SIZE];
1511    #endif
1512            if (page != dump->page) {
1513                    const unsigned int offset = pos % PAGE_SIZE;
1514                    /*
1515                     * Maybe kmap()/kunmap() should be used here.
1516                     * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1517                     * So do I.
1518                     */
1519                    char *kaddr = kmap_atomic(page, KM_USER0);
1520                    dump->page = page;
1521                    memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1522                    kunmap_atomic(kaddr, KM_USER0);
1523            }
1524            /* Same with put_arg_page(page) in fs/exec.c */
1525    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1526            put_page(page);
1527    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1528            put_page(page);
1529    #endif
1530            return true;
1531  }  }
1532    
1533  /**  /**
1534   * ccs_fetch_next_domain - Fetch next_domain from the list.   * ccs_fetch_next_domain - Fetch next_domain from the list.
1535   *   *
1536   * 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()
1537   * succeeds. This function does not return NULL.   * succeeds. This function does not return NULL.
1538   */   */
1539  struct domain_info *ccs_fetch_next_domain(void)  struct ccs_domain_info *ccs_fetch_next_domain(void)
1540  {  {
1541          struct task_struct *task = current;          struct ccs_execve_entry *ee = ccs_find_execve_entry();
1542          struct domain_info *next_domain = task->domain_info;          struct ccs_domain_info *next_domain = NULL;
1543          struct execve_entry *p;          if (ee)
1544          /***** CRITICAL SECTION START *****/                  next_domain = ee->r.domain;
1545          spin_lock(&execve_list_lock);          if (!next_domain)
1546          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 *****/  
1547          return next_domain;          return next_domain;
1548  }  }
1549    
1550  /**  /**
1551   * 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.  
1552   *   *
1553   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
  * @regs: Pointer to "struct pt_regs".  
1554   *   *
1555   * Returns result of search_binary_handler() on success,   * Returns 0 on success, negative value otherwise.
  * negative value otherwise.  
1556   */   */
1557  int search_binary_handler_with_transition(struct linux_binprm *bprm,  int ccs_start_execve(struct linux_binprm *bprm)
                                           struct pt_regs *regs)  
1558  {  {
1559          int retval;          int retval;
1560          struct task_struct *task = current;          struct task_struct *task = current;
1561          const struct path_info *handler;          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1562          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)  
1563                  ccs_load_policy(bprm->filename);                  ccs_load_policy(bprm->filename);
1564          if (!tmp)          if (!ee)
1565                  return -ENOMEM;                  return -ENOMEM;
1566            ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);
1567          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);          ee->r.ee = ee;
1568          r.bprm = bprm;          ee->bprm = bprm;
1569          r.obj = &obj;          ee->r.obj = &ee->obj;
1570          obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1_dentry = bprm->file->f_dentry;
1571          obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;
         obj.tmp = tmp;  
   
1572          /* Clear manager flag. */          /* Clear manager flag. */
1573          task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1574          handler = find_execute_handler(TYPE_EXECUTE_HANDLER);          if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {
1575          if (handler) {                  retval = ccs_try_alt_exec(ee);
                 retval = try_alt_exec(&r, handler, &eh_path);  
1576                  if (!retval)                  if (!retval)
1577                          audit_execute_handler_log(true, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, true);
1578                  goto ok;                  goto ok;
1579          }          }
1580          retval = find_next_domain(&r, NULL);          retval = ccs_find_next_domain(ee);
1581          if (retval != -EPERM)          if (retval != -EPERM)
1582                  goto ok;                  goto ok;
1583          handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {
1584          if (handler) {                  retval = ccs_try_alt_exec(ee);
                 retval = try_alt_exec(&r, handler, &eh_path);  
1585                  if (!retval)                  if (!retval)
1586                          audit_execute_handler_log(false, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, false);
1587          }          }
1588   ok:   ok:
1589          if (retval < 0)          if (retval < 0)
1590                  goto out;                  goto out;
1591          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);
1592          retval = check_environ(&r);          retval = ccs_check_environ(ee);
1593          if (retval < 0)          if (retval < 0)
1594                  goto out;                  goto out;
1595          retval = ccs_register_next_domain(r.domain);          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1596          if (retval < 0)          retval = 0;
1597                  goto out;   out:
1598          task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;          if (retval)
1599          retval = search_binary_handler(bprm, regs);                  ccs_finish_execve(retval);
1600          task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;          return retval;
1601    }
1602    
1603    /**
1604     * ccs_finish_execve - Clean up execve() operation.
1605     *
1606     * @retval: Return code of an execve() operation.
1607     *
1608     * Caller holds srcu_read_lock(&ccs_ss).
1609     */
1610    void ccs_finish_execve(int retval)
1611    {
1612            struct task_struct *task = current;
1613            struct ccs_execve_entry *ee = ccs_find_execve_entry();
1614            task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1615            if (!ee)
1616                    return;
1617          if (retval < 0)          if (retval < 0)
1618                  goto out;                  goto out;
1619          /* Proceed to next domain if execution suceeded. */          /* Proceed to next domain if execution suceeded. */
1620          task->domain_info = r.domain;          task->ccs_domain_info = ee->r.domain;
         mb(); /* Make domain transition visible to other CPUs. */  
1621          /* Mark the current process as execute handler. */          /* Mark the current process as execute handler. */
1622          if (handler)          if (ee->handler)
1623                  task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1624          /* Mark the current process as normal process. */          /* Mark the current process as normal process. */
1625          else          else
1626                  task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1627   out:   out:
1628          ccs_unregister_next_domain();          ccs_exit_request_info(&ee->r);
1629          ccs_free(eh_path);          ccs_free_execve_entry(ee);
         ccs_free(tmp);  
         return retval;  
1630  }  }
1631    
1632  #else  #else
1633    
1634  /**  /**
1635   * search_binary_handler_with_transition - Wrapper for search_binary_handler().   * ccs_start_execve - Prepare for execve() operation.
1636   *   *
1637   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
  * @regs: Pointer to "struct pt_regs".  
1638   *   *
1639   * Returns the result of search_binary_handler().   * Returns 0.
1640   */   */
1641  int search_binary_handler_with_transition(struct linux_binprm *bprm,  int ccs_start_execve(struct linux_binprm *bprm)
                                           struct pt_regs *regs)  
1642  {  {
1643  #ifdef CONFIG_SAKURA  #ifdef CONFIG_SAKURA
1644          /* Clear manager flag. */          /* Clear manager flag. */
1645          current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1646          ccs_load_policy(bprm->filename);          if (!ccs_policy_loaded)
1647                    ccs_load_policy(bprm->filename);
1648  #endif  #endif
1649          return search_binary_handler(bprm, regs);          return 0;
1650    }
1651    
1652    /**
1653     * ccs_finish_execve - Clean up execve() operation.
1654     */
1655    void ccs_finish_execve(int retval)
1656    {
1657  }  }
1658    
1659  #endif  #endif

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

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