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

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

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

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