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

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 1700 by kumaneko, Mon Oct 13 04:57:50 2008 UTC trunk/1.7.x/ccs-patch/security/ccsecurity/domain.c revision 3538 by kumaneko, Fri Mar 26 13:35:09 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Version: 1.7.2-pre   2010/03/21
  *  
  * Version: 1.6.5-pre   2008/10/11  
7   *   *
8   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
10   *   *
11   */   */
12    
13  #include <linux/ccs_common.h>  #include <linux/slab.h>
 #include <linux/tomoyo.h>  
 #include <linux/realpath.h>  
14  #include <linux/highmem.h>  #include <linux/highmem.h>
15  #include <linux/binfmts.h>  #include <linux/version.h>
16  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17  #include <linux/namei.h>  #include <linux/namei.h>
18  #include <linux/mount.h>  #include <linux/mount.h>
19  #endif  #endif
20    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
21  /* For compatibility with older kernels. */  #include <linux/fs_struct.h>
 #ifndef for_each_process  
 #define for_each_process for_each_task  
22  #endif  #endif
23    #include "internal.h"
24    
25  /* Variables definitions.*/  /* Variables definitions.*/
26    
27  /* The initial domain. */  /* The initial domain. */
28  struct domain_info KERNEL_DOMAIN;  struct ccs_domain_info ccs_kernel_domain;
   
 /* The list for "struct domain_info". */  
 LIST1_HEAD(domain_list);  
   
 #ifdef CONFIG_TOMOYO  
   
 /* Domain creation lock. */  
 static DEFINE_MUTEX(domain_list_lock);  
   
 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */  
 struct domain_initializer_entry {  
         struct list1_head list;  
         const struct path_info *domainname;    /* This may be NULL */  
         const struct path_info *program;  
         bool is_deleted;  
         bool is_not;       /* True if this entry is "no_initialize_domain".  */  
         bool is_last_name; /* True if the domainname is ccs_get_last_name(). */  
 };  
   
 /* Structure for "keep_domain" and "no_keep_domain" keyword. */  
 struct domain_keeper_entry {  
         struct list1_head list;  
         const struct path_info *domainname;  
         const struct path_info *program;       /* This may be NULL */  
         bool is_deleted;  
         bool is_not;       /* True if this entry is "no_keep_domain".        */  
         bool is_last_name; /* True if the domainname is ccs_get_last_name(). */  
 };  
   
 /* Structure for "aggregator" keyword. */  
 struct aggregator_entry {  
         struct list1_head list;  
         const struct path_info *original_name;  
         const struct path_info *aggregated_name;  
         bool is_deleted;  
 };  
   
 /* Structure for "alias" keyword. */  
 struct alias_entry {  
         struct list1_head list;  
         const struct path_info *original_name;  
         const struct path_info *aliased_name;  
         bool is_deleted;  
 };  
   
 /**  
  * ccs_set_domain_flag - Set or clear domain's attribute flags.  
  *  
  * @domain:    Pointer to "struct domain_info".  
  * @is_delete: True if it is a delete request.  
  * @flags:     Flags to set or clear.  
  *  
  * Returns nothing.  
  */  
 void ccs_set_domain_flag(struct domain_info *domain, const bool is_delete,  
                          const u8 flags)  
 {  
         /* We need to serialize because this is bitfield operation. */  
         static DEFINE_SPINLOCK(lock);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&lock);  
         if (!is_delete)  
                 domain->flags |= flags;  
         else  
                 domain->flags &= ~flags;  
         spin_unlock(&lock);  
         /***** CRITICAL SECTION END *****/  
 }  
   
 /**  
  * ccs_get_last_name - Get last component of a domainname.  
  *  
  * @domain: Pointer to "struct domain_info".  
  *  
  * Returns the last component of the domainname.  
  */  
 const char *ccs_get_last_name(const struct domain_info *domain)  
 {  
         const char *cp0 = domain->domainname->name;  
         const char *cp1 = strrchr(cp0, ' ');  
         if (cp1)  
                 return cp1 + 1;  
         return cp0;  
 }  
   
 /**  
  * ccs_add_domain_acl - Add the given ACL to the given domain.  
  *  
  * @domain: Pointer to "struct domain_info". May be NULL.  
  * @acl:    Pointer to "struct acl_info".  
  *  
  * Returns 0.  
  */  
 int ccs_add_domain_acl(struct domain_info *domain, struct acl_info *acl)  
 {  
         if (domain) {  
                 /*  
                  * We need to serialize because this function is called by  
                  * various update functions.  
                  */  
                 static DEFINE_SPINLOCK(lock);  
                 /***** CRITICAL SECTION START *****/  
                 spin_lock(&lock);  
                 list1_add_tail_mb(&acl->list, &domain->acl_info_list);  
                 spin_unlock(&lock);  
                 /***** CRITICAL SECTION END *****/  
         } else {  
                 acl->type &= ~ACL_DELETED;  
         }  
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
         return 0;  
 }  
29    
30  /**  /* The list for "struct ccs_domain_info". */
31   * ccs_del_domain_acl - Delete the given ACL from the domain.  LIST_HEAD(ccs_domain_list);
  *  
  * @acl: Pointer to "struct acl_info". May be NULL.  
  *  
  * Returns 0.  
  */  
 int ccs_del_domain_acl(struct acl_info *acl)  
 {  
         if (acl)  
                 acl->type |= ACL_DELETED;  
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
         return 0;  
 }  
32    
33  /**  /**
34   * audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
35   *   *
36     * @ee:         Pointer to "struct ccs_execve_entry".
37   * @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".  
38   *   *
39   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
40   */   */
41  static int audit_execute_handler_log(const bool is_default,  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
42                                       const char *handler,                                           const bool is_default)
                                      struct linux_binprm *bprm)  
43  {  {
44          struct ccs_request_info r;          int error;
45          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);          struct ccs_request_info *r = &ee->r;
46          r.bprm = bprm;          struct ccs_domain_info *domain = r->domain;
47          return ccs_write_audit_log(true, &r, "%s %s\n",          const char *handler = ee->handler->name;
48                                     is_default ? KEYWORD_EXECUTE_HANDLER :          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
49                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);          r->domain = ee->previous_domain;
50            error = ccs_write_audit_log(true, r, "%s %s\n",
51                                        is_default ? CCS_KEYWORD_EXECUTE_HANDLER :
52                                        CCS_KEYWORD_DENIED_EXECUTE_HANDLER,
53                                        handler);
54            r->domain = domain;
55            return error;
56  }  }
57    
58  /**  /**
59   * audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
60   *   *
61   * @domain:  Pointer to "struct domain_info".   * @domain:  Pointer to "struct ccs_domain_info".
62   *   *
63   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
64   */   */
65  static int audit_domain_creation_log(struct domain_info *domain)  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
66  {  {
67          struct ccs_request_info r;          struct ccs_request_info r;
68          ccs_init_request_info(&r, domain, CCS_TOMOYO_MAC_FOR_FILE);          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);
69          return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);          return ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
70  }  }
71    
72  /* The list for "struct domain_initializer_entry". */  /* The list for "struct ccs_domain_initializer_entry". */
73  static LIST1_HEAD(domain_initializer_list);  LIST_HEAD(ccs_domain_initializer_list);
74    
75  /**  /**
76   * update_domain_initializer_entry - Update "struct domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
77   *   *
78   * @domainname: The name of domain. May be NULL.   * @domainname: The name of domain. May be NULL.
79   * @program:    The name of program.   * @program:    The name of program.
# Line 207  static LIST1_HEAD(domain_initializer_lis Line 82  static LIST1_HEAD(domain_initializer_lis
82   *   *
83   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
84   */   */
85  static int update_domain_initializer_entry(const char *domainname,  static int ccs_update_domain_initializer_entry(const char *domainname,
86                                             const char *program,                                                 const char *program,
87                                             const bool is_not,                                                 const bool is_not,
88                                             const bool is_delete)                                                 const bool is_delete)
89  {  {
90          struct domain_initializer_entry *new_entry;          struct ccs_domain_initializer_entry *ptr;
91          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry e = { .is_not = is_not };
92          static DEFINE_MUTEX(lock);          int error = is_delete ? -ENOENT : -ENOMEM;
93          const struct path_info *saved_program;          if (!ccs_is_correct_path(program, 1, -1, -1))
         const struct path_info *saved_domainname = NULL;  
         int error = -ENOMEM;  
         bool is_last_name = false;  
         if (!ccs_is_correct_path(program, 1, -1, -1, __func__))  
94                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
95          if (domainname) {          if (domainname) {
96                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_is_domain_def(domainname) &&
97                      ccs_is_correct_path(domainname, 1, -1, -1, __func__))                      ccs_is_correct_path(domainname, 1, -1, -1))
98                          is_last_name = true;                          e.is_last_name = true;
99                  else if (!ccs_is_correct_domain(domainname, __func__))                  else if (!ccs_is_correct_domain(domainname))
100                          return -EINVAL;                          return -EINVAL;
101                  saved_domainname = ccs_save_name(domainname);                  e.domainname = ccs_get_name(domainname);
102                  if (!saved_domainname)                  if (!e.domainname)
103                          return -ENOMEM;                          goto out;
104          }          }
105          saved_program = ccs_save_name(program);          e.program = ccs_get_name(program);
106          if (!saved_program)          if (!e.program)
107                  return -ENOMEM;                  goto out;
108          mutex_lock(&lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
109          list1_for_each_entry(ptr, &domain_initializer_list, list) {                  goto out;
110                  if (ptr->is_not != is_not ||          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
111                      ptr->domainname != saved_domainname ||                  if (!ccs_is_same_domain_initializer_entry(ptr, &e))
                     ptr->program != saved_program)  
112                          continue;                          continue;
113                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
114                  error = 0;                  error = 0;
115                  goto out;                  break;
116          }          }
117          if (is_delete) {          if (!is_delete && error) {
118                  error = -ENOENT;                  struct ccs_domain_initializer_entry *entry =
119                  goto out;                          ccs_commit_ok(&e, sizeof(e));
120                    if (entry) {
121                            list_add_tail_rcu(&entry->list,
122                                              &ccs_domain_initializer_list);
123                            error = 0;
124                    }
125          }          }
126          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
         if (!new_entry)  
                 goto out;  
         new_entry->domainname = saved_domainname;  
         new_entry->program = saved_program;  
         new_entry->is_not = is_not;  
         new_entry->is_last_name = is_last_name;  
         list1_add_tail_mb(&new_entry->list, &domain_initializer_list);  
         error = 0;  
127   out:   out:
128          mutex_unlock(&lock);          ccs_put_name(e.domainname);
129          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.program);
130          return error;          return error;
131  }  }
132    
133  /**  /**
134   * ccs_read_domain_initializer_policy - Read "struct domain_initializer_entry" list.   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.
135   *   *
136   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
137   *   *
138   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
139     *
140     * Caller holds ccs_read_lock().
141   */   */
142  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
143  {  {
144          struct list1_head *pos;          struct list_head *pos;
145          list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) {          bool done = true;
146            list_for_each_cookie(pos, head->read_var2,
147                                 &ccs_domain_initializer_list) {
148                  const char *no;                  const char *no;
149                  const char *from = "";                  const char *from = "";
150                  const char *domain = "";                  const char *domain = "";
151                  struct domain_initializer_entry *ptr;                  struct ccs_domain_initializer_entry *ptr;
152                  ptr = list1_entry(pos, struct domain_initializer_entry, list);                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
153                                     list);
154                  if (ptr->is_deleted)                  if (ptr->is_deleted)
155                          continue;                          continue;
156                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 286  bool ccs_read_domain_initializer_policy( Line 158  bool ccs_read_domain_initializer_policy(
158                          from = " from ";                          from = " from ";
159                          domain = ptr->domainname->name;                          domain = ptr->domainname->name;
160                  }                  }
161                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_INITIALIZE_DOMAIN
162                                     "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",                                       "%s%s%s\n", no, ptr->program->name, from,
163                                     no, ptr->program->name, from, domain))                                       domain);
164                                  goto out;                  if (!done)
165                            break;
166          }          }
167          return true;          return done;
  out:  
         return false;  
168  }  }
169    
170  /**  /**
171   * ccs_write_domain_initializer_policy - Write "struct domain_initializer_entry" list.   * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.
172   *   *
173   * @data:      String to parse.   * @data:      String to parse.
174   * @is_not:    True if it is "no_initialize_domain" entry.   * @is_not:    True if it is "no_initialize_domain" entry.
# Line 311  int ccs_write_domain_initializer_policy( Line 182  int ccs_write_domain_initializer_policy(
182          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
183          if (cp) {          if (cp) {
184                  *cp = '\0';                  *cp = '\0';
185                  return update_domain_initializer_entry(cp + 6, data, is_not,                  return ccs_update_domain_initializer_entry(cp + 6, data,
186                                                         is_delete);                                                             is_not, is_delete);
187          }          }
188          return update_domain_initializer_entry(NULL, data, is_not, is_delete);          return ccs_update_domain_initializer_entry(NULL, data, is_not,
189                                                       is_delete);
190  }  }
191    
192  /**  /**
193   * is_domain_initializer - Check whether the given program causes domainname reinitialization.   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.
194   *   *
195   * @domainname: The name of domain.   * @domainname: The name of domain.
196   * @program:    The name of program.   * @program:    The name of program.
# Line 326  int ccs_write_domain_initializer_policy( Line 198  int ccs_write_domain_initializer_policy(
198   *   *
199   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
200   * false otherwise.   * false otherwise.
201     *
202     * Caller holds ccs_read_lock().
203   */   */
204  static bool is_domain_initializer(const struct path_info *domainname,  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
205                                    const struct path_info *program,                                        const struct ccs_path_info *program,
206                                    const struct path_info *last_name)                                        const struct ccs_path_info *last_name)
207  {  {
208          struct domain_initializer_entry *ptr;          struct ccs_domain_initializer_entry *ptr;
209          bool flag = false;          bool flag = false;
210          list1_for_each_entry(ptr,  &domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
211                  if (ptr->is_deleted)                  if (ptr->is_deleted)
212                          continue;                          continue;
213                  if (ptr->domainname) {                  if (ptr->domainname) {
# Line 347  static bool is_domain_initializer(const Line 221  static bool is_domain_initializer(const
221                  }                  }
222                  if (ccs_pathcmp(ptr->program, program))                  if (ccs_pathcmp(ptr->program, program))
223                          continue;                          continue;
224                  if (ptr->is_not)                  if (ptr->is_not) {
225                          return false;                          flag = false;
226                            break;
227                    }
228                  flag = true;                  flag = true;
229          }          }
230          return flag;          return flag;
231  }  }
232    
233  /* The list for "struct domain_keeper_entry". */  /* The list for "struct ccs_domain_keeper_entry". */
234  static LIST1_HEAD(domain_keeper_list);  LIST_HEAD(ccs_domain_keeper_list);
235    
236  /**  /**
237   * update_domain_keeper_entry - Update "struct domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
238   *   *
239   * @domainname: The name of domain.   * @domainname: The name of domain.
240   * @program:    The name of program. May be NULL.   * @program:    The name of program. May be NULL.
# Line 367  static LIST1_HEAD(domain_keeper_list); Line 243  static LIST1_HEAD(domain_keeper_list);
243   *   *
244   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
245   */   */
246  static int update_domain_keeper_entry(const char *domainname,  static int ccs_update_domain_keeper_entry(const char *domainname,
247                                        const char *program,                                            const char *program,
248                                        const bool is_not, const bool is_delete)                                            const bool is_not,
249  {                                            const bool is_delete)
250          struct domain_keeper_entry *new_entry;  {
251          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
252          const struct path_info *saved_domainname;          struct ccs_domain_keeper_entry e = { .is_not = is_not };
253          const struct path_info *saved_program = NULL;          int error = is_delete ? -ENOENT : -ENOMEM;
         static DEFINE_MUTEX(lock);  
         int error = -ENOMEM;  
         bool is_last_name = false;  
254          if (!ccs_is_domain_def(domainname) &&          if (!ccs_is_domain_def(domainname) &&
255              ccs_is_correct_path(domainname, 1, -1, -1, __func__))              ccs_is_correct_path(domainname, 1, -1, -1))
256                  is_last_name = true;                  e.is_last_name = true;
257          else if (!ccs_is_correct_domain(domainname, __func__))          else if (!ccs_is_correct_domain(domainname))
258                  return -EINVAL;                  return -EINVAL;
259          if (program) {          if (program) {
260                  if (!ccs_is_correct_path(program, 1, -1, -1, __func__))                  if (!ccs_is_correct_path(program, 1, -1, -1))
261                          return -EINVAL;                          return -EINVAL;
262                  saved_program = ccs_save_name(program);                  e.program = ccs_get_name(program);
263                  if (!saved_program)                  if (!e.program)
264                          return -ENOMEM;                          goto out;
265          }          }
266          saved_domainname = ccs_save_name(domainname);          e.domainname = ccs_get_name(domainname);
267          if (!saved_domainname)          if (!e.domainname)
268                  return -ENOMEM;                  goto out;
269          mutex_lock(&lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
270          list1_for_each_entry(ptr, &domain_keeper_list, list) {                  goto out;
271                  if (ptr->is_not != is_not ||          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
272                      ptr->domainname != saved_domainname ||                  if (!ccs_is_same_domain_keeper_entry(ptr, &e))
                     ptr->program != saved_program)  
273                          continue;                          continue;
274                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
275                  error = 0;                  error = 0;
276                  goto out;                  break;
277          }          }
278          if (is_delete) {          if (!is_delete && error) {
279                  error = -ENOENT;                  struct ccs_domain_keeper_entry *entry =
280                  goto out;                          ccs_commit_ok(&e, sizeof(e));
281                    if (entry) {
282                            list_add_tail_rcu(&entry->list,
283                                              &ccs_domain_keeper_list);
284                            error = 0;
285                    }
286          }          }
287          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
         if (!new_entry)  
                 goto out;  
         new_entry->domainname = saved_domainname;  
         new_entry->program = saved_program;  
         new_entry->is_not = is_not;  
         new_entry->is_last_name = is_last_name;  
         list1_add_tail_mb(&new_entry->list, &domain_keeper_list);  
         error = 0;  
288   out:   out:
289          mutex_unlock(&lock);          ccs_put_name(e.domainname);
290          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.program);
291          return error;          return error;
292  }  }
293    
294  /**  /**
295   * ccs_write_domain_keeper_policy - Write "struct domain_keeper_entry" list.   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.
296   *   *
297   * @data:      String to parse.   * @data:      String to parse.
298   * @is_not:    True if it is "no_keep_domain" entry.   * @is_not:    True if it is "no_keep_domain" entry.
# Line 436  int ccs_write_domain_keeper_policy(char Line 305  int ccs_write_domain_keeper_policy(char
305          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
306          if (cp) {          if (cp) {
307                  *cp = '\0';                  *cp = '\0';
308                  return update_domain_keeper_entry(cp + 6, data,                  return ccs_update_domain_keeper_entry(cp + 6, data,
309                                                    is_not, is_delete);                                                        is_not, is_delete);
310          }          }
311          return update_domain_keeper_entry(data, NULL, is_not, is_delete);          return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);
312  }  }
313    
314  /**  /**
315   * ccs_read_domain_keeper_policy - Read "struct domain_keeper_entry" list.   * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.
316   *   *
317   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
318   *   *
319   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
320     *
321     * Caller holds ccs_read_lock().
322   */   */
323  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
324  {  {
325          struct list1_head *pos;          struct list_head *pos;
326          list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) {          bool done = true;
327                  struct domain_keeper_entry *ptr;          list_for_each_cookie(pos, head->read_var2,
328                                 &ccs_domain_keeper_list) {
329                    struct ccs_domain_keeper_entry *ptr;
330                  const char *no;                  const char *no;
331                  const char *from = "";                  const char *from = "";
332                  const char *program = "";                  const char *program = "";
333                  ptr = list1_entry(pos, struct domain_keeper_entry, list);                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
334                  if (ptr->is_deleted)                  if (ptr->is_deleted)
335                          continue;                          continue;
336                  no = ptr->is_not ? "no_" : "";                  no = ptr->is_not ? "no_" : "";
# Line 465  bool ccs_read_domain_keeper_policy(struc Line 338  bool ccs_read_domain_keeper_policy(struc
338                          from = " from ";                          from = " from ";
339                          program = ptr->program->name;                          program = ptr->program->name;
340                  }                  }
341                  if (!ccs_io_printf(head,                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_KEEP_DOMAIN
342                                     "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,                                       "%s%s%s\n", no, program, from,
343                                     program, from, ptr->domainname->name))                                       ptr->domainname->name);
344                                  goto out;                  if (!done)
345                            break;
346          }          }
347          return true;          return done;
  out:  
         return false;  
348  }  }
349    
350  /**  /**
351   * 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.
352   *   *
353   * @domainname: The name of domain.   * @domainname: The name of domain.
354   * @program:    The name of program.   * @program:    The name of program.
# Line 484  bool ccs_read_domain_keeper_policy(struc Line 356  bool ccs_read_domain_keeper_policy(struc
356   *   *
357   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
358   * false otherwise.   * false otherwise.
359     *
360     * Caller holds ccs_read_lock().
361   */   */
362  static bool is_domain_keeper(const struct path_info *domainname,  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
363                               const struct path_info *program,                                   const struct ccs_path_info *program,
364                               const struct path_info *last_name)                                   const struct ccs_path_info *last_name)
365  {  {
366          struct domain_keeper_entry *ptr;          struct ccs_domain_keeper_entry *ptr;
367          bool flag = false;          bool flag = false;
368          list1_for_each_entry(ptr, &domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
369                  if (ptr->is_deleted)                  if (ptr->is_deleted)
370                          continue;                          continue;
371                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
# Line 503  static bool is_domain_keeper(const struc Line 377  static bool is_domain_keeper(const struc
377                  }                  }
378                  if (ptr->program && ccs_pathcmp(ptr->program, program))                  if (ptr->program && ccs_pathcmp(ptr->program, program))
379                          continue;                          continue;
380                  if (ptr->is_not)                  if (ptr->is_not) {
381                          return false;                          flag = false;
382                            break;
383                    }
384                  flag = true;                  flag = true;
385          }          }
386          return flag;          return flag;
387  }  }
388    
389  /* The list for "struct alias_entry". */  /* The list for "struct ccs_aggregator_entry". */
390  static LIST1_HEAD(alias_list);  LIST_HEAD(ccs_aggregator_list);
391    
392  /**  /**
393   * update_alias_entry - Update "struct alias_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
  *  
  * @original_name: The original program's real name.  
  * @aliased_name:  The symbolic program's symbolic link's name.  
  * @is_delete:     True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 static int update_alias_entry(const char *original_name,  
                               const char *aliased_name,  
                               const bool is_delete)  
 {  
         struct alias_entry *new_entry;  
         struct alias_entry *ptr;  
         static DEFINE_MUTEX(lock);  
         const struct path_info *saved_original_name;  
         const struct path_info *saved_aliased_name;  
         int error = -ENOMEM;  
         if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) ||  
             !ccs_is_correct_path(aliased_name, 1, -1, -1, __func__))  
                 return -EINVAL; /* No patterns allowed. */  
         saved_original_name = ccs_save_name(original_name);  
         saved_aliased_name = ccs_save_name(aliased_name);  
         if (!saved_original_name || !saved_aliased_name)  
                 return -ENOMEM;  
         mutex_lock(&lock);  
         list1_for_each_entry(ptr, &alias_list, list) {  
                 if (ptr->original_name != saved_original_name ||  
                     ptr->aliased_name != saved_aliased_name)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 goto out;  
         }  
         if (is_delete) {  
                 error = -ENOENT;  
                 goto out;  
         }  
         new_entry = ccs_alloc_element(sizeof(*new_entry));  
         if (!new_entry)  
                 goto out;  
         new_entry->original_name = saved_original_name;  
         new_entry->aliased_name = saved_aliased_name;  
         list1_add_tail_mb(&new_entry->list, &alias_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
         return error;  
 }  
   
 /**  
  * ccs_read_alias_policy - Read "struct alias_entry" list.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  */  
 bool ccs_read_alias_policy(struct ccs_io_buffer *head)  
 {  
         struct list1_head *pos;  
         list1_for_each_cookie(pos, head->read_var2, &alias_list) {  
                 struct alias_entry *ptr;  
                 ptr = list1_entry(pos, struct alias_entry, list);  
                 if (ptr->is_deleted)  
                         continue;  
                 if (!ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",  
                                    ptr->original_name->name,  
                                    ptr->aliased_name->name))  
                         goto out;  
         }  
         return true;  
  out:  
         return false;  
 }  
   
 /**  
  * ccs_write_alias_policy - Write "struct alias_entry" list.  
  *  
  * @data:      String to parse.  
  * @is_delete: True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 int ccs_write_alias_policy(char *data, const bool is_delete)  
 {  
         char *cp = strchr(data, ' ');  
         if (!cp)  
                 return -EINVAL;  
         *cp++ = '\0';  
         return update_alias_entry(data, cp, is_delete);  
 }  
   
 /* The list for "struct aggregator_entry". */  
 static LIST1_HEAD(aggregator_list);  
   
 /**  
  * update_aggregator_entry - Update "struct aggregator_entry" list.  
394   *   *
395   * @original_name:   The original program's name.   * @original_name:   The original program's name.
396   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 619  static LIST1_HEAD(aggregator_list); Line 398  static LIST1_HEAD(aggregator_list);
398   *   *
399   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
400   */   */
401  static int update_aggregator_entry(const char *original_name,  static int ccs_update_aggregator_entry(const char *original_name,
402                                     const char *aggregated_name,                                         const char *aggregated_name,
403                                     const bool is_delete)                                         const bool is_delete)
404  {  {
405          struct aggregator_entry *new_entry;          struct ccs_aggregator_entry *ptr;
406          struct aggregator_entry *ptr;          struct ccs_aggregator_entry e = { };
407          static DEFINE_MUTEX(lock);          int error = is_delete ? -ENOENT : -ENOMEM;
408          const struct path_info *saved_original_name;          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
409          const struct path_info *saved_aggregated_name;              !ccs_is_correct_path(aggregated_name, 1, -1, -1))
         int error = -ENOMEM;  
         if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) ||  
             !ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__))  
410                  return -EINVAL;                  return -EINVAL;
411          saved_original_name = ccs_save_name(original_name);          e.original_name = ccs_get_name(original_name);
412          saved_aggregated_name = ccs_save_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
413          if (!saved_original_name || !saved_aggregated_name)          if (!e.original_name || !e.aggregated_name)
414                  return -ENOMEM;                  goto out;
415          mutex_lock(&lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
416          list1_for_each_entry(ptr, &aggregator_list, list) {                  goto out;
417                  if (ptr->original_name != saved_original_name ||          list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
418                      ptr->aggregated_name != saved_aggregated_name)                  if (!ccs_is_same_aggregator_entry(ptr, &e))
419                          continue;                          continue;
420                  ptr->is_deleted = is_delete;                  ptr->is_deleted = is_delete;
421                  error = 0;                  error = 0;
422                  goto out;                  break;
423          }          }
424          if (is_delete) {          if (!is_delete && error) {
425                  error = -ENOENT;                  struct ccs_aggregator_entry *entry =
426                  goto out;                          ccs_commit_ok(&e, sizeof(e));
427                    if (entry) {
428                            list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
429                            error = 0;
430                    }
431          }          }
432          new_entry = ccs_alloc_element(sizeof(*new_entry));          mutex_unlock(&ccs_policy_lock);
         if (!new_entry)  
                 goto out;  
         new_entry->original_name = saved_original_name;  
         new_entry->aggregated_name = saved_aggregated_name;  
         list1_add_tail_mb(&new_entry->list, &aggregator_list);  
         error = 0;  
433   out:   out:
434          mutex_unlock(&lock);          ccs_put_name(e.original_name);
435          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);          ccs_put_name(e.aggregated_name);
436          return error;          return error;
437  }  }
438    
439  /**  /**
440   * ccs_read_aggregator_policy - Read "struct aggregator_entry" list.   * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.
441   *   *
442   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
443   *   *
444   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
445     *
446     * Caller holds ccs_read_lock().
447   */   */
448  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
449  {  {
450          struct list1_head *pos;          struct list_head *pos;
451          list1_for_each_cookie(pos, head->read_var2, &aggregator_list) {          bool done = true;
452                  struct aggregator_entry *ptr;          list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
453                  ptr = list1_entry(pos, struct aggregator_entry, list);                  struct ccs_aggregator_entry *ptr;
454                    ptr = list_entry(pos, struct ccs_aggregator_entry, list);
455                  if (ptr->is_deleted)                  if (ptr->is_deleted)
456                          continue;                          continue;
457                  if (!ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",                  done = ccs_io_printf(head, CCS_KEYWORD_AGGREGATOR "%s %s\n",
458                                     ptr->original_name->name,                                       ptr->original_name->name,
459                                     ptr->aggregated_name->name))                                       ptr->aggregated_name->name);
460                          goto out;                  if (!done)
461                            break;
462          }          }
463          return true;          return done;
  out:  
         return false;  
464  }  }
465    
466  /**  /**
467   * ccs_write_aggregator_policy - Write "struct aggregator_entry" list.   * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.
468   *   *
469   * @data:      String to parse.   * @data:      String to parse.
470   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
# Line 697  bool ccs_read_aggregator_policy(struct c Line 473  bool ccs_read_aggregator_policy(struct c
473   */   */
474  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator_policy(char *data, const bool is_delete)
475  {  {
476          char *cp = strchr(data, ' ');          char *w[2];
477          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
478                  return -EINVAL;                  return -EINVAL;
479          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return update_aggregator_entry(data, cp, is_delete);  
480  }  }
481    
482  /* Domain create/delete/undelete handler. */  /* Domain create/delete handler. */
   
 /* #define DEBUG_DOMAIN_UNDELETE */  
483    
484  /**  /**
485   * ccs_delete_domain - Delete a domain.   * ccs_delete_domain - Delete a domain.
# Line 717  int ccs_write_aggregator_policy(char *da Line 490  int ccs_write_aggregator_policy(char *da
490   */   */
491  int ccs_delete_domain(char *domainname)  int ccs_delete_domain(char *domainname)
492  {  {
493          struct domain_info *domain;          struct ccs_domain_info *domain;
494          struct path_info name;          struct ccs_path_info name;
495          name.name = domainname;          name.name = domainname;
496          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
497          mutex_lock(&domain_list_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
498  #ifdef DEBUG_DOMAIN_UNDELETE                  return 0;
         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  
499          /* Is there an active domain? */          /* Is there an active domain? */
500          list1_for_each_entry(domain, &domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
501                  struct domain_info *domain2;                  /* Never delete ccs_kernel_domain */
502                  /* Never delete KERNEL_DOMAIN */                  if (domain == &ccs_kernel_domain)
                 if (domain == &KERNEL_DOMAIN)  
503                          continue;                          continue;
504                  if (domain->is_deleted ||                  if (domain->is_deleted ||
505                      ccs_pathcmp(domain->domainname, &name))                      ccs_pathcmp(domain->domainname, &name))
506                          continue;                          continue;
507                  /* 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  
508                  break;                  break;
509          }          }
510          mutex_unlock(&domain_list_lock);          mutex_unlock(&ccs_policy_lock);
511          return 0;          return 0;
512  }  }
513    
514  /**  /**
  * ccs_undelete_domain - Undelete a domain.  
  *  
  * @domainname: The name of domain.  
  *  
  * Returns pointer to "struct domain_info" on success, NULL otherwise.  
  */  
 struct domain_info *ccs_undelete_domain(const char *domainname)  
 {  
         struct domain_info *domain;  
         struct domain_info *candidate_domain = NULL;  
         struct path_info name;  
         name.name = domainname;  
         ccs_fill_path_info(&name);  
         mutex_lock(&domain_list_lock);  
 #ifdef DEBUG_DOMAIN_UNDELETE  
         printk(KERN_DEBUG "ccs_undelete_domain %s\n", domainname);  
         list1_for_each_entry(domain, &domain_list, list) {  
                 if (ccs_pathcmp(domain->domainname, &name))  
                         continue;  
                 printk(KERN_DEBUG "List: %p %u\n", domain, domain->is_deleted);  
         }  
 #endif  
         list1_for_each_entry(domain, &domain_list, list) {  
                 if (ccs_pathcmp(&name, domain->domainname))  
                         continue;  
                 if (!domain->is_deleted) {  
                         /* This domain is active. I can't undelete. */  
                         candidate_domain = NULL;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                         printk(KERN_DEBUG "%p is active. I can't undelete.\n",  
                                domain);  
 #endif  
                         break;  
                 }  
                 /* Is this domain undeletable? */  
                 if (domain->is_deleted == 1)  
                         candidate_domain = domain;  
         }  
         if (candidate_domain) {  
                 candidate_domain->is_deleted = 0;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk(KERN_DEBUG "%p was undeleted.\n", candidate_domain);  
 #endif  
         }  
         mutex_unlock(&domain_list_lock);  
         return candidate_domain;  
 }  
   
 /**  
515   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_find_or_assign_new_domain - Create a domain.
516   *   *
517   * @domainname: The name of domain.   * @domainname: The name of domain.
518   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
519   *   *
520   * Returns pointer to "struct domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
521   */   */
522  struct domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
523                                                    const u8 profile)                                                        const u8 profile)
524  {  {
525          struct domain_info *domain = NULL;          struct ccs_domain_info *entry;
526          const struct path_info *saved_domainname;          struct ccs_domain_info *domain = NULL;
527          mutex_lock(&domain_list_lock);          const struct ccs_path_info *saved_domainname;
528          domain = ccs_find_domain(domainname);          bool found = false;
529          if (domain)  
530                  goto out;          if (!ccs_is_correct_domain(domainname))
531          if (!ccs_is_correct_domain(domainname, __func__))                  return NULL;
532                  goto out;          saved_domainname = ccs_get_name(domainname);
         saved_domainname = ccs_save_name(domainname);  
533          if (!saved_domainname)          if (!saved_domainname)
534                    return NULL;
535            entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
536            if (mutex_lock_interruptible(&ccs_policy_lock))
537                  goto out;                  goto out;
538          /* Can I reuse memory of deleted domain? */          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
539          list1_for_each_entry(domain, &domain_list, list) {                  if (domain->is_deleted ||
540                  struct task_struct *p;                      ccs_pathcmp(saved_domainname, domain->domainname))
                 struct acl_info *ptr;  
                 bool flag;  
                 if (!domain->is_deleted ||  
                     domain->domainname != saved_domainname)  
                         continue;  
                 flag = false;  
                 /***** CRITICAL SECTION START *****/  
                 read_lock(&tasklist_lock);  
                 for_each_process(p) {  
                         if (p->domain_info != domain)  
                                 continue;  
                         flag = true;  
                         break;  
                 }  
                 read_unlock(&tasklist_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (flag)  
541                          continue;                          continue;
542  #ifdef DEBUG_DOMAIN_UNDELETE                  found = true;
543                  printk(KERN_DEBUG "Reusing %p %s\n", domain,                  break;
                        domain->domainname->name);  
 #endif  
                 list1_for_each_entry(ptr, &domain->acl_info_list, list) {  
                         ptr->type |= ACL_DELETED;  
                 }  
                 ccs_set_domain_flag(domain, true, domain->flags);  
                 domain->profile = profile;  
                 domain->quota_warned = false;  
                 mb(); /* Avoid out-of-order execution. */  
                 domain->is_deleted = 0;  
                 goto out;  
544          }          }
545          /* No memory reusable. Create using new memory. */          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
546          domain = ccs_alloc_element(sizeof(*domain));                  INIT_LIST_HEAD(&entry->acl_info_list);
547          if (domain) {                  entry->domainname = saved_domainname;
548                  INIT_LIST1_HEAD(&domain->acl_info_list);                  saved_domainname = NULL;
549                  domain->domainname = saved_domainname;                  entry->profile = profile;
550                  domain->profile = profile;                  list_add_tail_rcu(&entry->list, &ccs_domain_list);
551                  list1_add_tail_mb(&domain->list, &domain_list);                  domain = entry;
552                    entry = NULL;
553                    found = true;
554          }          }
555            mutex_unlock(&ccs_policy_lock);
556   out:   out:
557          mutex_unlock(&domain_list_lock);          ccs_put_name(saved_domainname);
558          return domain;          kfree(entry);
559            return found ? domain : NULL;
560  }  }
561    
562  /**  /**
563   * get_argv0 - Get argv[0].   * ccs_find_next_domain - Find a domain.
564   *   *
565   * @bprm: Pointer to "struct linux_binprm".   * @ee: Pointer to "struct ccs_execve_entry".
  * @tmp:  Buffer for temporal use.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool get_argv0(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)  
 {  
         char *arg_ptr = tmp->buffer;  
         int arg_len = 0;  
         unsigned long pos = bprm->p;  
         int i = pos / PAGE_SIZE;  
         int offset = pos % PAGE_SIZE;  
         bool done = false;  
         if (!bprm->argc)  
                 goto out;  
         while (1) {  
                 struct page *page;  
                 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)  
                         goto out;  
                 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;  
                 }  
                 /* Read. */  
                 while (offset < PAGE_SIZE) {  
                         const unsigned char c = kaddr[offset++];  
                         if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {  
                                 if (c == '\\') {  
                                         arg_ptr[arg_len++] = '\\';  
                                         arg_ptr[arg_len++] = '\\';  
                                 } else if (c == '/') {  
                                         arg_len = 0;  
                                 } else if (c > ' ' && c < 127) {  
                                         arg_ptr[arg_len++] = c;  
                                 } else {  
                                         arg_ptr[arg_len++] = '\\';  
                                         arg_ptr[arg_len++] = (c >> 6) + '0';  
                                         arg_ptr[arg_len++]  
                                                 = ((c >> 3) & 7) + '0';  
                                         arg_ptr[arg_len++] = (c & 7) + '0';  
                                 }  
                         } else {  
                                 arg_ptr[arg_len] = '\0';  
                                 done = true;  
                                 break;  
                         }  
                 }  
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
                 offset = 0;  
                 if (done)  
                         break;  
         }  
         return true;  
  out:  
         return false;  
 }  
   
 /**  
  * find_next_domain - Find a domain.  
  *  
  * @r:       Pointer to "struct ccs_request_info".  
  * @handler: Pathname to verify. May be NULL.  
566   *   *
567   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
568     *
569     * Caller holds ccs_read_lock().
570   */   */
571  static int find_next_domain(struct ccs_request_info *r,  static int ccs_find_next_domain(struct ccs_execve_entry *ee)
                             const struct path_info *handler)  
572  {  {
573          /*          struct ccs_request_info *r = &ee->r;
574           * This function assumes that the size of buffer returned by          const struct ccs_path_info *handler = ee->handler;
575           * ccs_realpath() = CCS_MAX_PATHNAME_LEN.          struct ccs_domain_info *domain = NULL;
          */  
         struct domain_info *domain = NULL;  
576          const char *old_domain_name = r->domain->domainname->name;          const char *old_domain_name = r->domain->domainname->name;
577          struct linux_binprm *bprm = r->bprm;          struct linux_binprm *bprm = ee->bprm;
578          struct ccs_page_buffer *tmp = r->obj->tmp;          const u32 ccs_flags = current->ccs_flags;
579          const char *original_name = bprm->filename;          struct ccs_path_info rn = { }; /* real name */
580          const u8 mode = r->mode;          struct ccs_path_info ln; /* last name */
         const bool is_enforce = (mode == 3);  
         const u32 tomoyo_flags = r->tomoyo_flags;  
         char *new_domain_name = NULL;  
         char *real_program_name = NULL;  
         char *symlink_program_name = NULL;  
         struct path_info rn; /* real name */  
         struct path_info sn; /* symlink name */  
         struct path_info ln; /* last name */  
581          int retval;          int retval;
582            bool need_kfree = false;
583          {          ln.name = ccs_last_word(old_domain_name);
584                  /*          ccs_fill_path_info(&ln);
585                   * Built-in initializers. This is needed because policies are   retry:
586                   * not loaded until starting /sbin/init.          current->ccs_flags = ccs_flags;
587                   */          r->cond = NULL;
588                  static bool first = true;          if (need_kfree) {
589                  if (first) {                  kfree(rn.name);
590                          update_domain_initializer_entry(NULL, "/sbin/hotplug",                  need_kfree = false;
                                                         false, false);  
                         update_domain_initializer_entry(NULL, "/sbin/modprobe",  
                                                         false, false);  
                         first = false;  
                 }  
591          }          }
592    
593   retry:          /* Get symlink's pathname of program. */
594          current->tomoyo_flags = tomoyo_flags;          retval = ccs_symlink_path(bprm->filename, &rn);
595          r->tomoyo_flags = tomoyo_flags;          if (retval < 0)
         /* Get ccs_realpath of program. */  
         retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */  
         ccs_free(real_program_name);  
         real_program_name = ccs_realpath(original_name);  
         if (!real_program_name)  
                 goto out;  
         /* Get ccs_realpath of symbolic link. */  
         ccs_free(symlink_program_name);  
         symlink_program_name = ccs_realpath_nofollow(original_name);  
         if (!symlink_program_name)  
596                  goto out;                  goto out;
597            need_kfree = true;
         rn.name = real_program_name;  
         ccs_fill_path_info(&rn);  
         sn.name = symlink_program_name;  
         ccs_fill_path_info(&sn);  
         ln.name = ccs_get_last_name(r->domain);  
         ccs_fill_path_info(&ln);  
598    
599          if (handler) {          if (handler) {
600                  if (ccs_pathcmp(&rn, handler)) {                  if (ccs_pathcmp(&rn, handler)) {
# Line 1037  static int find_next_domain(struct ccs_r Line 607  static int find_next_domain(struct ccs_r
607                          }                          }
608                          goto out;                          goto out;
609                  }                  }
610                  goto calculate_domain;          } else {
611          }                  struct ccs_aggregator_entry *ptr;
612                    /* Check 'aggregator' directive. */
613          /* Check 'alias' directive. */                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
         if (ccs_pathcmp(&rn, &sn)) {  
                 struct alias_entry *ptr;  
                 /* Is this program allowed to be called via symbolic links? */  
                 list1_for_each_entry(ptr, &alias_list, list) {  
                         if (ptr->is_deleted ||  
                             ccs_pathcmp(&rn, ptr->original_name) ||  
                             ccs_pathcmp(&sn, ptr->aliased_name))  
                                 continue;  
                         memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);  
                         strncpy(real_program_name, ptr->aliased_name->name,  
                                 CCS_MAX_PATHNAME_LEN - 1);  
                         ccs_fill_path_info(&rn);  
                         break;  
                 }  
         }  
   
         /* Compare basename of real_program_name and argv[0] */  
         r->mode = ccs_check_flags(r->domain, CCS_TOMOYO_MAC_FOR_ARGV0);  
         if (bprm->argc > 0 && r->mode) {  
                 char *base_argv0 = tmp->buffer;  
                 const char *base_filename;  
                 retval = -ENOMEM;  
                 if (!get_argv0(bprm, tmp))  
                         goto out;  
                 base_filename = strrchr(real_program_name, '/');  
                 if (!base_filename)  
                         base_filename = real_program_name;  
                 else  
                         base_filename++;  
                 if (strcmp(base_argv0, base_filename)) {  
                         retval = ccs_check_argv0_perm(r, &rn, base_argv0);  
                         if (retval == 1) {  
                                 r->retry++;  
                                 goto retry;  
                         }  
                         r->retry = 0;  
                         r->tomoyo_flags = current->tomoyo_flags;  
                         if (retval < 0)  
                                 goto out;  
                 }  
         }  
   
         /* Check 'aggregator' directive. */  
         {  
                 struct aggregator_entry *ptr;  
                 /* Is this program allowed to be aggregated? */  
                 list1_for_each_entry(ptr, &aggregator_list, list) {  
614                          if (ptr->is_deleted ||                          if (ptr->is_deleted ||
615                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
616                                  continue;                                  continue;
617                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                          kfree(rn.name);
618                          strncpy(real_program_name, ptr->aggregated_name->name,                          need_kfree = false;
619                                  CCS_MAX_PATHNAME_LEN - 1);                          /* This is OK because it is read only. */
620                          ccs_fill_path_info(&rn);                          rn = *ptr->aggregated_name;
621                          break;                          break;
622                  }                  }
         }  
623    
624          /* Check execute permission. */                  /* Check execute permission. */
625          r->mode = mode;                  retval = ccs_exec_perm(r, &rn);
626          retval = ccs_check_exec_perm(r, &rn);                  if (retval == CCS_RETRY_REQUEST)
627          if (retval == 1) {                          goto retry;
628                  r->retry++;                  if (retval < 0)
629                  goto retry;                          goto out;
630          }          }
         r->retry = 0;  
         r->tomoyo_flags = current->tomoyo_flags;  
         if (retval < 0)  
                 goto out;  
631    
632   calculate_domain:          /* Calculate domain to transit to. */
633          new_domain_name = tmp->buffer;          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
634          if (is_domain_initializer(r->domain->domainname, &rn, &ln)) {                  /* Transit to the child of ccs_kernel_domain domain. */
635                  /* Transit to the child of KERNEL_DOMAIN domain. */                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
636                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                           rn.name);
637                           ROOT_NAME " " "%s", real_program_name);          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
         } else if (r->domain == &KERNEL_DOMAIN && !sbin_init_started) {  
638                  /*                  /*
639                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
640                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
641                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
642                   */                   */
643                  domain = r->domain;                  domain = r->domain;
644          } else if (is_domain_keeper(r->domain->domainname, &rn, &ln)) {          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
645                  /* Keep current domain. */                  /* Keep current domain. */
646                  domain = r->domain;                  domain = r->domain;
647          } else {          } else {
648                  /* Normal domain transition. */                  /* Normal domain transition. */
649                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
650                           "%s %s", old_domain_name, real_program_name);                           old_domain_name, rn.name);
651          }          }
652          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
653                  goto done;                  goto done;
654          domain = ccs_find_domain(new_domain_name);          domain = ccs_find_domain(ee->tmp);
655          if (domain)          if (domain)
656                  goto done;                  goto done;
657          if (is_enforce) {          if (r->mode == CCS_CONFIG_ENFORCING) {
658                  int error = ccs_check_supervisor(r,                  int error = ccs_supervisor(r, "# wants to create domain\n"
659                                                   "# wants to create domain\n"                                             "%s\n", ee->tmp);
660                                                   "%s\n", new_domain_name);                  if (error == CCS_RETRY_REQUEST)
                 if (error == 1) {  
                         r->retry++;  
661                          goto retry;                          goto retry;
                 }  
                 r->retry = 0;  
662                  if (error < 0)                  if (error < 0)
663                          goto done;                          goto done;
664          }          }
665          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);
666          if (domain)          if (domain)
667                  audit_domain_creation_log(domain);                  ccs_audit_domain_creation_log(domain);
668   done:   done:
669          if (!domain) {          if (!domain) {
670                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
671                         new_domain_name);                  if (!r->domain->domain_transition_failed) {
672                  if (is_enforce)                          r->domain->domain_transition_failed = true;
673                          retval = -EPERM;                          ccs_write_audit_log(false, r,
674                  else {                                              CCS_KEYWORD_TRANSITION_FAILED
675                          retval = 0;                                              "\n");
676                          ccs_set_domain_flag(r->domain, false,                          printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
677                                              DOMAIN_FLAGS_TRANSITION_FAILED);                                 ee->tmp);
678                  }                  }
679          } else {          } else {
680                  retval = 0;                  retval = 0;
681          }          }
682   out:   out:
         ccs_free(real_program_name);  
         ccs_free(symlink_program_name);  
683          if (domain)          if (domain)
684                  r->domain = domain;                  r->domain = domain;
685            if (need_kfree)
686                    kfree(rn.name);
687          return retval;          return retval;
688  }  }
689    
690  /**  /**
691   * check_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
692   *   *
693   * @r: Pointer to "struct ccs_request_info".   * @ee: Pointer to "struct ccs_execve_entry".
694   *   *
695   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
696   */   */
697  static int check_environ(struct ccs_request_info *r)  static int ccs_environ(struct ccs_execve_entry *ee)
698  {  {
699          struct linux_binprm *bprm = r->bprm;          struct ccs_request_info *r = &ee->r;
700          struct ccs_page_buffer *tmp = r->obj->tmp;          struct linux_binprm *bprm = ee->bprm;
701          char *arg_ptr = tmp->buffer;          /* env_page->data is allocated by ccs_dump_page(). */
702            struct ccs_page_dump env_page = { };
703            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
704          int arg_len = 0;          int arg_len = 0;
705          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
         int i = pos / PAGE_SIZE;  
706          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
707          int argv_count = bprm->argc;          int argv_count = bprm->argc;
708          int envp_count = bprm->envc;          int envp_count = bprm->envc;
# Line 1196  static int check_environ(struct ccs_requ Line 710  static int check_environ(struct ccs_requ
710          int error = -ENOMEM;          int error = -ENOMEM;
711          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
712                  return 0;                  return 0;
713            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
714            if (!arg_ptr)
715                    goto out;
716          while (error == -ENOMEM) {          while (error == -ENOMEM) {
717                  struct page *page;                  if (!ccs_dump_page(bprm, pos, &env_page))
                 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)  
718                          goto out;                          goto out;
719                  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;  
                 }  
720                  /* Read. */                  /* Read. */
721                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
722                          if (!kaddr[offset++])                          if (!env_page.data[offset++])
723                                  argv_count--;                                  argv_count--;
724                  }                  }
725                  if (argv_count)                  if (argv_count) {
726                          goto unmap_page;                          offset = 0;
727                            continue;
728                    }
729                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
730                          const unsigned char c = kaddr[offset++];                          const unsigned char c = env_page.data[offset++];
731                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
732                                  if (c == '=') {                                  if (c == '=') {
733                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
734                                  } else if (c == '\\') {                                  } else if (c == '\\') {
# Line 1244  static int check_environ(struct ccs_requ Line 748  static int check_environ(struct ccs_requ
748                          }                          }
749                          if (c)                          if (c)
750                                  continue;                                  continue;
751                          if (ccs_check_env_perm(r, arg_ptr)) {                          if (ccs_env_perm(r, arg_ptr)) {
752                                  error = -EPERM;                                  error = -EPERM;
753                                  break;                                  break;
754                          }                          }
# Line 1254  static int check_environ(struct ccs_requ Line 758  static int check_environ(struct ccs_requ
758                          }                          }
759                          arg_len = 0;                          arg_len = 0;
760                  }                  }
  unmap_page:  
                 /* Unmap. */  
                 kunmap(page);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  
                 put_page(page);  
 #endif  
                 i++;  
761                  offset = 0;                  offset = 0;
762          }          }
763   out:   out:
764          if (r->mode != 3)          if (r->mode != 3)
765                  error = 0;                  error = 0;
766            kfree(env_page.data);
767            kfree(arg_ptr);
768          return error;          return error;
769  }  }
770    
771  /**  /**
772   * unescape - Unescape escaped string.   * ccs_unescape - Unescape escaped string.
773   *   *
774   * @dest: String to unescape.   * @dest: String to unescape.
775   *   *
776   * Returns nothing.   * Returns nothing.
777   */   */
778  static void unescape(unsigned char *dest)  static void ccs_unescape(unsigned char *dest)
779  {  {
780          unsigned char *src = dest;          unsigned char *src = dest;
781          unsigned char c;          unsigned char c;
782          unsigned char d;          unsigned char d;
783          unsigned char e;          unsigned char e;
784          while ((c = *src++) != '\0') {          while (1) {
785                    c = *src++;
786                    if (!c)
787                            break;
788                  if (c != '\\') {                  if (c != '\\') {
789                          *dest++ = c;                          *dest++ = c;
790                          continue;                          continue;
# Line 1306  static void unescape(unsigned char *dest Line 808  static void unescape(unsigned char *dest
808  }  }
809    
810  /**  /**
811   * root_depth - Get number of directories to strip.   * ccs_root_depth - Get number of directories to strip.
812   *   *
813   * @dentry: Pointer to "struct dentry".   * @dentry: Pointer to "struct dentry".
814   * @vfsmnt: Pointer to "struct vfsmount".   * @vfsmnt: Pointer to "struct vfsmount".
815   *   *
816   * Returns number of directories to strip.   * Returns number of directories to strip.
817   */   */
818  static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
819  {  {
820          int depth = 0;          int depth = 0;
         /***** CRITICAL SECTION START *****/  
821          ccs_realpath_lock();          ccs_realpath_lock();
822          for (;;) {          for (;;) {
823                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
# Line 1331  static inline int root_depth(struct dent Line 832  static inline int root_depth(struct dent
832                  depth++;                  depth++;
833          }          }
834          ccs_realpath_unlock();          ccs_realpath_unlock();
         /***** CRITICAL SECTION END *****/  
835          return depth;          return depth;
836  }  }
837    
838  /**  /**
839   * get_root_depth - return the depth of root directory.   * ccs_get_root_depth - return the depth of root directory.
840   *   *
841   * Returns number of directories to strip.   * Returns number of directories to strip.
842   */   */
843  static int get_root_depth(void)  static int ccs_get_root_depth(void)
844  {  {
845          int depth;          int depth;
846          struct dentry *dentry;          struct dentry *dentry;
# Line 1348  static int get_root_depth(void) Line 848  static int get_root_depth(void)
848  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
849          struct path root;          struct path root;
850  #endif  #endif
         /***** CRITICAL SECTION START *****/  
851          read_lock(&current->fs->lock);          read_lock(&current->fs->lock);
852  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
853          root = current->fs->root;          root = current->fs->root;
# Line 1360  static int get_root_depth(void) Line 859  static int get_root_depth(void)
859          vfsmnt = mntget(current->fs->rootmnt);          vfsmnt = mntget(current->fs->rootmnt);
860  #endif  #endif
861          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
862          /***** CRITICAL SECTION END *****/          depth = ccs_root_depth(dentry, vfsmnt);
         depth = root_depth(dentry, vfsmnt);  
863  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
864          path_put(&root);          path_put(&root);
865  #else  #else
# Line 1372  static int get_root_depth(void) Line 870  static int get_root_depth(void)
870  }  }
871    
872  /**  /**
873   * try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
874   *   *
875   * @r:           Pointer to "struct ccs_request_info".   * @ee: Pointer to "struct ccs_execve_entry".
  * @handler:     Pointer to the name of execute handler.  
  * @eh_path:     Pointer to pointer to the name of execute handler.  
876   *   *
877   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
878   */   */
879  static int try_alt_exec(struct ccs_request_info *r,  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
                         const struct path_info *handler, char **eh_path)  
880  {  {
881          /*          /*
882           * Contents of modified bprm.           * Contents of modified bprm.
# Line 1397  static int try_alt_exec(struct ccs_reque Line 892  static int try_alt_exec(struct ccs_reque
892           * modified bprm->argv[0]           * modified bprm->argv[0]
893           *    = the program's name specified by execute_handler           *    = the program's name specified by execute_handler
894           * modified bprm->argv[1]           * modified bprm->argv[1]
895           *    = current->domain_info->domainname->name           *    = ccs_current_domain()->domainname->name
896           * modified bprm->argv[2]           * modified bprm->argv[2]
897           *    = the current process's name           *    = the current process's name
898           * modified bprm->argv[3]           * modified bprm->argv[3]
# Line 1419  static int try_alt_exec(struct ccs_reque Line 914  static int try_alt_exec(struct ccs_reque
914           * modified bprm->argv[bprm->envc + bprm->argc + 6]           * modified bprm->argv[bprm->envc + bprm->argc + 6]
915           *     = original bprm->envp[bprm->envc - 1]           *     = original bprm->envp[bprm->envc - 1]
916           */           */
917          struct linux_binprm *bprm = r->bprm;          struct linux_binprm *bprm = ee->bprm;
918          struct file *filp;          struct file *filp;
919          int retval;          int retval;
920          const int original_argc = bprm->argc;          const int original_argc = bprm->argc;
921          const int original_envc = bprm->envc;          const int original_envc = bprm->envc;
922          struct task_struct *task = current;          struct task_struct *task = current;
         char *buffer = r->obj->tmp->buffer;  
         /* Allocate memory for execute handler's pathname. */  
         char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));  
         *eh_path = execute_handler;  
         if (!execute_handler)  
                 return -ENOMEM;  
         strncpy(execute_handler, handler->name,  
                 sizeof(struct ccs_page_buffer) - 1);  
         unescape(execute_handler);  
923    
924          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
925            ee->obj.path1.dentry = NULL;
926            ee->obj.path1.mnt = NULL;
927            ee->obj.validate_done = false;
928          allow_write_access(bprm->file);          allow_write_access(bprm->file);
929          fput(bprm->file);          fput(bprm->file);
930          bprm->file = NULL;          bprm->file = NULL;
931    
932          { /* Adjust root directory for open_exec(). */          /* Invalidate page dump cache. */
933                  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);  
         }  
934    
935          /* Move envp[] to argv[] */          /* Move envp[] to argv[] */
936          bprm->argc += bprm->envc;          bprm->argc += bprm->envc;
# Line 1460  static int try_alt_exec(struct ccs_reque Line 938  static int try_alt_exec(struct ccs_reque
938    
939          /* Set argv[6] */          /* Set argv[6] */
940          {          {
941                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
942                           original_envc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
943                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
944                  if (retval < 0)                  if (retval < 0)
945                          goto out;                          goto out;
946                  bprm->argc++;                  bprm->argc++;
# Line 1470  static int try_alt_exec(struct ccs_reque Line 948  static int try_alt_exec(struct ccs_reque
948    
949          /* Set argv[5] */          /* Set argv[5] */
950          {          {
951                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",                  char *cp = ee->tmp;
952                           original_argc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
953                  retval = copy_strings_kernel(1, &buffer, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
954                  if (retval < 0)                  if (retval < 0)
955                          goto out;                          goto out;
956                  bprm->argc++;                  bprm->argc++;
# Line 1488  static int try_alt_exec(struct ccs_reque Line 966  static int try_alt_exec(struct ccs_reque
966    
967          /* Set argv[3] */          /* Set argv[3] */
968          {          {
969                  const u32 tomoyo_flags = task->tomoyo_flags;                  char *cp = ee->tmp;
970                  snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                  const u32 ccs_flags = task->ccs_flags;
971                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
972                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
973                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
974                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
975                           task->pid, task->uid, task->gid, task->euid,                           (pid_t) ccsecurity_exports.sys_getpid(),
976                           task->egid, task->suid, task->sgid, task->fsuid,                           current_uid(), current_gid(), current_euid(),
977                           task->fsgid, (u8) (tomoyo_flags >> 24),                           current_egid(), current_suid(), current_sgid(),
978                           (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));                           current_fsuid(), current_fsgid(),
979                  retval = copy_strings_kernel(1, &buffer, bprm);                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
980                             (u8) (ccs_flags >> 8));
981                    retval = copy_strings_kernel(1, &cp, bprm);
982                  if (retval < 0)                  if (retval < 0)
983                          goto out;                          goto out;
984                  bprm->argc++;                  bprm->argc++;
# Line 1508  static int try_alt_exec(struct ccs_reque Line 989  static int try_alt_exec(struct ccs_reque
989                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
990                  if (exe) {                  if (exe) {
991                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
992                          ccs_free(exe);                          kfree(exe);
993                  } else {                  } else {
994                          snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,                          exe = ee->tmp;
995                                   "<unknown>");                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
996                          retval = copy_strings_kernel(1, &buffer, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
997                  }                  }
998                  if (retval < 0)                  if (retval < 0)
999                          goto out;                          goto out;
# Line 1521  static int try_alt_exec(struct ccs_reque Line 1002  static int try_alt_exec(struct ccs_reque
1002    
1003          /* Set argv[1] */          /* Set argv[1] */
1004          {          {
1005                  strncpy(buffer, task->domain_info->domainname->name,                  char *cp = ee->tmp;
1006                          sizeof(struct ccs_page_buffer) - 1);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1007                  retval = copy_strings_kernel(1, &buffer, bprm);                           ccs_current_domain()->domainname->name);
1008                    retval = copy_strings_kernel(1, &cp, bprm);
1009                  if (retval < 0)                  if (retval < 0)
1010                          goto out;                          goto out;
1011                  bprm->argc++;                  bprm->argc++;
# Line 1531  static int try_alt_exec(struct ccs_reque Line 1013  static int try_alt_exec(struct ccs_reque
1013    
1014          /* Set argv[0] */          /* Set argv[0] */
1015          {          {
1016                  retval = copy_strings_kernel(1, &execute_handler, bprm);                  int depth = ccs_get_root_depth();
1017                    int len = ee->handler->total_len + 1;
1018                    char *cp = kmalloc(len, CCS_GFP_FLAGS);
1019                    if (!cp) {
1020                            retval = -ENOMEM;
1021                            goto out;
1022                    }
1023                    ee->handler_path = cp;
1024                    memmove(cp, ee->handler->name, len);
1025                    ccs_unescape(cp);
1026                    retval = -ENOENT;
1027                    if (!*cp || *cp != '/')
1028                            goto out;
1029                    /* Adjust root directory for open_exec(). */
1030                    while (depth) {
1031                            cp = strchr(cp + 1, '/');
1032                            if (!cp)
1033                                    goto out;
1034                            depth--;
1035                    }
1036                    memmove(ee->handler_path, cp, strlen(cp) + 1);
1037                    cp = ee->handler_path;
1038                    retval = copy_strings_kernel(1, &cp, bprm);
1039                  if (retval < 0)                  if (retval < 0)
1040                          goto out;                          goto out;
1041                  bprm->argc++;                  bprm->argc++;
# Line 1543  static int try_alt_exec(struct ccs_reque Line 1047  static int try_alt_exec(struct ccs_reque
1047  #endif  #endif
1048    
1049          /* OK, now restart the process with execute handler program's dentry. */          /* OK, now restart the process with execute handler program's dentry. */
1050          filp = open_exec(execute_handler);          filp = open_exec(ee->handler_path);
1051          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1052                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1053                  goto out;                  goto out;
1054          }          }
1055            ee->obj.path1.dentry = filp->f_dentry;
1056            ee->obj.path1.mnt = filp->f_vfsmnt;
1057          bprm->file = filp;          bprm->file = filp;
1058          bprm->filename = execute_handler;          bprm->filename = ee->handler_path;
1059  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1060          bprm->interp = execute_handler;          bprm->interp = bprm->filename;
1061  #endif  #endif
1062          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1063          if (retval < 0)          if (retval < 0)
1064                  goto out;                  goto out;
1065          task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1066          retval = find_next_domain(r, handler);          retval = ccs_find_next_domain(ee);
1067          task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;          task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1068   out:   out:
1069          return retval;          return retval;
1070  }  }
1071    
1072  /**  /**
1073   * find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1074   *   *
1075     * @ee:   Pointer to "struct ccs_execve_entry".
1076   * @type: Type of execute handler.   * @type: Type of execute handler.
1077   *   *
1078   * Returns pointer to "struct path_info" if found, NULL otherwise.   * Returns true if found, false otherwise.
1079     *
1080     * Caller holds ccs_read_lock().
1081   */   */
1082  static const struct path_info *find_execute_handler(const u8 type)  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1083                                         const u8 type)
1084  {  {
1085          struct task_struct *task = current;          struct task_struct *task = current;
1086          const struct domain_info *domain = task->domain_info;          const struct ccs_domain_info *domain = ccs_current_domain();
1087          struct acl_info *ptr;          struct ccs_acl_info *ptr;
1088            bool found = false;
1089          /*          /*
1090           * Don't use execute handler if the current process is           * Don't use execute handler if the current process is
1091           * marked as execute handler to avoid infinite execute handler loop.           * marked as execute handler to avoid infinite execute handler loop.
1092           */           */
1093          if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1094                  return NULL;                  return false;
1095          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry(ptr, &domain->acl_info_list, list) {
1096                  struct execute_handler_record *acl;                  struct ccs_execute_handler_record *acl;
1097                  if (ptr->type != type)                  if (ptr->type != type)
1098                          continue;                          continue;
1099                  acl = container_of(ptr, struct execute_handler_record, head);                  acl = container_of(ptr, struct ccs_execute_handler_record,
1100                  return acl->handler;                                     head);
1101                    ee->handler = acl->handler;
1102                    found = true;
1103                    break;
1104          }          }
1105          return NULL;          return found;
1106  }  }
1107    
 /* List of next_domain which is used for checking interpreter's permissions. */  
 struct execve_entry {  
         struct list_head list;  
         struct task_struct *task;  
         struct domain_info *next_domain;  
 };  
   
 static LIST_HEAD(execve_list);  
 static DEFINE_SPINLOCK(execve_list_lock);  
   
1108  /**  /**
1109   * ccs_register_next_domain - Remember next_domain.   * ccs_dump_page - Dump a page to buffer.
  *  
  * @next_domain: Pointer to "struct domain_info".  
1110   *   *
1111   * Returns 0 on success, -ENOMEM otherwise.   * @bprm: Pointer to "struct linux_binprm".
1112   */   * @pos:  Location to dump.
1113  static int ccs_register_next_domain(struct domain_info *next_domain)   * @dump: Poiner to "struct ccs_page_dump".
 {  
         struct execve_entry *ee = kmalloc(sizeof(*ee), GFP_KERNEL);  
         if (!ee)  
                 return -ENOMEM;  
         ee->task = current;  
         ee->next_domain = next_domain;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&execve_list_lock);  
         list_add(&ee->list, &execve_list);  
         spin_unlock(&execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         return 0;  
 }  
   
 /**  
  * ccs_fetch_next_domain - Fetch next_domain from the list.  
1114   *   *
1115   * Returns pointer to "struct domain_info" which will be used if execve()   * Returns true on success, false otherwise.
  * succeeds. This function does not return NULL.  
1116   */   */
1117  struct domain_info *ccs_fetch_next_domain(void)  bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1118                       struct ccs_page_dump *dump)
1119  {  {
1120          struct task_struct *task = current;          struct page *page;
1121          struct domain_info *next_domain = task->domain_info;          /* dump->data is released by ccs_finish_execve(). */
1122          struct execve_entry *p;          if (!dump->data) {
1123          /***** CRITICAL SECTION START *****/                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1124          spin_lock(&execve_list_lock);                  if (!dump->data)
1125          list_for_each_entry(p, &execve_list, list) {                          return false;
                 if (p->task != task)  
                         continue;  
                 next_domain = p->next_domain;  
                 break;  
1126          }          }
1127          spin_unlock(&execve_list_lock);          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1128          /***** CRITICAL SECTION END *****/  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1129          return next_domain;          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1130  }                  return false;
1131    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1132  /**          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1133   * ccs_unregister_next_domain - Forget next_domain.                  return false;
1134   */  #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1135  static void ccs_unregister_next_domain(void)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1136  {                  return false;
1137          struct task_struct *task = current;  #else
1138          struct execve_entry *p;          page = bprm->page[pos / PAGE_SIZE];
1139          struct execve_entry *ee = NULL;  #endif
1140          /***** CRITICAL SECTION START *****/          if (page != dump->page) {
1141          spin_lock(&execve_list_lock);                  const unsigned int offset = pos % PAGE_SIZE;
1142          list_for_each_entry(p, &execve_list, list) {                  /*
1143                  if (p->task != task)                   * Maybe kmap()/kunmap() should be used here.
1144                          continue;                   * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1145                  list_del(&p->list);                   * So do I.
1146                  ee = p;                   */
1147                  break;                  char *kaddr = kmap_atomic(page, KM_USER0);
1148                    dump->page = page;
1149                    memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1150                    kunmap_atomic(kaddr, KM_USER0);
1151          }          }
1152          spin_unlock(&execve_list_lock);          /* Same with put_arg_page(page) in fs/exec.c */
1153          /***** CRITICAL SECTION END *****/  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1154          kfree(ee);          put_page(page);
1155    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1156            put_page(page);
1157    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1158            put_page(page);
1159    #endif
1160            return true;
1161  }  }
1162    
1163  /**  /**
1164   * search_binary_handler_with_transition - Perform domain transition.   * ccs_start_execve - Prepare for execve() operation.
1165   *   *
1166   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1167   * @regs: Pointer to "struct pt_regs".   * @eep:  Pointer to "struct ccs_execve_entry *".
1168   *   *
1169   * Returns result of search_binary_handler() on success,   * Returns 0 on success, negative value otherwise.
  * negative value otherwise.  
1170   */   */
1171  int search_binary_handler_with_transition(struct linux_binprm *bprm,  static int ccs_start_execve(struct linux_binprm *bprm,
1172                                            struct pt_regs *regs)                              struct ccs_execve_entry **eep)
1173  {  {
1174          int retval;          int retval;
1175          struct task_struct *task = current;          struct task_struct *task = current;
1176          const struct path_info *handler;          struct ccs_execve_entry *ee;
1177          struct ccs_request_info r;          *eep = NULL;
1178          struct obj_info obj;          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1179          /*          if (!ee)
          * "eh_path" holds path to execute handler program.  
          * Thus, keep valid until search_binary_handler() finishes.  
          */  
         char *eh_path = NULL;  
         struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));  
         memset(&obj, 0, sizeof(obj));  
         if (!sbin_init_started)  
                 ccs_load_policy(bprm->filename);  
         if (!tmp)  
1180                  return -ENOMEM;                  return -ENOMEM;
1181            ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1182          ccs_init_request_info(&r, NULL, CCS_TOMOYO_MAC_FOR_FILE);          if (!ee->tmp) {
1183          r.bprm = bprm;                  kfree(ee);
1184          r.obj = &obj;                  return -ENOMEM;
1185          obj.path1_dentry = bprm->file->f_dentry;          }
1186          obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->reader_idx = ccs_read_lock();
1187          obj.tmp = tmp;          /* ee->dump->data is allocated by ccs_dump_page(). */
1188            ee->previous_domain = task->ccs_domain_info;
1189          /* Clear manager flag. */          /* Clear manager flag. */
1190          task->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1191          handler = find_execute_handler(TYPE_EXECUTE_HANDLER);          *eep = ee;
1192          if (handler) {          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);
1193                  retval = try_alt_exec(&r, handler, &eh_path);          ee->r.ee = ee;
1194            ee->bprm = bprm;
1195            ee->r.obj = &ee->obj;
1196            ee->obj.path1.dentry = bprm->file->f_dentry;
1197            ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1198            if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {
1199                    retval = ccs_try_alt_exec(ee);
1200                  if (!retval)                  if (!retval)
1201                          audit_execute_handler_log(true, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, true);
1202                  goto ok;                  goto ok;
1203          }          }
1204          retval = find_next_domain(&r, NULL);          retval = ccs_find_next_domain(ee);
1205          if (retval != -EPERM)          if (retval != -EPERM)
1206                  goto ok;                  goto ok;
1207          handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1208          if (handler) {                  retval = ccs_try_alt_exec(ee);
                 retval = try_alt_exec(&r, handler, &eh_path);  
1209                  if (!retval)                  if (!retval)
1210                          audit_execute_handler_log(false, handler->name, bprm);                          ccs_audit_execute_handler_log(ee, false);
1211          }          }
1212   ok:   ok:
1213          if (retval < 0)          if (retval < 0)
1214                  goto out;                  goto out;
1215          r.mode = ccs_check_flags(r.domain, CCS_TOMOYO_MAC_FOR_ENV);          /*
1216          retval = check_environ(&r);           * Tell GC that I started execve().
1217          if (retval < 0)           * Also, tell open_exec() to check read permission.
1218                  goto out;           */
1219          retval = ccs_register_next_domain(r.domain);          task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
1220          if (retval < 0)          /*
1221                  goto out;           * Make task->ccs_flags visible to GC before changing
1222          task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;           * task->ccs_domain_info .
1223          retval = search_binary_handler(bprm, regs);           */
1224          task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;          smp_mb();
1225            /*
1226             * Proceed to the next domain in order to allow reaching via PID.
1227             * It will be reverted if execve() failed. Reverting is not good.
1228             * But it is better than being unable to reach via PID in interactive
1229             * enforcing mode.
1230             */
1231            task->ccs_domain_info = ee->r.domain;
1232            ee->r.mode = ccs_get_mode(ee->r.domain->profile, CCS_MAC_ENVIRON);
1233            retval = ccs_environ(ee);
1234          if (retval < 0)          if (retval < 0)
1235                  goto out;                  goto out;
1236          /* Proceed to next domain if execution suceeded. */          retval = 0;
         task->domain_info = r.domain;  
         mb(); /* Make domain transition visible to other CPUs. */  
         /* Mark the current process as execute handler. */  
         if (handler)  
                 task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;  
         /* Mark the current process as normal process. */  
         else  
                 task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;  
1237   out:   out:
         ccs_unregister_next_domain();  
         ccs_free(eh_path);  
         ccs_free(tmp);  
1238          return retval;          return retval;
1239  }  }
1240    
1241  #else  /**
1242     * ccs_finish_execve - Clean up execve() operation.
1243     *
1244     * @retval: Return code of an execve() operation.
1245     * @ee:     Pointer to "struct ccs_execve_entry".
1246     *
1247     * Caller holds ccs_read_lock().
1248     */
1249    static void ccs_finish_execve(int retval, struct ccs_execve_entry *ee)
1250    {
1251            struct task_struct *task = current;
1252            if (!ee)
1253                    return;
1254            if (retval < 0) {
1255                    task->ccs_domain_info = ee->previous_domain;
1256                    /*
1257                     * Make task->ccs_domain_info visible to GC before changing
1258                     * task->ccs_flags .
1259                     */
1260                    smp_mb();
1261            } else {
1262                    /* Mark the current process as execute handler. */
1263                    if (ee->handler)
1264                            task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1265                    /* Mark the current process as normal process. */
1266                    else
1267                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1268            }
1269            /* Tell GC that I finished execve(). */
1270            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1271            ccs_read_unlock(ee->reader_idx);
1272            kfree(ee->handler_path);
1273            kfree(ee->tmp);
1274            kfree(ee->dump.data);
1275            kfree(ee);
1276    }
1277    
1278  /**  /**
1279   * search_binary_handler_with_transition - Wrapper for search_binary_handler().   * ccs_may_transit - Check permission and do domain transition without execve().
1280   *   *
1281   * @bprm: Pointer to "struct linux_binprm".   * @domainname: Domainname to transit to.
1282   * @regs: Pointer to "struct pt_regs".   * @pathname: Pathname to check.
1283   *   *
1284   * Returns the result of search_binary_handler().   * Returns 0 on success, negative value otherwise.
1285     *
1286     * Caller holds ccs_read_lock().
1287   */   */
1288  int search_binary_handler_with_transition(struct linux_binprm *bprm,  int ccs_may_transit(const char *domainname, const char *pathname)
                                           struct pt_regs *regs)  
1289  {  {
1290  #ifdef CONFIG_SAKURA          struct ccs_path_info name;
1291          /* Clear manager flag. */          struct ccs_request_info r;
1292          current->tomoyo_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          struct ccs_domain_info *domain;
1293          ccs_load_policy(bprm->filename);          int error;
1294  #endif          name.name = pathname;
1295          return search_binary_handler(bprm, regs);          ccs_fill_path_info(&name);
1296            /* Check allow_transit permission. */
1297            ccs_init_request_info(&r, NULL, CCS_MAC_FILE_TRANSIT);
1298            error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1299            if (error)
1300                    return error;
1301            /* Check destination domain. */
1302            domain = ccs_find_domain(domainname);
1303            if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1304                strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1305                    domain = ccs_find_or_assign_new_domain(domainname, r.profile);
1306                    if (domain)
1307                            ccs_audit_domain_creation_log(domain);
1308            }
1309            if (domain) {
1310                    error = 0;
1311                    current->ccs_domain_info = domain;
1312            } else {
1313                    error = -ENOENT;
1314            }
1315            return error;
1316  }  }
1317    
1318  #endif  static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1319                                           struct pt_regs *regs)
1320    {
1321            struct ccs_execve_entry *ee;
1322            int retval;
1323            if (!ccs_policy_loaded)
1324                    ccsecurity_exports.load_policy(bprm->filename);
1325            retval = ccs_start_execve(bprm, &ee);
1326            if (!retval)
1327                    retval = search_binary_handler(bprm, regs);
1328            ccs_finish_execve(retval, ee);
1329            return retval;
1330    }
1331    
1332    void __init ccs_domain_init(void)
1333    {
1334            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1335    }

Legend:
Removed from v.1700  
changed lines
  Added in v.3538

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