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

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

Legend:
Removed from v.1260  
changed lines
  Added in v.2718

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