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

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 1561 by kumaneko, Tue Sep 9 04:29:07 2008 UTC branches/ccs-patch/fs/tomoyo_domain.c revision 2545 by kumaneko, Thu May 14 07:44:57 2009 UTC
# Line 3  Line 3 
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Implementation of the Domain-Based Mandatory Access Control.
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Copyright (C) 2005-2009  NTT DATA CORPORATION
7   *   *
8   * Version: 1.6.5-pre   2008/09/09   * Version: 1.6.8-pre   2009/05/08
9   *   *
10   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
11   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
# Line 16  Line 16 
16  #include <linux/tomoyo.h>  #include <linux/tomoyo.h>
17  #include <linux/realpath.h>  #include <linux/realpath.h>
18  #include <linux/highmem.h>  #include <linux/highmem.h>
 #include <linux/binfmts.h>  
19  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
20  #include <linux/namei.h>  #include <linux/namei.h>
21  #include <linux/mount.h>  #include <linux/mount.h>
22  #endif  #endif
23    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
24    #include <linux/fs_struct.h>
25    #endif
26    
27  /* For compatibility with older kernels. */  /* For compatibility with older kernels. */
28  #ifndef for_each_process  #ifndef for_each_process
# Line 30  Line 32 
32  /* Variables definitions.*/  /* Variables definitions.*/
33    
34  /* The initial domain. */  /* The initial domain. */
35  struct domain_info KERNEL_DOMAIN;  struct ccs_domain_info ccs_kernel_domain;
36    
37  /* The list for "struct domain_info". */  /* The list for "struct ccs_domain_info". */
38  LIST1_HEAD(domain_list);  LIST_HEAD(ccs_domain_list);
39    
40  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
41    
 /* Lock for appending domain's ACL. */  
 DEFINE_MUTEX(domain_acl_lock);  
   
 /* 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);  
 }  
   
42  /**  /**
43   * ccs_get_last_name - Get last component of a domainname.   * ccs_get_last_name - Get last component of a domainname.
44   *   *
45   * @domain: Pointer to "struct domain_info".   * @domain: Pointer to "struct ccs_domain_info".
46   *   *
47   * Returns the last component of the domainname.   * Returns the last component of the domainname.
48   */   */
49  const char *ccs_get_last_name(const struct domain_info *domain)  const char *ccs_get_last_name(const struct ccs_domain_info *domain)
50  {  {
51          const char *cp0 = domain->domainname->name, *cp1 = strrchr(cp0, ' ');          const char *cp0 = domain->domainname->name;
52            const char *cp1 = strrchr(cp0, ' ');
53          if (cp1)          if (cp1)
54                  return cp1 + 1;                  return cp1 + 1;
55          return cp0;          return cp0;
# Line 117  const char *ccs_get_last_name(const stru Line 58  const char *ccs_get_last_name(const stru
58  /**  /**
59   * ccs_add_domain_acl - Add the given ACL to the given domain.   * ccs_add_domain_acl - Add the given ACL to the given domain.
60   *   *
61   * @domain: Pointer to "struct domain_info". May be NULL.   * @domain: Pointer to "struct ccs_domain_info". May be NULL.
62   * @acl:    Pointer to "struct acl_info".   * @acl:    Pointer to "struct ccs_acl_info".
63   *   *
64   * Returns 0.   * Returns 0.
65   */   */
66  int ccs_add_domain_acl(struct domain_info *domain, struct acl_info *acl)  int ccs_add_domain_acl(struct ccs_domain_info *domain, struct ccs_acl_info *acl)
67  {  {
68          if (domain)          if (domain) {
69                  list1_add_tail_mb(&acl->list, &domain->acl_info_list);                  list_add_tail(&acl->list, &domain->acl_info_list);
70          else          } else {
71                  acl->type &= ~ACL_DELETED;                  acl->type &= ~ACL_DELETED;
72            }
73          ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
74          return 0;          return 0;
75  }  }
# Line 135  int ccs_add_domain_acl(struct domain_inf Line 77  int ccs_add_domain_acl(struct domain_inf
77  /**  /**
78   * ccs_del_domain_acl - Delete the given ACL from the domain.   * ccs_del_domain_acl - Delete the given ACL from the domain.
79   *   *
80   * @acl: Pointer to "struct acl_info". May be NULL.   * @acl: Pointer to "struct ccs_acl_info". May be NULL.
81   *   *
82   * Returns 0.   * Returns 0.
83   */   */
84  int ccs_del_domain_acl(struct acl_info *acl)  int ccs_del_domain_acl(struct ccs_acl_info *acl)
85  {  {
86          if (acl)          if (acl)
87                  acl->type |= ACL_DELETED;                  acl->type |= ACL_DELETED;
# Line 148  int ccs_del_domain_acl(struct acl_info * Line 90  int ccs_del_domain_acl(struct acl_info *
90  }  }
91    
92  /**  /**
93   * audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
94   *   *
95     * @ee:         Pointer to "struct ccs_execve_entry".
96   * @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".  
97   *   *
98   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
99   */   */
100  static int audit_execute_handler_log(const bool is_default,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
101                                       const char *handler,                                           const bool is_default)
102                                       struct linux_binprm *bprm)  {
103  {          struct ccs_request_info *r = &ee->r;
104          char *buf;          const char *handler = ee->handler->name;
105          int len;          r->mode = ccs_check_flags(r->cookie.u.domain, CCS_MAC_FOR_FILE);
106          int len2;          return ccs_write_audit_log(true, r, "%s %s\n",
107          u8 profile;                                     is_default ? KEYWORD_EXECUTE_HANDLER :
108          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);  
109  }  }
110    
111  /**  /**
112   * audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
113   *   *
114   * @domainname: The name of newly created domain.   * @domain:  Pointer to "struct ccs_domain_info".
  * @mode:       Access control mode used.  
  * @profile:    Profile number used.  
115   *   *
116   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
117   */   */
118  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)  
119  {  {
120          char *buf;          int error;
121          char *cp;          struct ccs_request_info r;
122          int len;          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);
123          int len2;          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
124          if (ccs_can_save_audit_log(false) < 0)          ccs_exit_request_info(&r);
125                  return -ENOMEM;          return error;
         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);  
126  }  }
127    
128  /* The list for "struct domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
129  static LIST1_HEAD(domain_initializer_list);  LIST_HEAD(ccs_domain_initializer_list);
130    
131  /**  /**
132   * update_domain_initializer_entry - Update "struct domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
133   *   *
134   * @domainname: The name of domain. May be NULL.   * @domainname: The name of domain. May be NULL.
135   * @program:    The name of program.   * @program:    The name of program.
# Line 227  static LIST1_HEAD(domain_initializer_lis Line 138  static LIST1_HEAD(domain_initializer_lis
138   *   *
139   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
140   */   */
141  static int update_domain_initializer_entry(const char *domainname,  static int ccs_update_domain_initializer_entry(const char *domainname,
142                                             const char *program,                                                 const char *program,
143                                             const bool is_not,                                                 const bool is_not,
144                                             const bool is_delete)                                                 const bool is_delete)
145  {  {
146          struct domain_initializer_entry *new_entry;          struct ccs_domain_initializer_entry *entry = NULL;
147          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
148          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_program;
149          const struct path_info *saved_program;          const struct ccs_path_info *saved_domainname = NULL;
150          const struct path_info *saved_domainname = NULL;          int error = is_delete ? -ENOENT : -ENOMEM;
         int error = -ENOMEM;  
151          bool is_last_name = false;          bool is_last_name = false;
152          if (!ccs_is_correct_path(program, 1, -1, -1, __func__))          if (!ccs_is_correct_path(program, 1, -1, -1, __func__))
153                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
# Line 247  static int update_domain_initializer_ent Line 157  static int update_domain_initializer_ent
157                          is_last_name = true;                          is_last_name = true;
158                  else if (!ccs_is_correct_domain(domainname, __func__))                  else if (!ccs_is_correct_domain(domainname, __func__))
159                          return -EINVAL;                          return -EINVAL;
160                  saved_domainname = ccs_save_name(domainname);                  saved_domainname = ccs_get_name(domainname);
161                  if (!saved_domainname)                  if (!saved_domainname)
162                          return -ENOMEM;                          return -ENOMEM;
163          }          }
164          saved_program = ccs_save_name(program);          saved_program = ccs_get_name(program);
165          if (!saved_program)          if (!saved_program) {
166                    ccs_put_name(saved_domainname);
167                  return -ENOMEM;                  return -ENOMEM;
168          mutex_lock(&lock);          }
169          list1_for_each_entry(ptr, &domain_initializer_list, list) {          if (!is_delete)
170                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
171            /***** WRITER SECTION START *****/
172            down_write(&ccs_policy_lock);
173            list_for_each_entry(ptr, &ccs_domain_initializer_list, list) {
174                  if (ptr->is_not != is_not ||                  if (ptr->is_not != is_not ||
175                      ptr->domainname != saved_domainname ||                      ptr->domainname != saved_domainname ||
176                      ptr->program != saved_program)                      ptr->program != saved_program)
177                          continue;                          continue;
178                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
179                  error = 0;                  error = 0;
180                  goto out;                  break;
181          }          }
182          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
183                  error = -ENOENT;                  entry->domainname = saved_domainname;
184                  goto out;                  saved_domainname = NULL;
185                    entry->program = saved_program;
186                    saved_program = NULL;
187                    entry->is_not = is_not;
188                    entry->is_last_name = is_last_name;
189                    list_add_tail(&entry->list, &ccs_domain_initializer_list);
190                    entry = NULL;
191                    error = 0;
192          }          }
193          new_entry = ccs_alloc_element(sizeof(*new_entry));          up_write(&ccs_policy_lock);
194          if (!new_entry)          /***** WRITER SECTION END *****/
195                  goto out;          ccs_put_name(saved_domainname);
196          new_entry->domainname = saved_domainname;          ccs_put_name(saved_program);
197          new_entry->program = saved_program;          kfree(entry);
         new_entry->is_not = is_not;  
         new_entry->is_last_name = is_last_name;  
         list1_add_tail_mb(&new_entry->list, &domain_initializer_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
198          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
199          return error;          return error;
200  }  }
201    
202  /**  /**
203   * ccs_read_domain_initializer_policy - Read "struct domain_initializer_entry" list.   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.
204   *   *
205   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
206   *   *
# Line 292  static int update_domain_initializer_ent Line 208  static int update_domain_initializer_ent
208   */   */
209  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
210  {  {
211          struct list1_head *pos;          struct list_head *pos;
212          list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) {          bool done = true;
213            /***** READER SECTION START *****/
214            down_read(&ccs_policy_lock);
215            list_for_each_cookie(pos, head->read_var2.u.list,
216                                  &ccs_domain_initializer_list) {
217                  const char *no;                  const char *no;
218                  const char *from = "";                  const char *from = "";
219                  const char *domain = "";                  const char *domain = "";
220                  struct domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
221                  ptr = list1_entry(pos, struct domain_initializer_entry, list);                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
222                                      list);
223                  if (ptr->is_deleted)                  if (ptr->is_deleted)
224                          continue;                          continue;
225                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 306  bool ccs_read_domain_initializer_policy( Line 227  bool ccs_read_domain_initializer_policy(
227                          from = " from ";                          from = " from ";
228                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
229                  }                  }
230                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
231                                     "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",
232                                     no, ptr->program->name, from, domain))                                       no, ptr->program->name, from, domain);
233                                  goto out;                  if (!done)
234                            break;
235          }          }
236          return true;          up_read(&ccs_policy_lock);
237   out:          /***** READER SECTION END *****/
238          return false;          return done;
239  }  }
240    
241  /**  /**
242   * ccs_write_domain_initializer_policy - Write "struct domain_initializer_entry" list.   * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.
243   *   *
244   * @data:      String to parse.   * @data:      String to parse.
245   * @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 253  int ccs_write_domain_initializer_policy(
253          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
254          if (cp) {          if (cp) {
255                  *cp = '\0';                  *cp = '\0';
256                  return update_domain_initializer_entry(cp + 6, data, is_not,                  return ccs_update_domain_initializer_entry(cp + 6, data,
257                                                         is_delete);                                                             is_not, is_delete);
258          }          }
259          return update_domain_initializer_entry(NULL, data, is_not, is_delete);          return ccs_update_domain_initializer_entry(NULL, data, is_not,
260                                                       is_delete);
261  }  }
262    
263  /**  /**
264   * is_domain_initializer - Check whether the given program causes domainname reinitialization.   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.
265   *   *
266   * @domainname: The name of domain.   * @domainname: The name of domain.
267   * @program:    The name of program.   * @program:    The name of program.
# Line 347  int ccs_write_domain_initializer_policy( Line 270  int ccs_write_domain_initializer_policy(
270   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
271   * false otherwise.   * false otherwise.
272   */   */
273  static bool is_domain_initializer(const struct path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
274                                    const struct path_info *program,                                        const struct ccs_path_info *program,
275                                    const struct path_info *last_name)                                        const struct ccs_path_info *last_name)
276  {  {
277          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
278          bool flag = false;          bool flag = false;
279          list1_for_each_entry(ptr,  &domain_initializer_list, list) {          /***** READER SECTION START *****/
280            down_read(&ccs_policy_lock);
281            list_for_each_entry(ptr, &ccs_domain_initializer_list, list) {
282                  if (ptr->is_deleted)                  if (ptr->is_deleted)
283                          continue;                          continue;
284                  if (ptr->domainname) {                  if (ptr->domainname) {
# Line 367  static bool is_domain_initializer(const Line 292  static bool is_domain_initializer(const
292                  }                  }
293                  if (ccs_pathcmp(ptr->program, program))                  if (ccs_pathcmp(ptr->program, program))
294                          continue;                          continue;
295                  if (ptr->is_not)                  if (ptr->is_not) {
296                          return false;                          flag = false;
297                            break;
298                    }
299                  flag = true;                  flag = true;
300          }          }
301            up_read(&ccs_policy_lock);
302            /***** READER SECTION END *****/
303          return flag;          return flag;
304  }  }
305    
306  /* The list for "struct domain_keeper_entry". */  /* The list for "struct ccs_domain_keeper_entry". */
307  static LIST1_HEAD(domain_keeper_list);  LIST_HEAD(ccs_domain_keeper_list);
308    
309  /**  /**
310   * update_domain_keeper_entry - Update "struct domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
311   *   *
312   * @domainname: The name of domain.   * @domainname: The name of domain.
313   * @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 316  static LIST1_HEAD(domain_keeper_list);
316   *   *
317   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
318   */   */
319  static int update_domain_keeper_entry(const char *domainname,  static int ccs_update_domain_keeper_entry(const char *domainname,
320                                        const char *program,                                            const char *program,
321                                        const bool is_not, const bool is_delete)                                            const bool is_not,
322  {                                            const bool is_delete)
323          struct domain_keeper_entry *new_entry;  {
324          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *entry = NULL;
325          const struct path_info *saved_domainname;          struct ccs_domain_keeper_entry *ptr;
326          const struct path_info *saved_program = NULL;          const struct ccs_path_info *saved_domainname;
327          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_program = NULL;
328          int error = -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
329          bool is_last_name = false;          bool is_last_name = false;
330          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
331              ccs_is_correct_path(domainname, 1, -1, -1, __func__))              ccs_is_correct_path(domainname, 1, -1, -1, __func__))
# Line 406  static int update_domain_keeper_entry(co Line 335  static int update_domain_keeper_entry(co
335          if (program) {          if (program) {
336                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))
337                          return -EINVAL;                          return -EINVAL;
338                  saved_program = ccs_save_name(program);                  saved_program = ccs_get_name(program);
339                  if (!saved_program)                  if (!saved_program)
340                          return -ENOMEM;                          return -ENOMEM;
341          }          }
342          saved_domainname = ccs_save_name(domainname);          saved_domainname = ccs_get_name(domainname);
343          if (!saved_domainname)          if (!saved_domainname) {
344                    ccs_put_name(saved_program);
345                  return -ENOMEM;                  return -ENOMEM;
346          mutex_lock(&lock);          }
347          list1_for_each_entry(ptr, &domain_keeper_list, list) {          if (!is_delete)
348                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
349            /***** WRITER SECTION START *****/
350            down_write(&ccs_policy_lock);
351            list_for_each_entry(ptr, &ccs_domain_keeper_list, list) {
352                  if (ptr->is_not != is_not ||                  if (ptr->is_not != is_not ||
353                      ptr->domainname != saved_domainname ||                      ptr->domainname != saved_domainname ||
354                      ptr->program != saved_program)                      ptr->program != saved_program)
355                          continue;                          continue;
356                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
357                  error = 0;                  error = 0;
358                  goto out;                  break;
359          }          }
360          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
361                  error = -ENOENT;                  entry->domainname = saved_domainname;
362                  goto out;                  saved_domainname = NULL;
363                    entry->program = saved_program;
364                    saved_program = NULL;
365                    entry->is_not = is_not;
366                    entry->is_last_name = is_last_name;
367                    list_add_tail(&entry->list, &ccs_domain_keeper_list);
368                    entry = NULL;
369                    error = 0;
370          }          }
371          new_entry = ccs_alloc_element(sizeof(*new_entry));          up_write(&ccs_policy_lock);
372          if (!new_entry)          /***** WRITER SECTION END *****/
373                  goto out;          ccs_put_name(saved_domainname);
374          new_entry->domainname = saved_domainname;          ccs_put_name(saved_program);
375          new_entry->program = saved_program;          kfree(entry);
         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);  
376          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
377          return error;          return error;
378  }  }
379    
380  /**  /**
381   * ccs_write_domain_keeper_policy - Write "struct domain_keeper_entry" list.   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.
382   *   *
383   * @data:      String to parse.   * @data:      String to parse.
384   * @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 391  int ccs_write_domain_keeper_policy(char
391          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
392          if (cp) {          if (cp) {
393                  *cp = '\0';                  *cp = '\0';
394                  return update_domain_keeper_entry(cp + 6, data,                  return ccs_update_domain_keeper_entry(cp + 6, data,
395                                                    is_not, is_delete);                                                        is_not, is_delete);
396          }          }
397          return update_domain_keeper_entry(data, NULL, is_not, is_delete);          return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);
398  }  }
399    
400  /**  /**
401   * ccs_read_domain_keeper_policy - Read "struct domain_keeper_entry" list.   * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.
402   *   *
403   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
404   *   *
# Line 471  int ccs_write_domain_keeper_policy(char Line 406  int ccs_write_domain_keeper_policy(char
406   */   */
407  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
408  {  {
409          struct list1_head *pos;          struct list_head *pos;
410          list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) {          bool done = true;
411                  struct domain_keeper_entry *ptr;          /***** READER SECTION START *****/
412            down_read(&ccs_policy_lock);
413            list_for_each_cookie(pos, head->read_var2.u.list,
414                                  &ccs_domain_keeper_list) {
415                    struct ccs_domain_keeper_entry *ptr;
416                  const char *no;                  const char *no;
417                  const char *from = "";                  const char *from = "";
418                  const char *program = "";                  const char *program = "";
419                  ptr = list1_entry(pos, struct domain_keeper_entry, list);                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
420                  if (ptr->is_deleted)                  if (ptr->is_deleted)
421                          continue;                          continue;
422                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 485  bool ccs_read_domain_keeper_policy(struc Line 424  bool ccs_read_domain_keeper_policy(struc
424                          from = " from ";                          from = " from ";
425                          program = ptr->program->name;                          program = ptr->program->name;
426                  }                  }
427                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head,
428                                     "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,
429                                     program, from, ptr->domainname->name))                                       program, from, ptr->domainname->name);
430                                  goto out;                  if (!done)
431                            break;
432          }          }
433          return true;          up_read(&ccs_policy_lock);
434   out:          /***** READER SECTION END *****/
435          return false;          return done;
436  }  }
437    
438  /**  /**
439   * 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.
440   *   *
441   * @domainname: The name of domain.   * @domainname: The name of domain.
442   * @program:    The name of program.   * @program:    The name of program.
# Line 505  bool ccs_read_domain_keeper_policy(struc Line 445  bool ccs_read_domain_keeper_policy(struc
445   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
446   * false otherwise.   * false otherwise.
447   */   */
448  static bool is_domain_keeper(const struct path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
449                               const struct path_info *program,                                   const struct ccs_path_info *program,
450                               const struct path_info *last_name)                                   const struct ccs_path_info *last_name)
451  {  {
452          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
453          bool flag = false;          bool flag = false;
454          list1_for_each_entry(ptr, &domain_keeper_list, list) {          /***** READER SECTION START *****/
455            down_read(&ccs_policy_lock);
456            list_for_each_entry(ptr, &ccs_domain_keeper_list, list) {
457                  if (ptr->is_deleted)                  if (ptr->is_deleted)
458                          continue;                          continue;
459                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
# Line 523  static bool is_domain_keeper(const struc Line 465  static bool is_domain_keeper(const struc
465                  }                  }
466                  if (ptr->program && ccs_pathcmp(ptr->program, program))                  if (ptr->program && ccs_pathcmp(ptr->program, program))
467                          continue;                          continue;
468                  if (ptr->is_not)                  if (ptr->is_not) {
469                          return false;                          flag = false;
470                            break;
471                    }
472                  flag = true;                  flag = true;
473          }          }
474            up_read(&ccs_policy_lock);
475            /***** READER SECTION END *****/
476          return flag;          return flag;
477  }  }
478    
479  /* The list for "struct alias_entry". */  /* The list for "struct ccs_alias_entry". */
480  static LIST1_HEAD(alias_list);  LIST_HEAD(ccs_alias_list);
481    
482  /**  /**
483   * update_alias_entry - Update "struct alias_entry" list.   * ccs_update_alias_entry - Update "struct ccs_alias_entry" list.
484   *   *
485   * @original_name: The original program's real name.   * @original_name: The original program's real name.
486   * @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 488  static LIST1_HEAD(alias_list);
488   *   *
489   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
490   */   */
491  static int update_alias_entry(const char *original_name,  static int ccs_update_alias_entry(const char *original_name,
492                                const char *aliased_name,                                    const char *aliased_name,
493                                const bool is_delete)                                    const bool is_delete)
494  {  {
495          struct alias_entry *new_entry;          struct ccs_alias_entry *entry = NULL;
496          struct alias_entry *ptr;          struct ccs_alias_entry *ptr;
497          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_original_name;
498          const struct path_info *saved_original_name;          const struct ccs_path_info *saved_aliased_name;
499          const struct path_info *saved_aliased_name;          int error = is_delete ? -ENOENT : -ENOMEM;
         int error = -ENOMEM;  
500          if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) ||          if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) ||
501              !ccs_is_correct_path(aliased_name, 1, -1, -1, __func__))              !ccs_is_correct_path(aliased_name, 1, -1, -1, __func__))
502                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
503          saved_original_name = ccs_save_name(original_name);          saved_original_name = ccs_get_name(original_name);
504          saved_aliased_name = ccs_save_name(aliased_name);          saved_aliased_name = ccs_get_name(aliased_name);
505          if (!saved_original_name || !saved_aliased_name)          if (!saved_original_name || !saved_aliased_name) {
506                    ccs_put_name(saved_original_name);
507                    ccs_put_name(saved_aliased_name);
508                  return -ENOMEM;                  return -ENOMEM;
509          mutex_lock(&lock);          }
510          list1_for_each_entry(ptr, &alias_list, list) {          if (!is_delete)
511                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
512            /***** WRITER SECTION START *****/
513            down_write(&ccs_policy_lock);
514            list_for_each_entry(ptr, &ccs_alias_list, list) {
515                  if (ptr->original_name != saved_original_name ||                  if (ptr->original_name != saved_original_name ||
516                      ptr->aliased_name != saved_aliased_name)                      ptr->aliased_name != saved_aliased_name)
517                          continue;                          continue;
518                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
519                  error = 0;                  error = 0;
520                  goto out;                  break;
521          }          }
522          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
523                  error = -ENOENT;                  entry->original_name = saved_original_name;
524                  goto out;                  saved_original_name = NULL;
525                    entry->aliased_name = saved_aliased_name;
526                    saved_aliased_name = NULL;
527                    list_add_tail(&entry->list, &ccs_alias_list);
528                    entry = NULL;
529                    error = 0;
530          }          }
531          new_entry = ccs_alloc_element(sizeof(*new_entry));          up_write(&ccs_policy_lock);
532          if (!new_entry)          /***** WRITER SECTION END *****/
533                  goto out;          ccs_put_name(saved_original_name);
534          new_entry->original_name = saved_original_name;          ccs_put_name(saved_aliased_name);
535          new_entry->aliased_name = saved_aliased_name;          kfree(entry);
         list1_add_tail_mb(&new_entry->list, &alias_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
536          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
537          return error;          return error;
538  }  }
539    
540  /**  /**
541   * ccs_read_alias_policy - Read "struct alias_entry" list.   * ccs_read_alias_policy - Read "struct ccs_alias_entry" list.
542   *   *
543   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
544   *   *
# Line 594  static int update_alias_entry(const char Line 546  static int update_alias_entry(const char
546   */   */
547  bool ccs_read_alias_policy(struct ccs_io_buffer *head)  bool ccs_read_alias_policy(struct ccs_io_buffer *head)
548  {  {
549          struct list1_head *pos;          struct list_head *pos;
550          list1_for_each_cookie(pos, head->read_var2, &alias_list) {          bool done = true;
551                  struct alias_entry *ptr;          /***** READER SECTION START *****/
552                  ptr = list1_entry(pos, struct alias_entry, list);          down_read(&ccs_policy_lock);
553            list_for_each_cookie(pos, head->read_var2.u.list, &ccs_alias_list) {
554                    struct ccs_alias_entry *ptr;
555                    ptr = list_entry(pos, struct ccs_alias_entry, list);
556                  if (ptr->is_deleted)                  if (ptr->is_deleted)
557                          continue;                          continue;
558                  if (!ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",                  done = ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",
559                                     ptr->original_name->name,                                       ptr->original_name->name,
560                                     ptr->aliased_name->name))                                       ptr->aliased_name->name);
561                          goto out;                  if (!done)
562                            break;
563          }          }
564          return true;          up_read(&ccs_policy_lock);
565   out:          /***** READER SECTION END *****/
566          return false;          return done;
567  }  }
568    
569  /**  /**
570   * ccs_write_alias_policy - Write "struct alias_entry" list.   * ccs_write_alias_policy - Write "struct ccs_alias_entry" list.
571   *   *
572   * @data:      String to parse.   * @data:      String to parse.
573   * @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 580  int ccs_write_alias_policy(char *data, c
580          if (!cp)          if (!cp)
581                  return -EINVAL;                  return -EINVAL;
582          *cp++ = '\0';          *cp++ = '\0';
583          return update_alias_entry(data, cp, is_delete);          return ccs_update_alias_entry(data, cp, is_delete);
584  }  }
585    
586  /* The list for "struct aggregator_entry". */  /* The list for "struct ccs_aggregator_entry". */
587  static LIST1_HEAD(aggregator_list);  LIST_HEAD(ccs_aggregator_list);
588    
589  /**  /**
590   * update_aggregator_entry - Update "struct aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
591   *   *
592   * @original_name:   The original program's name.   * @original_name:   The original program's name.
593   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 639  static LIST1_HEAD(aggregator_list); Line 595  static LIST1_HEAD(aggregator_list);
595   *   *
596   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
597   */   */
598  static int update_aggregator_entry(const char *original_name,  static int ccs_update_aggregator_entry(const char *original_name,
599                                     const char *aggregated_name,                                         const char *aggregated_name,
600                                     const bool is_delete)                                         const bool is_delete)
601  {  {
602          struct aggregator_entry *new_entry;          struct ccs_aggregator_entry *entry = NULL;
603          struct aggregator_entry *ptr;          struct ccs_aggregator_entry *ptr;
604          static DEFINE_MUTEX(lock);          const struct ccs_path_info *saved_original_name;
605          const struct path_info *saved_original_name;          const struct ccs_path_info *saved_aggregated_name;
606          const struct path_info *saved_aggregated_name;          int error = is_delete ? -ENOENT : -ENOMEM;
         int error = -ENOMEM;  
607          if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) ||          if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) ||
608              !ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__))              !ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__))
609                  return -EINVAL;                  return -EINVAL;
610          saved_original_name = ccs_save_name(original_name);          saved_original_name = ccs_get_name(original_name);
611          saved_aggregated_name = ccs_save_name(aggregated_name);          saved_aggregated_name = ccs_get_name(aggregated_name);
612          if (!saved_original_name || !saved_aggregated_name)          if (!saved_original_name || !saved_aggregated_name) {
613                    ccs_put_name(saved_original_name);
614                    ccs_put_name(saved_aggregated_name);
615                  return -ENOMEM;                  return -ENOMEM;
616          mutex_lock(&lock);          }
617          list1_for_each_entry(ptr, &aggregator_list, list) {          if (!is_delete)
618                    entry = kzalloc(sizeof(*entry), GFP_KERNEL);
619            /***** WRITER SECTION START *****/
620            down_write(&ccs_policy_lock);
621            list_for_each_entry(ptr, &ccs_aggregator_list, list) {
622                  if (ptr->original_name != saved_original_name ||                  if (ptr->original_name != saved_original_name ||
623                      ptr->aggregated_name != saved_aggregated_name)                      ptr->aggregated_name != saved_aggregated_name)
624                          continue;                          continue;
625                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
626                  error = 0;                  error = 0;
627                  goto out;                  break;
628          }          }
629          if (is_delete) {          if (!is_delete && error && ccs_memory_ok(entry)) {
630                  error = -ENOENT;                  entry->original_name = saved_original_name;
631                  goto out;                  saved_original_name = NULL;
632                    entry->aggregated_name = saved_aggregated_name;
633                    saved_aggregated_name = NULL;
634                    list_add_tail(&entry->list, &ccs_aggregator_list);
635                    entry = NULL;
636                    error = 0;
637          }          }
638          new_entry = ccs_alloc_element(sizeof(*new_entry));          up_write(&ccs_policy_lock);
639          if (!new_entry)          /***** WRITER SECTION END *****/
640                  goto out;          ccs_put_name(saved_original_name);
641          new_entry->original_name = saved_original_name;          ccs_put_name(saved_aggregated_name);
642          new_entry->aggregated_name = saved_aggregated_name;          kfree(entry);
         list1_add_tail_mb(&new_entry->list, &aggregator_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
643          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
644          return error;          return error;
645  }  }
646    
647  /**  /**
648   * ccs_read_aggregator_policy - Read "struct aggregator_entry" list.   * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.
649   *   *
650   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
651   *   *
# Line 691  static int update_aggregator_entry(const Line 653  static int update_aggregator_entry(const
653   */   */
654  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
655  {  {
656          struct list1_head *pos;          struct list_head *pos;
657          list1_for_each_cookie(pos, head->read_var2, &aggregator_list) {          bool done = true;
658                  struct aggregator_entry *ptr;          /***** READER SECTION START *****/
659                  ptr = list1_entry(pos, struct aggregator_entry, list);          down_read(&ccs_policy_lock);
660            list_for_each_cookie(pos, head->read_var2.u.list,
661                                  &ccs_aggregator_list) {
662                    struct ccs_aggregator_entry *ptr;
663                    ptr = list_entry(pos, struct ccs_aggregator_entry, list);
664                  if (ptr->is_deleted)                  if (ptr->is_deleted)
665                          continue;                          continue;
666                  if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",
667                                     ptr->original_name->name,                                       ptr->original_name->name,
668                                     ptr->aggregated_name->name))                                       ptr->aggregated_name->name);
669                          goto out;                  if (!done)
670                            break;
671          }          }
672          return true;          up_read(&ccs_policy_lock);
673   out:          /***** READER SECTION END *****/
674          return false;          return done;
675  }  }
676    
677  /**  /**
678   * ccs_write_aggregator_policy - Write "struct aggregator_entry" list.   * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.
679   *   *
680   * @data:      String to parse.   * @data:      String to parse.
681   * @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 688  int ccs_write_aggregator_policy(char *da
688          if (!cp)          if (!cp)
689                  return -EINVAL;                  return -EINVAL;
690          *cp++ = '\0';          *cp++ = '\0';
691          return update_aggregator_entry(data, cp, is_delete);          return ccs_update_aggregator_entry(data, cp, is_delete);
692  }  }
693    
694  /* Domain create/delete/undelete handler. */  /* Domain create/delete handler. */
   
 /* #define DEBUG_DOMAIN_UNDELETE */  
695    
696  /**  /**
697   * ccs_delete_domain - Delete a domain.   * ccs_delete_domain - Delete a domain.
# Line 737  int ccs_write_aggregator_policy(char *da Line 702  int ccs_write_aggregator_policy(char *da
702   */   */
703  int ccs_delete_domain(char *domainname)  int ccs_delete_domain(char *domainname)
704  {  {
705          struct domain_info *domain;          struct ccs_domain_info *domain;
706          struct path_info name;          struct ccs_path_info name;
707          name.name = domainname;          name.name = domainname;
708          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
709          mutex_lock(&new_domain_assign_lock);          /***** WRITER SECTION START *****/
710  #ifdef DEBUG_DOMAIN_UNDELETE          down_write(&ccs_policy_lock);
         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  
711          /* Is there an active domain? */          /* Is there an active domain? */
712          list1_for_each_entry(domain, &domain_list, list) {          list_for_each_entry(domain, &ccs_domain_list, list) {
713                  struct domain_info *domain2;                  /* Never delete ccs_kernel_domain */
714                  /* Never delete KERNEL_DOMAIN */                  if (domain == &ccs_kernel_domain)
                 if (domain == &KERNEL_DOMAIN)  
715                          continue;                          continue;
716                  if (domain->is_deleted ||                  if (domain->is_deleted ||
717                      ccs_pathcmp(domain->domainname, &name))                      ccs_pathcmp(domain->domainname, &name))
718                          continue;                          continue;
719                  /* 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  
720                  break;                  break;
721          }          }
722          mutex_unlock(&new_domain_assign_lock);          up_write(&ccs_policy_lock);
723            /***** WRITER SECTION END *****/
724          return 0;          return 0;
725  }  }
726    
727  /**  /**
  * 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;  
 }  
   
 /**  
728   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_find_or_assign_new_domain - Create a domain.
729   *   *
730   * @domainname: The name of domain.   * @domainname: The name of domain.
731   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
732     * @cookie:     Pointer to "struct ccs_cookie".
733   *   *
734   * Returns pointer to "struct domain_info" on success, NULL otherwise.   * Returns true on success, false otherwise.
735   */   */
736  struct domain_info *ccs_find_or_assign_new_domain(const char *domainname,  bool ccs_find_or_assign_new_domain(const char *domainname, const u8 profile,
737                                                    const u8 profile)                                     struct ccs_cookie *cookie)
738  {  {
739          struct domain_info *domain = NULL;          struct ccs_domain_info *entry;
740          const struct path_info *saved_domainname;          struct ccs_domain_info *domain;
741          mutex_lock(&new_domain_assign_lock);          const struct ccs_path_info *saved_domainname;
742          domain = ccs_find_domain(domainname);          cookie->u.domain = NULL;
         if (domain)  
                 goto out;  
743          if (!ccs_is_correct_domain(domainname, __func__))          if (!ccs_is_correct_domain(domainname, __func__))
744                  goto out;                  return false;
745          saved_domainname = ccs_save_name(domainname);          saved_domainname = ccs_get_name(domainname);
746          if (!saved_domainname)          if (!saved_domainname)
747                  goto out;                  return false;
748          /* Can I reuse memory of deleted domain? */          entry = kzalloc(sizeof(*entry), GFP_KERNEL);
749          list1_for_each_entry(domain, &domain_list, list) {          /***** WRITER SECTION START *****/
750                  struct task_struct *p;          down_write(&ccs_policy_lock);
751                  struct acl_info *ptr;          list_for_each_entry(domain, &ccs_domain_list, list) {
752                  bool flag;                  if (domain->is_deleted ||
753                  if (!domain->is_deleted ||                      ccs_pathcmp(saved_domainname, domain->domainname))
754                      domain->domainname != saved_domainname)                          continue;
755                          continue;                  cookie->u.domain = domain;
756                  flag = false;                  break;
                 /***** 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);  
757          }          }
758   out:          if (!cookie->u.domain && ccs_memory_ok(entry)) {
759          mutex_unlock(&new_domain_assign_lock);                  INIT_LIST_HEAD(&entry->acl_info_list);
760          return domain;                  entry->domainname = saved_domainname;
761                    saved_domainname = NULL;
762                    entry->profile = profile;
763                    list_add_tail(&entry->list, &ccs_domain_list);
764                    cookie->u.domain = entry;
765                    entry = NULL;
766            }
767            up_write(&ccs_policy_lock);
768            /***** WRITER SECTION END *****/
769            ccs_put_name(saved_domainname);
770            kfree(entry);
771            return cookie->u.domain != NULL;
772  }  }
773    
774  /**  /**
775   * get_argv0 - Get argv[0].   * ccs_get_argv0 - Get argv[0].
776   *   *
777   * @bprm: Pointer to "struct linux_binprm".   * @ee: Pointer to "struct ccs_execve_entry".
  * @tmp:  Buffer for temporal use.  
778   *   *
779   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
780   */   */
781  static bool get_argv0(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)  static bool ccs_get_argv0(struct ccs_execve_entry *ee)
782  {  {
783          char *arg_ptr = tmp->buffer;          struct linux_binprm *bprm = ee->bprm;
784            char *arg_ptr = ee->tmp;
785          int arg_len = 0;          int arg_len = 0;
786          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
787          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
788          bool done = false;          bool done = false;
789          if (!bprm->argc)          if (!bprm->argc)
790                  goto out;                  goto out;
791          while (1) {          while (1) {
792                  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)  
793                          goto out;                          goto out;
794                  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;  
                 }  
795                  /* Read. */                  /* Read. */
796                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
797                            const char *kaddr = ee->dump.data;
798                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
799                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
800                                  if (c == '\\') {                                  if (c == '\\') {
# Line 967  static bool get_argv0(struct linux_binpr Line 817  static bool get_argv0(struct linux_binpr
817                                  break;                                  break;
818                          }                          }
819                  }                  }
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
820                  offset = 0;                  offset = 0;
821                  if (done)                  if (done)
822                          break;                          break;
# Line 983  static bool get_argv0(struct linux_binpr Line 827  static bool get_argv0(struct linux_binpr
827  }  }
828    
829  /**  /**
830   * find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
831   *   *
832   * @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.  
833   *   *
834   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
835   */   */
836  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)  
837  {  {
838          /*          struct ccs_request_info *r = &ee->r;
839           * This function assumes that the size of buffer returned by          const struct ccs_path_info *handler = ee->handler;
840           * ccs_realpath() = CCS_MAX_PATHNAME_LEN.          const char *old_domain_name = r->cookie.u.domain->domainname->name;
841           */          struct linux_binprm *bprm = ee->bprm;
842          struct domain_info *old_domain = current->domain_info;          const u8 mode = r->mode;
         struct domain_info *domain = NULL;  
         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);  
843          const bool is_enforce = (mode == 3);          const bool is_enforce = (mode == 3);
844            const u32 ccs_flags = current->ccs_flags;
845            char *new_domain_name = NULL;
846            struct ccs_path_info rn; /* real name */
847            struct ccs_path_info sn; /* symlink name */
848            struct ccs_path_info ln; /* last name */
849          int retval;          int retval;
850          struct path_info r; /* real name */          bool found = false;
         struct path_info s; /* symlink name */  
         struct path_info l; /* last name */  
         const u32 tomoyo_flags = current->tomoyo_flags;  
   
         {  
                 /*  
                  * 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;  
                 }  
         }  
   
851   retry:   retry:
852          current->tomoyo_flags = tomoyo_flags;          current->ccs_flags = ccs_flags;
853          /* Get ccs_realpath of program. */          r->condition_cookie.u.cond = NULL;
854          retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */          /* Get realpath of program and symbolic link. */
855          ccs_free(real_program_name);          retval = ccs_realpath_both(bprm->filename, ee);
856          real_program_name = ccs_realpath(original_name);          if (retval < 0)
         if (!real_program_name)  
                 goto out;  
         /* Get ccs_realpath of symbolic link. */  
         ccs_free(symlink_program_name);  
         symlink_program_name = ccs_realpath_nofollow(original_name);  
         if (!symlink_program_name)  
857                  goto out;                  goto out;
858    
859          r.name = real_program_name;          rn.name = ee->program_path;
860          ccs_fill_path_info(&r);          ccs_fill_path_info(&rn);
861          s.name = symlink_program_name;          sn.name = ee->tmp;
862          ccs_fill_path_info(&s);          ccs_fill_path_info(&sn);
863          l.name = ccs_get_last_name(old_domain);          ln.name = ccs_get_last_name(r->cookie.u.domain);
864          ccs_fill_path_info(&l);          ccs_fill_path_info(&ln);
865    
866          if (path_to_verify) {          if (handler) {
867                  if (ccs_pathcmp(&r, path_to_verify)) {                  if (ccs_pathcmp(&rn, handler)) {
868                          /* Failed to verify execute handler. */                          /* Failed to verify execute handler. */
869                          static u8 counter = 20;                          static u8 counter = 20;
870                          if (counter) {                          if (counter) {
871                                  counter--;                                  counter--;
872                                  printk(KERN_WARNING "Failed to verify: %s\n",                                  printk(KERN_WARNING "Failed to verify: %s\n",
873                                         path_to_verify->name);                                         handler->name);
874                          }                          }
875                          goto out;                          goto out;
876                  }                  }
# Line 1067  static int find_next_domain(struct linux Line 878  static int find_next_domain(struct linux
878          }          }
879    
880          /* Check 'alias' directive. */          /* Check 'alias' directive. */
881          if (ccs_pathcmp(&r, &s)) {          if (ccs_pathcmp(&rn, &sn)) {
882                  struct alias_entry *ptr;                  struct ccs_alias_entry *ptr;
883                  /* Is this program allowed to be called via symbolic links? */                  /* Is this program allowed to be called via symbolic links? */
884                  list1_for_each_entry(ptr, &alias_list, list) {                  /***** READER SECTION START *****/
885                    down_read(&ccs_policy_lock);
886                    list_for_each_entry(ptr, &ccs_alias_list, list) {
887                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
888                              ccs_pathcmp(&r, ptr->original_name) ||                              ccs_pathcmp(&rn, ptr->original_name) ||
889                              ccs_pathcmp(&s, ptr->aliased_name))                              ccs_pathcmp(&sn, ptr->aliased_name))
890                                  continue;                                  continue;
891                          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,  
892                                  CCS_MAX_PATHNAME_LEN - 1);                                  CCS_MAX_PATHNAME_LEN - 1);
893                          ccs_fill_path_info(&r);                          ccs_fill_path_info(&rn);
894                          break;                          break;
895                  }                  }
896                    up_read(&ccs_policy_lock);
897                    /***** READER SECTION END *****/
898          }          }
899            /* sn will be overwritten after here. */
900    
901          /* Compare basename of real_program_name and argv[0] */          /* Compare basename of program_path and argv[0] */
902          if (bprm->argc > 0 && ccs_check_flags(CCS_TOMOYO_MAC_FOR_ARGV0)) {          r->mode = ccs_check_flags(r->cookie.u.domain, CCS_MAC_FOR_ARGV0);
903                  char *base_argv0 = tmp->buffer;          if (bprm->argc > 0 && r->mode) {
904                    char *base_argv0 = ee->tmp;
905                  const char *base_filename;                  const char *base_filename;
906                  retval = -ENOMEM;                  retval = -ENOMEM;
907                  if (!get_argv0(bprm, tmp))                  if (!ccs_get_argv0(ee))
908                          goto out;                          goto out;
909                  base_filename = strrchr(real_program_name, '/');                  base_filename = strrchr(ee->program_path, '/');
910                  if (!base_filename)                  if (!base_filename)
911                          base_filename = real_program_name;                          base_filename = ee->program_path;
912                  else                  else
913                          base_filename++;                          base_filename++;
914                  if (strcmp(base_argv0, base_filename)) {                  if (strcmp(base_argv0, base_filename)) {
915                          retval = ccs_check_argv0_perm(&r, base_argv0);                          retval = ccs_check_argv0_perm(r, &rn, base_argv0);
916                          if (retval == 1)                          if (retval == 1)
917                                  goto retry;                                  goto retry;
918                          if (retval < 0)                          if (retval < 0)
# Line 1106  static int find_next_domain(struct linux Line 922  static int find_next_domain(struct linux
922    
923          /* Check 'aggregator' directive. */          /* Check 'aggregator' directive. */
924          {          {
925                  struct aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
926                  /* Is this program allowed to be aggregated? */                  /* Is this program allowed to be aggregated? */
927                  list1_for_each_entry(ptr, &aggregator_list, list) {                  /***** READER SECTION START *****/
928                    down_read(&ccs_policy_lock);
929                    list_for_each_entry(ptr, &ccs_aggregator_list, list) {
930                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
931                              !ccs_path_matches_pattern(&r, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
932                                  continue;                                  continue;
933                          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,  
934                                  CCS_MAX_PATHNAME_LEN - 1);                                  CCS_MAX_PATHNAME_LEN - 1);
935                          ccs_fill_path_info(&r);                          ccs_fill_path_info(&rn);
936                          break;                          break;
937                  }                  }
938                    up_read(&ccs_policy_lock);
939                    /***** READER SECTION END *****/
940          }          }
941    
942          /* Check execute permission. */          /* Check execute permission. */
943          retval = ccs_check_exec_perm(&r, bprm, tmp);          r->mode = mode;
944            retval = ccs_check_exec_perm(r, &rn);
945          if (retval == 1)          if (retval == 1)
946                  goto retry;                  goto retry;
947          if (retval < 0)          if (retval < 0)
948                  goto out;                  goto out;
949    
950   calculate_domain:   calculate_domain:
951          new_domain_name = tmp->buffer;          new_domain_name = ee->tmp;
952          if (is_domain_initializer(old_domain->domainname, &r, &l)) {          if (ccs_is_domain_initializer(r->cookie.u.domain->domainname, &rn,
953                  /* Transit to the child of KERNEL_DOMAIN domain. */                                        &ln)) {
954                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  /* Transit to the child of ccs_kernel_domain domain. */
955                           ROOT_NAME " " "%s", real_program_name);                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
956          } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {                           ROOT_NAME " " "%s", ee->program_path);
957            } else if (r->cookie.u.domain == &ccs_kernel_domain &&
958                       !ccs_policy_loaded) {
959                  /*                  /*
960                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
961                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
962                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
963                   */                   */
964                  domain = old_domain;                  found = true;
965          } else if (is_domain_keeper(old_domain->domainname, &r, &l)) {          } else if (ccs_is_domain_keeper(r->cookie.u.domain->domainname, &rn, &ln)) {
966                  /* Keep current domain. */                  /* Keep current domain. */
967                  domain = old_domain;                  found = true;
968          } else {          } else {
969                  /* Normal domain transition. */                  /* Normal domain transition. */
970                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
971                           "%s %s", old_domain_name, real_program_name);                           "%s %s", old_domain_name, ee->program_path);
972          }          }
973          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (found || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
974                  goto done;                  goto done;
975          domain = ccs_find_domain(new_domain_name);          found = ccs_find_domain(new_domain_name, &r->cookie);
976          if (domain)          if (found)
977                  goto done;                  goto done;
978          if (is_enforce) {          if (is_enforce) {
979                  int error = ccs_check_supervisor(NULL,                  int error = ccs_check_supervisor(r,
980                                                   "# wants to create domain\n"                                                   "# wants to create domain\n"
981                                                   "%s\n", new_domain_name);                                                   "%s\n", new_domain_name);
982                  if (error == 1)                  if (error == 1)
# Line 1162  static int find_next_domain(struct linux Line 984  static int find_next_domain(struct linux
984                  if (error < 0)                  if (error < 0)
985                          goto done;                          goto done;
986          }          }
987          domain = ccs_find_or_assign_new_domain(new_domain_name,          found = ccs_find_or_assign_new_domain(new_domain_name, r->profile,
988                                                 old_domain->profile);                                                &r->cookie);
989          if (domain)          if (found)
990                  audit_domain_creation_log(new_domain_name, mode,                  ccs_audit_domain_creation_log(r->cookie.u.domain);
                                           domain->profile);  
991   done:   done:
992          if (!domain) {          if (found) {
993                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  retval = 0;
994                         new_domain_name);                  goto out;
995                  if (is_enforce)          }
996                          retval = -EPERM;          printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
997                  else {                 new_domain_name);
998                          retval = 0;          if (is_enforce)
999                          ccs_set_domain_flag(old_domain, false,                  retval = -EPERM;
1000                                              DOMAIN_FLAGS_TRANSITION_FAILED);          else {
                 }  
         } else {  
1001                  retval = 0;                  retval = 0;
1002                    r->cookie.u.domain->domain_transition_failed = true;
1003          }          }
1004   out:   out:
         ccs_free(real_program_name);  
         ccs_free(symlink_program_name);  
         *next_domain = domain ? domain : old_domain;  
1005          return retval;          return retval;
1006  }  }
1007    
1008  /**  /**
1009   * check_environ - Check permission for environment variable names.   * ccs_check_environ - Check permission for environment variable names.
1010   *   *
1011   * @bprm: Pointer to "struct linux_binprm".   * @ee: Pointer to "struct ccs_execve_entry".
  * @tmp:  Buffer for temporal use.  
1012   *   *
1013   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1014   */   */
1015  static int check_environ(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)  static int ccs_check_environ(struct ccs_execve_entry *ee)
1016  {  {
1017          const u8 profile = current->domain_info->profile;          struct ccs_request_info *r = &ee->r;
1018          const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_ENV);          struct linux_binprm *bprm = ee->bprm;
1019          char *arg_ptr = tmp->buffer;          char *arg_ptr = ee->tmp;
1020          int arg_len = 0;          int arg_len = 0;
1021          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
1022          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
1023          int argv_count = bprm->argc;          int argv_count = bprm->argc;
1024          int envp_count = bprm->envc;          int envp_count = bprm->envc;
1025          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1026          int error = -ENOMEM;          int error = -ENOMEM;
1027          if (!mode || !envp_count)          if (!r->mode || !envp_count)
1028                  return 0;                  return 0;
1029          while (error == -ENOMEM) {          while (error == -ENOMEM) {
1030                  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)  
1031                          goto out;                          goto out;
1032                  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;  
                 }  
1033                  /* Read. */                  /* Read. */
1034                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
1035                            const char *kaddr = ee->dump.data;
1036                          if (!kaddr[offset++])                          if (!kaddr[offset++])
1037                                  argv_count--;                                  argv_count--;
1038                  }                  }
1039                  if (argv_count)                  if (argv_count) {
1040                          goto unmap_page;                          offset = 0;
1041                            continue;
1042                    }
1043                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
1044                            const char *kaddr = ee->dump.data;
1045                          const unsigned char c = kaddr[offset++];                          const unsigned char c = kaddr[offset++];
1046                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1047                                  if (c == '=') {                                  if (c == '=') {
# Line 1259  static int check_environ(struct linux_bi Line 1063  static int check_environ(struct linux_bi
1063                          }                          }
1064                          if (c)                          if (c)
1065                                  continue;                                  continue;
1066                          if (ccs_check_env_perm(arg_ptr, profile, mode)) {                          if (ccs_check_env_perm(r, arg_ptr)) {
1067                                  error = -EPERM;                                  error = -EPERM;
1068                                  break;                                  break;
1069                          }                          }
# Line 1269  static int check_environ(struct linux_bi Line 1073  static int check_environ(struct linux_bi
1073                          }                          }
1074                          arg_len = 0;                          arg_len = 0;
1075                  }                  }
  unmap_page:  
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
1076                  offset = 0;                  offset = 0;
1077          }          }
1078   out:   out:
1079          if (error && mode != 3)          if (r->mode != 3)
1080                  error = 0;                  error = 0;
1081          return error;          return error;
1082  }  }
1083    
1084  /**  /**
1085   * unescape - Unescape escaped string.   * ccs_unescape - Unescape escaped string.
1086   *   *
1087   * @dest: String to unescape.   * @dest: String to unescape.
1088   *   *
1089   * Returns nothing.   * Returns nothing.
1090   */   */
1091  static void unescape(unsigned char *dest)  static void ccs_unescape(unsigned char *dest)
1092  {  {
1093          unsigned char *src = dest;          unsigned char *src = dest;
1094          unsigned char c;          unsigned char c;
1095          unsigned char d;          unsigned char d;
1096          unsigned char e;          unsigned char e;
1097          while ((c = *src++) != '\0') {          while (1) {
1098                    c = *src++;
1099                    if (!c)
1100                            break;
1101                  if (c != '\\') {                  if (c != '\\') {
1102                          *dest++ = c;                          *dest++ = c;
1103                          continue;                          continue;
# Line 1321  static void unescape(unsigned char *dest Line 1121  static void unescape(unsigned char *dest
1121  }  }
1122    
1123  /**  /**
1124   * root_depth - Get number of directories to strip.   * ccs_root_depth - Get number of directories to strip.
1125   *   *
1126   * @dentry: Pointer to "struct dentry".   * @dentry: Pointer to "struct dentry".
1127   * @vfsmnt: Pointer to "struct vfsmount".   * @vfsmnt: Pointer to "struct vfsmount".
1128   *   *
1129   * Returns number of directories to strip.   * Returns number of directories to strip.
1130   */   */
1131  static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1132  {  {
1133          int depth = 0;          int depth = 0;
1134          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
# Line 1351  static inline int root_depth(struct dent Line 1151  static inline int root_depth(struct dent
1151  }  }
1152    
1153  /**  /**
1154   * get_root_depth - return the depth of root directory.   * ccs_get_root_depth - return the depth of root directory.
1155   *   *
1156   * Returns number of directories to strip.   * Returns number of directories to strip.
1157   */   */
1158  static int get_root_depth(void)  static int ccs_get_root_depth(void)
1159  {  {
1160          int depth;          int depth;
1161          struct dentry *dentry;          struct dentry *dentry;
# Line 1376  static int get_root_depth(void) Line 1176  static int get_root_depth(void)
1176  #endif  #endif
1177          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
1178          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
1179          depth = root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
1180  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1181          path_put(&root);          path_put(&root);
1182  #else  #else
# Line 1386  static int get_root_depth(void) Line 1186  static int get_root_depth(void)
1186          return depth;          return depth;
1187  }  }
1188    
1189    static LIST_HEAD(ccs_execve_list);
1190    static DEFINE_SPINLOCK(ccs_execve_list_lock);
1191    
1192  /**  /**
1193   * try_alt_exec - Try to start execute handler.   * ccs_allocate_execve_entry - Allocate memory for execve().
1194   *   *
1195   * @bprm:        Pointer to "struct linux_binprm".   * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1196   * @handler:     Pointer to the name of execute handler.   */
1197   * @eh_path:     Pointer to pointer to the name of execute handler.  static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1198   * @next_domain: Pointer to pointer to "struct domain_info".  {
1199   * @tmp:         Buffer for temporal use.          struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);
1200            if (!ee)
1201                    return NULL;
1202            memset(ee, 0, sizeof(*ee));
1203            ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1204            ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1205            if (!ee->program_path || !ee->tmp) {
1206                    ccs_free(ee->program_path);
1207                    ccs_free(ee->tmp);
1208                    ccs_free(ee);
1209                    return NULL;
1210            }
1211            /* ee->dump->data is allocated by ccs_dump_page(). */
1212            ee->task = current;
1213            /***** CRITICAL SECTION START *****/
1214            spin_lock(&ccs_execve_list_lock);
1215            list_add(&ee->list, &ccs_execve_list);
1216            spin_unlock(&ccs_execve_list_lock);
1217            /***** CRITICAL SECTION END *****/
1218            return ee;
1219    }
1220    
1221    /**
1222     * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1223     *
1224     * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1225     */
1226    static struct ccs_execve_entry *ccs_find_execve_entry(void)
1227    {
1228            struct task_struct *task = current;
1229            struct ccs_execve_entry *ee = NULL;
1230            struct ccs_execve_entry *p;
1231            /***** CRITICAL SECTION START *****/
1232            spin_lock(&ccs_execve_list_lock);
1233            list_for_each_entry(p, &ccs_execve_list, list) {
1234                    if (p->task != task)
1235                            continue;
1236                    ee = p;
1237                    break;
1238            }
1239            spin_unlock(&ccs_execve_list_lock);
1240            /***** CRITICAL SECTION END *****/
1241            return ee;
1242    }
1243    
1244    /**
1245     * ccs_free_execve_entry - Free memory for execve().
1246     *
1247     * @ee: Pointer to "struct ccs_execve_entry".
1248     */
1249    static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1250    {
1251            if (!ee)
1252                    return;
1253            /***** CRITICAL SECTION START *****/
1254            spin_lock(&ccs_execve_list_lock);
1255            list_del(&ee->list);
1256            spin_unlock(&ccs_execve_list_lock);
1257            /***** CRITICAL SECTION END *****/
1258            ccs_free(ee->program_path);
1259            ccs_free(ee->tmp);
1260            kfree(ee->dump.data);
1261            ccs_free(ee);
1262    }
1263    
1264    /**
1265     * ccs_try_alt_exec - Try to start execute handler.
1266     *
1267     * @ee: Pointer to "struct ccs_execve_entry".
1268   *   *
1269   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1270   */   */
1271  static int try_alt_exec(struct linux_binprm *bprm,  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
                         const struct path_info *handler, char **eh_path,  
                         struct domain_info **next_domain,  
                         struct ccs_page_buffer *tmp)  
1272  {  {
1273          /*          /*
1274           * Contents of modified bprm.           * Contents of modified bprm.
# Line 1416  static int try_alt_exec(struct linux_bin Line 1284  static int try_alt_exec(struct linux_bin
1284           * modified bprm->argv[0]           * modified bprm->argv[0]
1285           *    = the program's name specified by execute_handler           *    = the program's name specified by execute_handler
1286           * modified bprm->argv[1]           * modified bprm->argv[1]
1287           *    = current->domain_info->domainname->name           *    = ccs_current_domain()->domainname->name
1288           * modified bprm->argv[2]           * modified bprm->argv[2]
1289           *    = the current process's name           *    = the current process's name
1290           * modified bprm->argv[3]           * modified bprm->argv[3]
# Line 1438  static int try_alt_exec(struct linux_bin Line 1306  static int try_alt_exec(struct linux_bin
1306           * modified bprm->argv[bprm->envc + bprm->argc + 6]           * modified bprm->argv[bprm->envc + bprm->argc + 6]
1307           *     = original bprm->envp[bprm->envc - 1]           *     = original bprm->envp[bprm->envc - 1]
1308           */           */
1309            struct linux_binprm *bprm = ee->bprm;
1310          struct file *filp;          struct file *filp;
1311          int retval;          int retval;
1312          const int original_argc = bprm->argc;          const int original_argc = bprm->argc;
1313          const int original_envc = bprm->envc;          const int original_envc = bprm->envc;
1314          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));  
         *eh_path = execute_handler;  
         if (!execute_handler)  
                 return -ENOMEM;  
         strncpy(execute_handler, handler->name,  
                 sizeof(struct ccs_page_buffer) - 1);  
         unescape(execute_handler);  
1315    
1316          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
1317          allow_write_access(bprm->file);          allow_write_access(bprm->file);
1318          fput(bprm->file);          fput(bprm->file);
1319          bprm->file = NULL;          bprm->file = NULL;
1320    
1321          { /* Adjust root directory for open_exec(). */          /* Invalidate page dump cache. */
1322                  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);  
         }  
1323    
1324          /* Move envp[] to argv[] */          /* Move envp[] to argv[] */
1325          bprm->argc += bprm->envc;          bprm->argc += bprm->envc;
# Line 1478  static int try_alt_exec(struct linux_bin Line 1327  static int try_alt_exec(struct linux_bin
1327    
1328          /* Set argv[6] */          /* Set argv[6] */
1329          {          {
1330                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
1331                           original_envc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1332                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1333                  if (retval < 0)                  if (retval < 0)
1334                          goto out;                          goto out;
1335                  bprm->argc++;                  bprm->argc++;
# Line 1488  static int try_alt_exec(struct linux_bin Line 1337  static int try_alt_exec(struct linux_bin
1337    
1338          /* Set argv[5] */          /* Set argv[5] */
1339          {          {
1340                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
1341                           original_argc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1342                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1343                  if (retval < 0)                  if (retval < 0)
1344                          goto out;                          goto out;
1345                  bprm->argc++;                  bprm->argc++;
# Line 1506  static int try_alt_exec(struct linux_bin Line 1355  static int try_alt_exec(struct linux_bin
1355    
1356          /* Set argv[3] */          /* Set argv[3] */
1357          {          {
1358                  const u32 tomoyo_flags = task->tomoyo_flags;                  char *cp = ee->tmp;
1359                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                  const u32 ccs_flags = task->ccs_flags;
1360                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1361                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1362                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1363                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
1364                           task->pid, task->uid, task->gid, task->euid,                           (pid_t) sys_getpid(), current_uid(), current_gid(),
1365                           task->egid, task->suid, task->sgid, task->fsuid,                           current_euid(), current_egid(), current_suid(),
1366                           task->fsgid, (u8) (tomoyo_flags >> 24),                           current_sgid(), current_fsuid(), current_fsgid(),
1367                           (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1368                  retval = copy_strings_kernel(1, &buffer, bprm);                           (u8) (ccs_flags >> 8));
1369                    retval = copy_strings_kernel(1, &cp, bprm);
1370                  if (retval < 0)                  if (retval < 0)
1371                          goto out;                          goto out;
1372                  bprm->argc++;                  bprm->argc++;
# Line 1528  static int try_alt_exec(struct linux_bin Line 1379  static int try_alt_exec(struct linux_bin
1379                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1380                          ccs_free(exe);                          ccs_free(exe);
1381                  } else {                  } else {
1382                          snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                          exe = ee->tmp;
1383                                   "<unknown>");                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
1384                          retval = copy_strings_kernel(1, &buffer, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
1385                  }                  }
1386                  if (retval < 0)                  if (retval < 0)
1387                          goto out;                          goto out;
# Line 1539  static int try_alt_exec(struct linux_bin Line 1390  static int try_alt_exec(struct linux_bin
1390    
1391          /* Set argv[1] */          /* Set argv[1] */
1392          {          {
1393                  strncpy(buffer, task->domain_info->domainname->name,                  char *cp = ee->tmp;
1394                          sizeof(struct ccs_page_buffer) - 1);                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,
1395                  retval = copy_strings_kernel(1, &buffer, bprm);                          CCS_EXEC_TMPSIZE - 1);
1396                    retval = copy_strings_kernel(1, &cp, bprm);
1397                  if (retval < 0)                  if (retval < 0)
1398                          goto out;                          goto out;
1399                  bprm->argc++;                  bprm->argc++;
# Line 1549  static int try_alt_exec(struct linux_bin Line 1401  static int try_alt_exec(struct linux_bin
1401    
1402          /* Set argv[0] */          /* Set argv[0] */
1403          {          {
1404                  retval = copy_strings_kernel(1, &execute_handler, bprm);                  int depth = ccs_get_root_depth();
1405                    char *cp = ee->program_path;
1406                    strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);
1407                    ccs_unescape(cp);
1408                    retval = -ENOENT;
1409                    if (!*cp || *cp != '/')
1410                            goto out;
1411                    /* Adjust root directory for open_exec(). */
1412                    while (depth) {
1413                            cp = strchr(cp + 1, '/');
1414                            if (!cp)
1415                                    goto out;
1416                            depth--;
1417                    }
1418                    memmove(ee->program_path, cp, strlen(cp) + 1);
1419                    cp = ee->program_path;
1420                    retval = copy_strings_kernel(1, &cp, bprm);
1421                  if (retval < 0)                  if (retval < 0)
1422                          goto out;                          goto out;
1423                  bprm->argc++;                  bprm->argc++;
# Line 1561  static int try_alt_exec(struct linux_bin Line 1429  static int try_alt_exec(struct linux_bin
1429  #endif  #endif
1430    
1431          /* OK, now restart the process with execute handler program's dentry. */          /* OK, now restart the process with execute handler program's dentry. */
1432          filp = open_exec(execute_handler);          filp = open_exec(ee->program_path);
1433          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1434                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1435                  goto out;                  goto out;
1436          }          }
1437          bprm->file = filp;          bprm->file = filp;
1438          bprm->filename = execute_handler;          bprm->filename = ee->program_path;
1439  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1440          bprm->interp = execute_handler;          bprm->interp = bprm->filename;
1441  #endif  #endif
1442          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1443          if (retval < 0)          if (retval < 0)
1444                  goto out;                  goto out;
1445          task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          {
1446          retval = find_next_domain(bprm, next_domain, handler, tmp);                  /*
1447          task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;                   * Backup ee->program_path because ccs_find_next_domain() will
1448                     * overwrite ee->program_path and ee->tmp.
1449                     */
1450                    const int len = strlen(ee->program_path) + 1;
1451                    char *cp = kmalloc(len, GFP_KERNEL);
1452                    if (!cp) {
1453                            retval = -ENOMEM;
1454                            goto out;
1455                    }
1456                    memmove(cp, ee->program_path, len);
1457                    bprm->filename = cp;
1458    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1459                    bprm->interp = bprm->filename;
1460    #endif
1461                    task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1462                    retval = ccs_find_next_domain(ee);
1463                    task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1464                    /* Restore ee->program_path for search_binary_handler(). */
1465                    memmove(ee->program_path, cp, len);
1466                    bprm->filename = ee->program_path;
1467    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1468                    bprm->interp = bprm->filename;
1469    #endif
1470                    kfree(cp);
1471            }
1472   out:   out:
1473          return retval;          return retval;
1474  }  }
1475    
1476  /**  /**
1477   * find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1478   *   *
1479     * @ee:   Pointer to "struct ccs_execve_entry".
1480   * @type: Type of execute handler.   * @type: Type of execute handler.
1481   *   *
1482   * Returns pointer to "struct path_info" if found, NULL otherwise.   * Returns true if found, false otherwise.
1483   */   */
1484  static const struct path_info *find_execute_handler(const u8 type)  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1485                                         const u8 type)
1486  {  {
1487          struct task_struct *task = current;          struct task_struct *task = current;
1488          const struct domain_info *domain = task->domain_info;          const struct ccs_domain_info *domain = ccs_current_domain();
1489          struct acl_info *ptr;          struct ccs_acl_info *ptr;
1490            bool found = false;
1491          /*          /*
1492           * Don't use execute handler if the current process is           * Don't use execute handler if the current process is
1493           * marked as execute handler to avoid infinite execute handler loop.           * marked as execute handler to avoid infinite execute handler loop.
1494           */           */
1495          if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1496                  return NULL;                  return false;
1497          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          /***** READER SECTION START *****/
1498                  struct execute_handler_record *acl;          down_read(&ccs_policy_lock);
1499            list_for_each_entry(ptr, &domain->acl_info_list, list) {
1500                    struct ccs_execute_handler_record *acl;
1501                  if (ptr->type != type)                  if (ptr->type != type)
1502                          continue;                          continue;
1503                  acl = container_of(ptr, struct execute_handler_record, head);                  acl = container_of(ptr, struct ccs_execute_handler_record,
1504                  return acl->handler;                                     head);
1505                    ee->handler = acl->handler;
1506                    found = true;
1507                    break;
1508          }          }
1509          return NULL;          up_read(&ccs_policy_lock);
1510            /***** READER SECTION END *****/
1511            return found;
1512  }  }
1513    
1514  /**  /**
1515   * search_binary_handler_with_transition - Perform domain transition.   * ccs_dump_page - Dump a page to buffer.
1516   *   *
1517   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1518   * @regs: Pointer to "struct pt_regs".   * @pos:  Location to dump.
1519     * @dump: Poiner to "struct ccs_page_dump".
1520   *   *
1521   * Returns result of search_binary_handler() on success,   * Returns true on success, false otherwise.
  * negative value otherwise.  
1522   */   */
1523  int search_binary_handler_with_transition(struct linux_binprm *bprm,  bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1524                                            struct pt_regs *regs)                     struct ccs_page_dump *dump)
1525    {
1526            struct page *page;
1527            /* dump->data is released by ccs_free_execve_entry(). */
1528            if (!dump->data) {
1529                    dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
1530                    if (!dump->data)
1531                            return false;
1532            }
1533            /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1534    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1535            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1536                    return false;
1537    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1538            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1539                    return false;
1540    #else
1541            page = bprm->page[pos / PAGE_SIZE];
1542    #endif
1543            if (page != dump->page) {
1544                    const unsigned int offset = pos % PAGE_SIZE;
1545                    /*
1546                     * Maybe kmap()/kunmap() should be used here.
1547                     * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1548                     * So do I.
1549                     */
1550                    char *kaddr = kmap_atomic(page, KM_USER0);
1551                    dump->page = page;
1552                    memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1553                    kunmap_atomic(kaddr, KM_USER0);
1554            }
1555            /* Same with put_arg_page(page) in fs/exec.c */
1556    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1557            put_page(page);
1558    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1559            put_page(page);
1560    #endif
1561            return true;
1562    }
1563    
1564    /**
1565     * ccs_fetch_next_domain - Fetch next_domain from the list.
1566     *
1567     * Returns pointer to "struct ccs_domain_info" which will be used if execve()
1568     * succeeds. This function does not return NULL.
1569     */
1570    struct ccs_domain_info *ccs_fetch_next_domain(void)
1571    {
1572            struct ccs_execve_entry *ee = ccs_find_execve_entry();
1573            struct ccs_domain_info *next_domain = NULL;
1574            if (ee)
1575                    next_domain = ee->r.cookie.u.domain;
1576            if (!next_domain)
1577                    next_domain = ccs_current_domain();
1578            return next_domain;
1579    }
1580    
1581    /**
1582     * ccs_start_execve - Prepare for execve() operation.
1583     *
1584     * @bprm: Pointer to "struct linux_binprm".
1585     *
1586     * Returns 0 on success, negative value otherwise.
1587     */
1588    int ccs_start_execve(struct linux_binprm *bprm)
1589  {  {
         struct task_struct *task = current;  
         struct domain_info *next_domain = NULL;  
         struct domain_info *prev_domain = task->domain_info;  
         const struct path_info *handler;  
1590          int retval;          int retval;
1591          /*          struct task_struct *task = current;
1592           * "eh_path" holds path to execute handler program.          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1593           * Thus, keep valid until search_binary_handler() finishes.          if (!ccs_policy_loaded)
1594           */                  ccs_load_policy(bprm->filename);
1595          char *eh_path = NULL;          if (!ee)
         struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));  
         ccs_load_policy(bprm->filename);  
         if (!tmp)  
1596                  return -ENOMEM;                  return -ENOMEM;
1597          /* printk(KERN_DEBUG "rootdepth=%d\n", get_root_depth()); */          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);
1598          handler = find_execute_handler(TYPE_EXECUTE_HANDLER);          ee->r.ee = ee;
1599          if (handler) {          ee->bprm = bprm;
1600                  retval = try_alt_exec(bprm, handler, &eh_path, &next_domain,          ee->r.obj = &ee->obj;
1601                                        tmp);          ee->obj.path1_dentry = bprm->file->f_dentry;
1602            ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;
1603            /* Clear manager flag. */
1604            task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1605            if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {
1606                    retval = ccs_try_alt_exec(ee);
1607                  if (!retval)                  if (!retval)
1608                          audit_execute_handler_log(true, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, true);
1609                  goto ok;                  goto ok;
1610          }          }
1611          retval = find_next_domain(bprm, &next_domain, NULL, tmp);          retval = ccs_find_next_domain(ee);
1612          if (retval != -EPERM)          if (retval != -EPERM)
1613                  goto ok;                  goto ok;
1614          handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {
1615          if (handler) {                  retval = ccs_try_alt_exec(ee);
                 retval = try_alt_exec(bprm, handler, &eh_path, &next_domain,  
                                       tmp);  
1616                  if (!retval)                  if (!retval)
1617                          audit_execute_handler_log(false, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, false);
1618          }          }
1619   ok:   ok:
1620          if (retval < 0)          if (retval < 0)
1621                  goto out;                  goto out;
1622          task->domain_info = next_domain;          ee->r.mode = ccs_check_flags(ee->r.cookie.u.domain, CCS_MAC_FOR_ENV);
1623          retval = check_environ(bprm, tmp);          retval = ccs_check_environ(ee);
1624          if (retval < 0)          if (retval < 0)
1625                  goto out;                  goto out;
1626          task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;          task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1627          retval = search_binary_handler(bprm, regs);          retval = 0;
         task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;  
1628   out:   out:
1629          /* Return to previous domain if execution failed. */          if (retval)
1630                    ccs_finish_execve(retval);
1631            return retval;
1632    }
1633    
1634    /**
1635     * ccs_finish_execve - Clean up execve() operation.
1636     *
1637     * @retval: Return code of an execve() operation.
1638     */
1639    void ccs_finish_execve(int retval)
1640    {
1641            struct task_struct *task = current;
1642            struct ccs_execve_entry *ee = ccs_find_execve_entry();
1643            task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1644            if (!ee)
1645                    return;
1646          if (retval < 0)          if (retval < 0)
1647                  task->domain_info = prev_domain;                  goto out;
1648            /***** READER SECTION START *****/
1649            down_read(&ccs_policy_lock);
1650            /* Proceed to next domain if execution suceeded. */
1651            task->ccs_domain_info = ee->r.cookie.u.domain;
1652            up_read(&ccs_policy_lock);
1653            /***** READER SECTION END *****/
1654          /* Mark the current process as execute handler. */          /* Mark the current process as execute handler. */
1655          else if (handler)          if (ee->handler)
1656                  task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1657          /* Mark the current process as normal process. */          /* Mark the current process as normal process. */
1658          else          else
1659                  task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1660          ccs_free(eh_path);   out:
1661          ccs_free(tmp);          ccs_exit_request_info(&ee->r);
1662          return retval;          ccs_free_execve_entry(ee);
1663  }  }
1664    
1665  #else  #else
1666    
1667  /**  /**
1668   * search_binary_handler_with_transition - Wrapper for search_binary_handler().   * ccs_start_execve - Prepare for execve() operation.
1669   *   *
1670   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
  * @regs: Pointer to "struct pt_regs".  
1671   *   *
1672   * Returns the result of search_binary_handler().   * Returns 0.
1673   */   */
1674  int search_binary_handler_with_transition(struct linux_binprm *bprm,  int ccs_start_execve(struct linux_binprm *bprm)
                                           struct pt_regs *regs)  
1675  {  {
1676  #ifdef CONFIG_SAKURA  #ifdef CONFIG_SAKURA
1677          ccs_load_policy(bprm->filename);          /* Clear manager flag. */
1678            current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1679            if (!ccs_policy_loaded)
1680                    ccs_load_policy(bprm->filename);
1681  #endif  #endif
1682          return search_binary_handler(bprm, regs);          return 0;
1683    }
1684    
1685    /**
1686     * ccs_finish_execve - Clean up execve() operation.
1687     */
1688    void ccs_finish_execve(int retval)
1689    {
1690  }  }
1691    
1692  #endif  #endif

Legend:
Removed from v.1561  
changed lines
  Added in v.2545

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