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

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

Legend:
Removed from v.851  
changed lines
  Added in v.2308

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