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

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

Legend:
Removed from v.1012  
changed lines
  Added in v.2539

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