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

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 502 by kumaneko, Tue Sep 25 13:33:45 2007 UTC trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c revision 2393 by kumaneko, Mon Apr 6 05:24:05 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-2007  NTT DATA CORPORATION   * Copyright (C) 2005-2009  NTT DATA CORPORATION
7   *   *
8   * Version: 1.5.0   2007/09/20   * Version: 1.6.7   2009/04/01
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 = { NULL, NULL, NULL, 0, 0, 0 };  struct ccs_domain_info ccs_kernel_domain;
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  DECLARE_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 domain_initializer_entry *next;  struct ccs_domain_initializer_entry {
44          const struct path_info *domainname;    /* This may be NULL */          struct list1_head list;
45          const struct path_info *program;          const struct ccs_path_info *domainname;    /* This may be NULL */
46          u8 is_deleted;          const struct ccs_path_info *program;
47          u8 is_not;          bool is_deleted;
48          u8 is_last_name;          bool is_not;       /* True if this entry is "no_initialize_domain".  */
49            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 {
54  struct domain_keeper_entry {          struct list1_head list;
55          struct domain_keeper_entry *next;          const struct ccs_path_info *domainname;
56          const struct path_info *domainname;          const struct ccs_path_info *program;       /* This may be NULL */
57          const struct path_info *program;       /* This may be NULL */          bool is_deleted;
58          u8 is_deleted;          bool is_not;       /* True if this entry is "no_keep_domain".        */
59          u8 is_not;          bool is_last_name; /* True if the domainname is ccs_get_last_name(). */
         u8 is_last_name;  
60  };  };
61    
62  /***** The structure for program files that should be aggregated. *****/  /* Structure for "aggregator" keyword. */
63    struct ccs_aggregator_entry {
64  struct aggregator_entry {          struct list1_head list;
65          struct aggregator_entry *next;          const struct ccs_path_info *original_name;
66          const struct path_info *original_name;          const struct ccs_path_info *aggregated_name;
67          const struct path_info *aggregated_name;          bool is_deleted;
         int is_deleted;  
68  };  };
69    
70  /***** The structure for program files that should be aliased. *****/  /* Structure for "alias" keyword. */
71    struct ccs_alias_entry {
72  struct alias_entry {          struct list1_head list;
73          struct alias_entry *next;          const struct ccs_path_info *original_name;
74          const struct path_info *original_name;          const struct ccs_path_info *aliased_name;
75          const struct path_info *aliased_name;          bool is_deleted;
         int is_deleted;  
76  };  };
77    
78  /*************************  VARIABLES  *************************/  /**
79     * ccs_set_domain_flag - Set or clear domain's attribute flags.
80  /* Domain creation lock. */   *
81  static DECLARE_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 acl_info *ptr, struct domain_info *domain, struct acl_info *new_ptr)  /**
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          mb(); /* Instead of using spinlock. */          if (domain) {
129          if (!ptr) domain->first_acl_ptr = (struct acl_info *) new_ptr;                  /*
130          else ptr->next = (struct acl_info *) new_ptr;                   * We need to serialize because this function is called by
131          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);                   * 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  int TooManyDomainACL(struct domain_info * const domain) {  /**
162          unsigned int count = 0;   * ccs_audit_execute_handler_log - Audit execute_handler log.
163          struct acl_info *ptr;   *
164          for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {   * @ee:         Pointer to "struct ccs_execve_entry".
165                  if (!ptr->is_deleted) count++;   * @is_default: True if it is "execute_handler" log.
166          }   *
167          /* If there are so many entries, don't append if learning mode. */   * Returns 0 on success, negative value otherwise.
168          if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 0;   */
169          if (!domain->quota_warned) {  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
170                  printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);                                           const bool is_default)
171                  domain->quota_warned = 1;  {
172          }          struct ccs_request_info *r = &ee->r;
173          return 1;          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    /**
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  /*************************  DOMAIN INITIALIZER HANDLER  *************************/  /* The list for "struct ccs_domain_initializer_entry". */
195    static LIST1_HEAD(ccs_domain_initializer_list);
 static struct domain_initializer_entry *domain_initializer_list = NULL;  
196    
197  static int AddDomainInitializerEntry(const char *domainname, const char *program, const int is_not, const int is_delete)  /**
198  {   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
199          struct domain_initializer_entry *new_entry, *ptr;   *
200          static DECLARE_MUTEX(lock);   * @domainname: The name of domain. May be NULL.
201          const struct path_info *saved_program, *saved_domainname = NULL;   * @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 ccs_domain_initializer_entry *new_entry;
213            struct ccs_domain_initializer_entry *ptr;
214            static DEFINE_MUTEX(lock);
215            const struct ccs_path_info *saved_program;
216            const struct ccs_path_info *saved_domainname = NULL;
217          int error = -ENOMEM;          int error = -ENOMEM;
218          int 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          down(&lock);          saved_program = ccs_save_name(program);
232          for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {          if (!saved_program)
233                  if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {                  return -ENOMEM;
234                          ptr->is_deleted = is_delete;          mutex_lock(&lock);
235                          error = 0;          list1_for_each_entry(ptr, &ccs_domain_initializer_list, list) {
236                          goto out;                  if (ptr->is_not != is_not ||
237                  }                      ptr->domainname != saved_domainname ||
238                        ptr->program != saved_program)
239                            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          mb(); /* Instead of using spinlock. */          list1_add_tail_mb(&new_entry->list, &ccs_domain_initializer_list);
         if ((ptr = domain_initializer_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 domain_initializer_list = new_entry;  
         }  
256          error = 0;          error = 0;
257   out:   out:
258          up(&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 domain_initializer_entry *ptr = head->read_var2;          struct list1_head *pos;
273          if (!ptr) ptr = domain_initializer_list;          list1_for_each_cookie(pos, head->read_var2,
274          while (ptr) {                                &ccs_domain_initializer_list) {
275                  head->read_var2 = ptr;                  const char *no;
276                  if (!ptr->is_deleted) {                  const char *from = "";
277                          if (ptr->domainname) {                  const char *domain = "";
278                                  if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;                  struct ccs_domain_initializer_entry *ptr;
279                          } else {                  ptr = list1_entry(pos, struct ccs_domain_initializer_entry,
280                                  if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->program->name)) break;                                    list);
281                          }                  if (ptr->is_deleted)
282                            continue;
283                    no = ptr->is_not ? "no_" : "";
284                    if (ptr->domainname) {
285                            from = " from ";
286                            domain = ptr->domainname->name;
287                  }                  }
288                  ptr = ptr->next;                  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 ptr ? -ENOMEM : 0;          return true;
294     out:
295            return false;
296  }  }
297    
298  int AddDomainInitializerPolicy(char *data, const int is_not, const int 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 int 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          int flag = 0;   * @domainname: The name of domain.
324          for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {   * @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 struct domain_keeper_entry *domain_keeper_list = NULL;  
359    
360  static int AddDomainKeeperEntry(const char *domainname, const char *program, const int is_not, const int 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          static DECLARE_MUTEX(lock);   * @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);
380          int error = -ENOMEM;          int error = -ENOMEM;
381          int 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          down(&lock);                          return -ENOMEM;
393          for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {          }
394                  if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {          saved_domainname = ccs_save_name(domainname);
395                          ptr->is_deleted = is_delete;          if (!saved_domainname)
396                          error = 0;                  return -ENOMEM;
397                          goto out;          mutex_lock(&lock);
398                  }          list1_for_each_entry(ptr, &ccs_domain_keeper_list, list) {
399                    if (ptr->is_not != is_not ||
400                        ptr->domainname != saved_domainname ||
401                        ptr->program != saved_program)
402                            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          mb(); /* Instead of using spinlock. */          list1_add_tail_mb(&new_entry->list, &ccs_domain_keeper_list);
         if ((ptr = domain_keeper_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 domain_keeper_list = new_entry;  
         }  
419          error = 0;          error = 0;
420   out:   out:
421          up(&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 int is_not, const int 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 domain_keeper_entry *ptr = head->read_var2;          struct list1_head *pos;
456          if (!ptr) ptr = domain_keeper_list;          list1_for_each_cookie(pos, head->read_var2, &ccs_domain_keeper_list) {
457          while (ptr) {                  struct ccs_domain_keeper_entry *ptr;
458                  head->read_var2 = ptr;                  const char *no;
459                  if (!ptr->is_deleted) {                  const char *from = "";
460                          if (ptr->program) {                  const char *program = "";
461                                  if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;                  ptr = list1_entry(pos, struct ccs_domain_keeper_entry, list);
462                          } else {                  if (ptr->is_deleted)
463                                  if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->domainname->name)) break;                          continue;
464                          }                  no = ptr->is_not ? "no_" : "";
465                    if (ptr->program) {
466                            from = " from ";
467                            program = ptr->program->name;
468                  }                  }
469                  ptr = ptr->next;                  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 ptr ? -ENOMEM : 0;          return true;
475     out:
476            return false;
477  }  }
478    
479  static int 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          int flag = 0;   * @domainname: The name of domain.
483          for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {   * @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);
516    
517  static struct alias_entry *alias_list = NULL;  /**
518     * ccs_update_alias_entry - Update "struct ccs_alias_entry" list.
519  static int AddAliasEntry(const char *original_name, const char *aliased_name, const int is_delete)   *
520  {   * @original_name: The original program's real name.
521          struct alias_entry *new_entry, *ptr;   * @aliased_name:  The symbolic program's symbolic link's name.
522          static DECLARE_MUTEX(lock);   * @is_delete:     True if it is a delete request.
523          const struct path_info *saved_original_name, *saved_aliased_name;   *
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 ccs_alias_entry *new_entry;
531            struct ccs_alias_entry *ptr;
532            static DEFINE_MUTEX(lock);
533            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          down(&lock);                  return -EINVAL; /* No patterns allowed. */
539          for (ptr = alias_list; ptr; ptr = ptr->next) {          saved_original_name = ccs_save_name(original_name);
540                  if (ptr->original_name == saved_original_name && ptr->aliased_name == saved_aliased_name) {          saved_aliased_name = ccs_save_name(aliased_name);
541                          ptr->is_deleted = is_delete;          if (!saved_original_name || !saved_aliased_name)
542                          error = 0;                  return -ENOMEM;
543                          goto out;          mutex_lock(&lock);
544                  }          list1_for_each_entry(ptr, &ccs_alias_list, list) {
545                    if (ptr->original_name != saved_original_name ||
546                        ptr->aliased_name != saved_aliased_name)
547                            continue;
548                    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          mb(); /* Instead of using spinlock. */          list1_add_tail_mb(&new_entry->list, &ccs_alias_list);
         if ((ptr = alias_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 alias_list = new_entry;  
         }  
562          error = 0;          error = 0;
563   out:   out:
564          up(&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 alias_entry *ptr = head->read_var2;          struct list1_head *pos;
579          if (!ptr) ptr = alias_list;          list1_for_each_cookie(pos, head->read_var2, &ccs_alias_list) {
580          while (ptr) {                  struct ccs_alias_entry *ptr;
581                  head->read_var2 = ptr;                  ptr = list1_entry(pos, struct ccs_alias_entry, list);
582                  if (!ptr->is_deleted && io_printf(head, KEYWORD_ALIAS "%s %s\n", ptr->original_name->name, ptr->aliased_name->name)) break;                  if (ptr->is_deleted)
583                  ptr = ptr->next;                          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 ptr ? -ENOMEM : 0;          return true;
590     out:
591            return false;
592  }  }
593    
594  int AddAliasPolicy(char *data, const int 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 struct aggregator_entry *aggregator_list = NULL;  
613    
614  static int AddAggregatorEntry(const char *original_name, const char *aggregated_name, const int is_delete)  /**
615  {   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
616          struct aggregator_entry *new_entry, *ptr;   *
617          static DECLARE_MUTEX(lock);   * @original_name:   The original program's name.
618          const struct path_info *saved_original_name, *saved_aggregated_name;   * @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 ccs_aggregator_entry *new_entry;
628            struct ccs_aggregator_entry *ptr;
629            static DEFINE_MUTEX(lock);
630            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          down(&lock);                  return -EINVAL;
636          for (ptr = aggregator_list; ptr; ptr = ptr->next) {          saved_original_name = ccs_save_name(original_name);
637                  if (ptr->original_name == saved_original_name && ptr->aggregated_name == saved_aggregated_name) {          saved_aggregated_name = ccs_save_name(aggregated_name);
638                          ptr->is_deleted = is_delete;          if (!saved_original_name || !saved_aggregated_name)
639                          error = 0;                  return -ENOMEM;
640                          goto out;          mutex_lock(&lock);
641                  }          list1_for_each_entry(ptr, &ccs_aggregator_list, list) {
642                    if (ptr->original_name != saved_original_name ||
643                        ptr->aggregated_name != saved_aggregated_name)
644                            continue;
645                    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          mb(); /* Instead of using spinlock. */          list1_add_tail_mb(&new_entry->list, &ccs_aggregator_list);
         if ((ptr = aggregator_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 aggregator_list = new_entry;  
         }  
659          error = 0;          error = 0;
660   out:   out:
661          up(&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 aggregator_entry *ptr = head->read_var2;          struct list1_head *pos;
676          if (!ptr) ptr = aggregator_list;          list1_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
677          while (ptr) {                  struct ccs_aggregator_entry *ptr;
678                  head->read_var2 = ptr;                  ptr = list1_entry(pos, struct ccs_aggregator_entry, list);
679                  if (!ptr->is_deleted && io_printf(head, KEYWORD_AGGREGATOR "%s %s\n", ptr->original_name->name, ptr->aggregated_name->name)) break;                  if (ptr->is_deleted)
680                  ptr = ptr->next;                          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 ptr ? -ENOMEM : 0;          return true;
687     out:
688            return false;
689  }  }
690    
691  int AddAggregatorPolicy(char *data, const int 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 handler. */
709    
710  /* #define DEBUG_DOMAIN_UNDELETE */  /**
711     * ccs_delete_domain - Delete a domain.
712  int DeleteDomain(char *domainname0)   *
713     * @domainname: The name of domain.
714     *
715     * Returns 0.
716     */
717    int ccs_delete_domain(char *domainname)
718  {  {
719          struct domain_info *domain;          struct ccs_domain_info *domain;
720          struct path_info domainname;          struct ccs_path_info name;
721          domainname.name = domainname0;          name.name = domainname;
722          fill_path_info(&domainname);          ccs_fill_path_info(&name);
723          down(&new_domain_assign_lock);          mutex_lock(&ccs_domain_list_lock);
 #ifdef DEBUG_DOMAIN_UNDELETE  
         printk("DeleteDomain %s\n", domainname0);  
         for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {  
                 if (pathcmp(domain->domainname, &domainname)) continue;  
                 printk("List: %p %u\n", domain, domain->is_deleted);  
         }  
 #endif  
724          /* Is there an active domain? */          /* Is there an active domain? */
725          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) { /* Never delete KERNEL_DOMAIN */          list1_for_each_entry(domain, &ccs_domain_list, list) {
726                  if (domain->is_deleted || pathcmp(domain->domainname, &domainname)) continue;                  /* Never delete ccs_kernel_domain */
727                    if (domain == &ccs_kernel_domain)
728                            continue;
729                    if (domain->is_deleted ||
730                        ccs_pathcmp(domain->domainname, &name))
731                            continue;
732                    domain->is_deleted = true;
733                  break;                  break;
734          }          }
735          if (domain) {          mutex_unlock(&ccs_domain_list_lock);
                 struct domain_info *domain2;  
                 /* Mark already deleted domains as non undeletable. */  
                 for (domain2 = KERNEL_DOMAIN.next; domain2; domain2 = domain2->next) {  
                         if (!domain2->is_deleted || pathcmp(domain2->domainname, &domainname)) continue;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                         if (domain2->is_deleted != 255) printk("Marked %p as non undeletable\n", domain2);  
 #endif  
                         domain2->is_deleted = 255;  
                 }  
                 /* Delete and mark active domain as undeletable. */  
                 domain->is_deleted = 1;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk("Marked %p as undeletable\n", domain);  
 #endif  
         }  
         up(&new_domain_assign_lock);  
736          return 0;          return 0;
737  }  }
738    
739  struct domain_info *UndeleteDomain(const char *domainname0)  /**
740  {   * ccs_find_or_assign_new_domain - Create a domain.
741          struct domain_info *domain, *candidate_domain = NULL;   *
742          struct path_info domainname;   * @domainname: The name of domain.
743          domainname.name = domainname0;   * @profile:    Profile number to assign if the domain was newly created.
744          fill_path_info(&domainname);   *
745          down(&new_domain_assign_lock);   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
746  #ifdef DEBUG_DOMAIN_UNDELETE   */
747          printk("UndeleteDomain %s\n", domainname0);  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
748          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {                                                    const u8 profile)
                 if (pathcmp(domain->domainname, &domainname)) continue;  
                 printk("List: %p %u\n", domain, domain->is_deleted);  
         }  
 #endif  
         for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {  
                 if (pathcmp(&domainname, domain->domainname)) continue;  
                 if (!domain->is_deleted) {  
                         /* This domain is active. I can't undelete. */  
                         candidate_domain = NULL;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                         printk("%p is active. I can't undelete.\n", domain);  
 #endif  
                         break;  
                 }  
                 /* Is this domain undeletable? */  
                 if (domain->is_deleted == 1) candidate_domain = domain;  
         }  
         if (candidate_domain) {  
                 candidate_domain->is_deleted = 0;  
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk("%p was undeleted.\n", candidate_domain);  
 #endif  
         }  
         up(&new_domain_assign_lock);  
         return candidate_domain;  
 }  
   
 /*************************  DOMAIN TRANSITION HANDLER  *************************/  
   
 struct domain_info *FindOrAssignNewDomain(const char *domainname, const u8 profile)  
749  {  {
750          struct domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
751          const struct path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
752          down(&new_domain_assign_lock);          mutex_lock(&ccs_domain_list_lock);
753          if ((domain = FindDomain(domainname)) != NULL) goto out;          domain = ccs_find_domain(domainname);
754          if (!IsCorrectDomain(domainname, __FUNCTION__)) goto out;          if (domain)
755          if ((saved_domainname = SaveName(domainname)) == NULL) goto out;                  goto out;
756            if (!ccs_is_correct_domain(domainname, __func__))
757                    goto out;
758            saved_domainname = ccs_save_name(domainname);
759            if (!saved_domainname)
760                    goto out;
761          /* Can I reuse memory of deleted domain? */          /* Can I reuse memory of deleted domain? */
762          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {          list1_for_each_entry(domain, &ccs_domain_list, list) {
763                  struct task_struct *p;                  struct task_struct *p;
764                  struct acl_info *ptr;                  struct ccs_acl_info *ptr;
765                  int flag;                  bool flag;
766                  if (!domain->is_deleted || domain->domainname != saved_domainname) continue;                  if (!domain->is_deleted ||
767                  flag = 0;                      domain->domainname != saved_domainname)
768                            continue;
769                    flag = false;
770                  /***** CRITICAL SECTION START *****/                  /***** CRITICAL SECTION START *****/
771                  read_lock(&tasklist_lock);                  read_lock(&tasklist_lock);
772                  for_each_process(p) {                  for_each_process(p) {
773                          if (p->domain_info == domain) { flag = 1; break; }                          if (ccs_task_domain(p) != domain)
774                                    continue;
775                            flag = true;
776                            break;
777                  }                  }
778                  read_unlock(&tasklist_lock);                  read_unlock(&tasklist_lock);
779                  /***** CRITICAL SECTION END *****/                  /***** CRITICAL SECTION END *****/
780                  if (flag) continue;                  if (flag)
781  #ifdef DEBUG_DOMAIN_UNDELETE                          continue;
782                  printk("Reusing %p %s\n", domain, domain->domainname->name);                  list1_for_each_entry(ptr, &domain->acl_info_list, list) {
783  #endif                          ptr->type |= ACL_DELETED;
784                  for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) ptr->is_deleted = 1;                  }
785                    ccs_set_domain_flag(domain, true, domain->flags);
786                  domain->profile = profile;                  domain->profile = profile;
787                  domain->quota_warned = 0;                  domain->quota_warned = false;
788                  mb(); /* Instead of using spinlock. */                  mb(); /* Avoid out-of-order execution. */
789                  domain->is_deleted = 0;                  domain->is_deleted = false;
790                  goto out;                  goto out;
791          }          }
792          /* No memory reusable. Create using new memory. */          /* No memory reusable. Create using new memory. */
793          if ((domain = alloc_element(sizeof(*domain))) != NULL) {          domain = ccs_alloc_element(sizeof(*domain));
794                  struct domain_info *ptr = &KERNEL_DOMAIN;          if (domain) {
795                    INIT_LIST1_HEAD(&domain->acl_info_list);
796                  domain->domainname = saved_domainname;                  domain->domainname = saved_domainname;
797                  domain->profile = profile;                  domain->profile = profile;
798                  mb(); /* Instead of using spinlock. */                  list1_add_tail_mb(&domain->list, &ccs_domain_list);
                 while (ptr->next) ptr = ptr->next; ptr->next = domain;  
         }  
  out: ;  
         up(&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++;  
799          }          }
         if (--dest_len <= 0) goto out;  
         *dest = '\0';  
         return 0;  
800   out:   out:
801          return -ENOMEM;          mutex_unlock(&ccs_domain_list_lock);
802            return domain;
803  }  }
804    
805  static char *get_argv0(struct linux_binprm *bprm)  /**
806     * ccs_get_argv0 - Get argv[0].
807     *
808     * @ee: Pointer to "struct ccs_execve_entry".
809     *
810     * Returns true on success, false otherwise.
811     */
812    static bool ccs_get_argv0(struct ccs_execve_entry *ee)
813  {  {
814          char *arg_ptr = ccs_alloc(PAGE_SIZE); /* Initial buffer. */          struct linux_binprm *bprm = ee->bprm;
815            char *arg_ptr = ee->tmp;
816          int arg_len = 0;          int arg_len = 0;
817          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
818          int i = pos / PAGE_SIZE, offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
819          if (!bprm->argc || !arg_ptr) goto out;          bool done = false;
820            if (!bprm->argc)
821                    goto out;
822          while (1) {          while (1) {
823                  struct page *page;                  if (!ccs_dump_page(bprm, pos, &ee->dump))
824  #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);  
825                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
826  #endif                  /* Read. */
827                  arg_len += PAGE_SIZE - offset;                  while (offset < PAGE_SIZE) {
828                  if (memchr(arg_ptr, '\0', arg_len)) break;                          const char *kaddr = ee->dump.data;
829                  { /* Initial buffer was too small for argv[0]. Retry after expanding buffer. */                          const unsigned char c = kaddr[offset++];
830                          char *tmp_arg_ptr = ccs_alloc(arg_len + PAGE_SIZE);                          if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
831                          if (!tmp_arg_ptr) goto out;                                  if (c == '\\') {
832                          memmove(tmp_arg_ptr, arg_ptr, arg_len);                                          arg_ptr[arg_len++] = '\\';
833                          ccs_free(arg_ptr);                                          arg_ptr[arg_len++] = '\\';
834                          arg_ptr = tmp_arg_ptr;                                  } else if (c == '/') {
835                                            arg_len = 0;
836                                    } else if (c > ' ' && c < 127) {
837                                            arg_ptr[arg_len++] = c;
838                                    } else {
839                                            arg_ptr[arg_len++] = '\\';
840                                            arg_ptr[arg_len++] = (c >> 6) + '0';
841                                            arg_ptr[arg_len++]
842                                                    = ((c >> 3) & 7) + '0';
843                                            arg_ptr[arg_len++] = (c & 7) + '0';
844                                    }
845                            } else {
846                                    arg_ptr[arg_len] = '\0';
847                                    done = true;
848                                    break;
849                            }
850                  }                  }
                 i++;  
851                  offset = 0;                  offset = 0;
852                    if (done)
853                            break;
854          }          }
855          return arg_ptr;          return true;
856   out: /* Release initial buffer. */   out:
857          ccs_free(arg_ptr);          return false;
         return NULL;  
858  }  }
859    
860  static int FindNextDomain(struct linux_binprm *bprm, struct domain_info **next_domain)  /**
861  {   * ccs_find_next_domain - Find a domain.
862          /* This function assumes that the size of buffer returned by realpath() = CCS_MAX_PATHNAME_LEN. */   *
863          struct domain_info *old_domain = current->domain_info, *domain = NULL;   * @ee: Pointer to "struct ccs_execve_entry".
864          const char *old_domain_name = old_domain->domainname->name;   *
865          const char *original_name = bprm->filename;   * Returns 0 on success, negative value otherwise.
866          struct file *filp = bprm->file;   */
867    static int ccs_find_next_domain(struct ccs_execve_entry *ee)
868    {
869            struct ccs_request_info *r = &ee->r;
870            const struct ccs_path_info *handler = ee->handler;
871            struct ccs_domain_info *domain = NULL;
872            const char *old_domain_name = r->domain->domainname->name;
873            struct linux_binprm *bprm = ee->bprm;
874            const u8 mode = r->mode;
875            const bool is_enforce = (mode == 3);
876            const u32 ccs_flags = current->ccs_flags;
877          char *new_domain_name = NULL;          char *new_domain_name = NULL;
878          char *real_program_name = NULL, *symlink_program_name = NULL;          struct ccs_path_info rn; /* real name */
879          const int is_enforce = CheckCCSEnforce(CCS_TOMOYO_MAC_FOR_FILE);          struct ccs_path_info sn; /* symlink name */
880            struct ccs_path_info ln; /* last name */
881          int retval;          int retval;
882          struct path_info r, s, l;   retry:
883            current->ccs_flags = ccs_flags;
884            r->cond = NULL;
885            /* Get realpath of program and symbolic link. */
886            retval = ccs_realpath_both(bprm->filename, ee);
887            if (retval < 0)
888                    goto out;
889    
890          {          rn.name = ee->program_path;
891                  /*          ccs_fill_path_info(&rn);
892                   * Built-in initializers. This is needed because policies are not loaded until starting /sbin/init .          sn.name = ee->tmp;
893                   */          ccs_fill_path_info(&sn);
894                  static int first = 1;          ln.name = ccs_get_last_name(r->domain);
895                  if (first) {          ccs_fill_path_info(&ln);
896                          AddDomainInitializerEntry(NULL, "/sbin/hotplug", 0, 0);  
897                          AddDomainInitializerEntry(NULL, "/sbin/modprobe", 0, 0);          if (handler) {
898                          first = 0;                  if (ccs_pathcmp(&rn, handler)) {
899                            /* Failed to verify execute handler. */
900                            static u8 counter = 20;
901                            if (counter) {
902                                    counter--;
903                                    printk(KERN_WARNING "Failed to verify: %s\n",
904                                           handler->name);
905                            }
906                            goto out;
907                  }                  }
908                    goto calculate_domain;
909          }          }
910    
         /* 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);  
   
911          /* Check 'alias' directive. */          /* Check 'alias' directive. */
912          if (pathcmp(&r, &s)) {          if (ccs_pathcmp(&rn, &sn)) {
913                  struct alias_entry *ptr;                  struct ccs_alias_entry *ptr;
914                  /* Is this program allowed to be called via symbolic links? */                  /* Is this program allowed to be called via symbolic links? */
915                  for (ptr = alias_list; ptr; ptr = ptr->next) {                  list1_for_each_entry(ptr, &ccs_alias_list, list) {
916                          if (ptr->is_deleted || pathcmp(&r, ptr->original_name) || pathcmp(&s, ptr->aliased_name)) continue;                          if (ptr->is_deleted ||
917                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                              ccs_pathcmp(&rn, ptr->original_name) ||
918                          strncpy(real_program_name, ptr->aliased_name->name, CCS_MAX_PATHNAME_LEN - 1);                              ccs_pathcmp(&sn, ptr->aliased_name))
919                          fill_path_info(&r);                                  continue;
920                            strncpy(ee->program_path, ptr->aliased_name->name,
921                                    CCS_MAX_PATHNAME_LEN - 1);
922                            ccs_fill_path_info(&rn);
923                          break;                          break;
924                  }                  }
925          }          }
926                    /* sn will be overwritten after here. */
927          /* Compare basename of real_program_name and argv[0] */  
928          if (bprm->argc > 0 && CheckCCSFlags(CCS_TOMOYO_MAC_FOR_ARGV0)) {          /* Compare basename of program_path and argv[0] */
929                  char *org_argv0 = get_argv0(bprm);          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);
930            if (bprm->argc > 0 && r->mode) {
931                    char *base_argv0 = ee->tmp;
932                    const char *base_filename;
933                  retval = -ENOMEM;                  retval = -ENOMEM;
934                  if (org_argv0) {                  if (!ccs_get_argv0(ee))
935                          const int len = strlen(org_argv0);                          goto out;
936                          char *printable_argv0 = ccs_alloc(len * 4 + 8);                  base_filename = strrchr(ee->program_path, '/');
937                          if (printable_argv0 && Escape(printable_argv0, org_argv0, len * 4 + 8) == 0) {                  if (!base_filename)
938                                  const char *base_argv0, *base_filename;                          base_filename = ee->program_path;
939                                  if ((base_argv0 = strrchr(printable_argv0, '/')) == NULL) base_argv0 = printable_argv0; else base_argv0++;                  else
940                                  if ((base_filename = strrchr(real_program_name, '/')) == NULL) base_filename = real_program_name; else base_filename++;                          base_filename++;
941                                  if (strcmp(base_argv0, base_filename)) retval = CheckArgv0Perm(&r, base_argv0);                  if (strcmp(base_argv0, base_filename)) {
942                                  else retval = 0;                          retval = ccs_check_argv0_perm(r, &rn, base_argv0);
943                          }                          if (retval == 1)
944                          ccs_free(printable_argv0);                                  goto retry;
945                          ccs_free(org_argv0);                          if (retval < 0)
946                                    goto out;
947                  }                  }
                 if (retval) goto out;  
948          }          }
949            
950          /* Check 'aggregator' directive. */          /* Check 'aggregator' directive. */
951          {          {
952                  struct aggregator_entry *ptr;                  struct ccs_aggregator_entry *ptr;
953                  /* Is this program allowed to be aggregated? */                  /* Is this program allowed to be aggregated? */
954                  for (ptr = aggregator_list; ptr; ptr = ptr->next) {                  list1_for_each_entry(ptr, &ccs_aggregator_list, list) {
955                          if (ptr->is_deleted || !PathMatchesToPattern(&r, ptr->original_name)) continue;                          if (ptr->is_deleted ||
956                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                              !ccs_path_matches_pattern(&rn, ptr->original_name))
957                          strncpy(real_program_name, ptr->aggregated_name->name, CCS_MAX_PATHNAME_LEN - 1);                                  continue;
958                          fill_path_info(&r);                          strncpy(ee->program_path, ptr->aggregated_name->name,
959                                    CCS_MAX_PATHNAME_LEN - 1);
960                            ccs_fill_path_info(&rn);
961                          break;                          break;
962                  }                  }
963          }          }
964    
965          /* Check execute permission. */          /* Check execute permission. */
966          if ((retval = CheckExecPerm(&r, filp)) < 0) goto out;          r->mode = mode;
967            retval = ccs_check_exec_perm(r, &rn);
968            if (retval == 1)
969                    goto retry;
970            if (retval < 0)
971                    goto out;
972    
973          /* Allocate memory for calcurating domain name. */   calculate_domain:
974          retval = -ENOMEM;          new_domain_name = ee->tmp;
975          if ((new_domain_name = ccs_alloc(CCS_MAX_PATHNAME_LEN + 16)) == NULL) goto out;          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
976                            /* Transit to the child of ccs_kernel_domain domain. */
977          if (IsDomainInitializer(old_domain->domainname, &r, &l)) {                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,
978                  /* Transit to the child of KERNEL_DOMAIN domain. */                           ROOT_NAME " " "%s", ee->program_path);
979                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1, ROOT_NAME " " "%s", real_program_name);          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
         } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {  
980                  /*                  /*
981                   * Needn't to transit from kernel domain before starting /sbin/init .                   * Needn't to transit from kernel domain before starting
982                   * But transit from kernel domain if executing initializers, for they might start before /sbin/init .                   * /sbin/init. But transit from kernel domain if executing
983                     * initializers because they might start before /sbin/init.
984                   */                   */
985                  domain = old_domain;                  domain = r->domain;
986          } else if (IsDomainKeeper(old_domain->domainname, &r, &l)) {          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
987                  /* Keep current domain. */                  /* Keep current domain. */
988                  domain = old_domain;                  domain = r->domain;
989          } else {          } else {
990                  /* Normal domain transition. */                  /* Normal domain transition. */
991                  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,
992          }                           "%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);  
                 }  
993          }          }
994            if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
995                    goto done;
996            domain = ccs_find_domain(new_domain_name);
997            if (domain)
998                    goto done;
999            if (is_enforce) {
1000                    int error = ccs_check_supervisor(r,
1001                                                     "# wants to create domain\n"
1002                                                     "%s\n", new_domain_name);
1003                    if (error == 1)
1004                            goto retry;
1005                    if (error < 0)
1006                            goto done;
1007            }
1008            domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);
1009            if (domain)
1010                    ccs_audit_domain_creation_log(domain);
1011     done:
1012          if (!domain) {          if (!domain) {
1013                  printk("TOMOYO-ERROR: Domain '%s' not defined.\n", new_domain_name);                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1014                  if (is_enforce) retval = -EPERM;                         new_domain_name);
1015                    if (is_enforce)
1016                            retval = -EPERM;
1017                    else {
1018                            retval = 0;
1019                            ccs_set_domain_flag(r->domain, false,
1020                                                DOMAIN_FLAGS_TRANSITION_FAILED);
1021                    }
1022          } else {          } else {
1023                  retval = 0;                  retval = 0;
1024          }          }
1025   out: ;   out:
1026          ccs_free(new_domain_name);          if (domain)
1027          ccs_free(real_program_name);                  r->domain = domain;
         ccs_free(symlink_program_name);  
         *next_domain = domain ? domain : old_domain;  
1028          return retval;          return retval;
1029  }  }
1030    
1031    /**
1032     * ccs_check_environ - Check permission for environment variable names.
1033     *
1034     * @ee: Pointer to "struct ccs_execve_entry".
1035     *
1036     * Returns 0 on success, negative value otherwise.
1037     */
1038    static int ccs_check_environ(struct ccs_execve_entry *ee)
1039    {
1040            struct ccs_request_info *r = &ee->r;
1041            struct linux_binprm *bprm = ee->bprm;
1042            char *arg_ptr = ee->tmp;
1043            int arg_len = 0;
1044            unsigned long pos = bprm->p;
1045            int offset = pos % PAGE_SIZE;
1046            int argv_count = bprm->argc;
1047            int envp_count = bprm->envc;
1048            /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1049            int error = -ENOMEM;
1050            if (!r->mode || !envp_count)
1051                    return 0;
1052            while (error == -ENOMEM) {
1053                    if (!ccs_dump_page(bprm, pos, &ee->dump))
1054                            goto out;
1055                    pos += PAGE_SIZE - offset;
1056                    /* Read. */
1057                    while (argv_count && offset < PAGE_SIZE) {
1058                            const char *kaddr = ee->dump.data;
1059                            if (!kaddr[offset++])
1060                                    argv_count--;
1061                    }
1062                    if (argv_count) {
1063                            offset = 0;
1064                            continue;
1065                    }
1066                    while (offset < PAGE_SIZE) {
1067                            const char *kaddr = ee->dump.data;
1068                            const unsigned char c = kaddr[offset++];
1069                            if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1070                                    if (c == '=') {
1071                                            arg_ptr[arg_len++] = '\0';
1072                                    } else if (c == '\\') {
1073                                            arg_ptr[arg_len++] = '\\';
1074                                            arg_ptr[arg_len++] = '\\';
1075                                    } else if (c > ' ' && c < 127) {
1076                                            arg_ptr[arg_len++] = c;
1077                                    } else {
1078                                            arg_ptr[arg_len++] = '\\';
1079                                            arg_ptr[arg_len++] = (c >> 6) + '0';
1080                                            arg_ptr[arg_len++]
1081                                                    = ((c >> 3) & 7) + '0';
1082                                            arg_ptr[arg_len++] = (c & 7) + '0';
1083                                    }
1084                            } else {
1085                                    arg_ptr[arg_len] = '\0';
1086                            }
1087                            if (c)
1088                                    continue;
1089                            if (ccs_check_env_perm(r, arg_ptr)) {
1090                                    error = -EPERM;
1091                                    break;
1092                            }
1093                            if (!--envp_count) {
1094                                    error = 0;
1095                                    break;
1096                            }
1097                            arg_len = 0;
1098                    }
1099                    offset = 0;
1100            }
1101     out:
1102            if (r->mode != 3)
1103                    error = 0;
1104            return error;
1105    }
1106    
1107    /**
1108     * ccs_unescape - Unescape escaped string.
1109     *
1110     * @dest: String to unescape.
1111     *
1112     * Returns nothing.
1113     */
1114    static void ccs_unescape(unsigned char *dest)
1115    {
1116            unsigned char *src = dest;
1117            unsigned char c;
1118            unsigned char d;
1119            unsigned char e;
1120            while (1) {
1121                    c = *src++;
1122                    if (!c)
1123                            break;
1124                    if (c != '\\') {
1125                            *dest++ = c;
1126                            continue;
1127                    }
1128                    c = *src++;
1129                    if (c == '\\') {
1130                            *dest++ = c;
1131                            continue;
1132                    }
1133                    if (c < '0' || c > '3')
1134                            break;
1135                    d = *src++;
1136                    if (d < '0' || d > '7')
1137                            break;
1138                    e = *src++;
1139                    if (e < '0' || e > '7')
1140                            break;
1141                    *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1142            }
1143            *dest = '\0';
1144    }
1145    
1146    /**
1147     * ccs_root_depth - Get number of directories to strip.
1148     *
1149     * @dentry: Pointer to "struct dentry".
1150     * @vfsmnt: Pointer to "struct vfsmount".
1151     *
1152     * Returns number of directories to strip.
1153     */
1154    static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1155    {
1156            int depth = 0;
1157            /***** CRITICAL SECTION START *****/
1158            ccs_realpath_lock();
1159            for (;;) {
1160                    if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1161                            /* Global root? */
1162                            if (vfsmnt->mnt_parent == vfsmnt)
1163                                    break;
1164                            dentry = vfsmnt->mnt_mountpoint;
1165                            vfsmnt = vfsmnt->mnt_parent;
1166                            continue;
1167                    }
1168                    dentry = dentry->d_parent;
1169                    depth++;
1170            }
1171            ccs_realpath_unlock();
1172            /***** CRITICAL SECTION END *****/
1173            return depth;
1174    }
1175    
1176    /**
1177     * ccs_get_root_depth - return the depth of root directory.
1178     *
1179     * Returns number of directories to strip.
1180     */
1181    static int ccs_get_root_depth(void)
1182    {
1183            int depth;
1184            struct dentry *dentry;
1185            struct vfsmount *vfsmnt;
1186    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1187            struct path root;
1188    #endif
1189            /***** CRITICAL SECTION START *****/
1190            read_lock(&current->fs->lock);
1191    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1192            root = current->fs->root;
1193            path_get(&current->fs->root);
1194            dentry = root.dentry;
1195            vfsmnt = root.mnt;
1196    #else
1197            dentry = dget(current->fs->root);
1198            vfsmnt = mntget(current->fs->rootmnt);
1199    #endif
1200            read_unlock(&current->fs->lock);
1201            /***** CRITICAL SECTION END *****/
1202            depth = ccs_root_depth(dentry, vfsmnt);
1203    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1204            path_put(&root);
1205    #else
1206            dput(dentry);
1207            mntput(vfsmnt);
1208  #endif  #endif
1209            return depth;
1210    }
1211    
1212    static LIST_HEAD(ccs_execve_list);
1213    static DEFINE_SPINLOCK(ccs_execve_list_lock);
1214    
1215  int search_binary_handler_with_transition(struct linux_binprm *bprm, struct pt_regs *regs)  /**
1216     * ccs_allocate_execve_entry - Allocate memory for execve().
1217     *
1218     * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1219     */
1220    static struct ccs_execve_entry *ccs_allocate_execve_entry(void)
1221  {  {
1222          struct domain_info *next_domain = NULL, *prev_domain = current->domain_info;          struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);
1223          int retval;          if (!ee)
1224  #if defined(CONFIG_SAKURA) || defined(CONFIG_TOMOYO)                  return NULL;
1225          extern void CCS_LoadPolicy(const char *filename);          memset(ee, 0, sizeof(*ee));
1226          CCS_LoadPolicy(bprm->filename);          ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1227            ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
1228            if (!ee->program_path || !ee->tmp) {
1229                    ccs_free(ee->program_path);
1230                    ccs_free(ee->tmp);
1231                    ccs_free(ee);
1232                    return NULL;
1233            }
1234            /* ee->dump->data is allocated by ccs_dump_page(). */
1235            ee->task = current;
1236            /***** CRITICAL SECTION START *****/
1237            spin_lock(&ccs_execve_list_lock);
1238            list_add(&ee->list, &ccs_execve_list);
1239            spin_unlock(&ccs_execve_list_lock);
1240            /***** CRITICAL SECTION END *****/
1241            return ee;
1242    }
1243    
1244    /**
1245     * ccs_find_execve_entry - Find ccs_execve_entry of current process.
1246     *
1247     * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
1248     */
1249    static struct ccs_execve_entry *ccs_find_execve_entry(void)
1250    {
1251            struct task_struct *task = current;
1252            struct ccs_execve_entry *ee = NULL;
1253            struct ccs_execve_entry *p;
1254            /***** CRITICAL SECTION START *****/
1255            spin_lock(&ccs_execve_list_lock);
1256            list_for_each_entry(p, &ccs_execve_list, list) {
1257                    if (p->task != task)
1258                            continue;
1259                    ee = p;
1260                    break;
1261            }
1262            spin_unlock(&ccs_execve_list_lock);
1263            /***** CRITICAL SECTION END *****/
1264            return ee;
1265    }
1266    
1267    /**
1268     * ccs_free_execve_entry - Free memory for execve().
1269     *
1270     * @ee: Pointer to "struct ccs_execve_entry".
1271     */
1272    static void ccs_free_execve_entry(struct ccs_execve_entry *ee)
1273    {
1274            if (!ee)
1275                    return;
1276            /***** CRITICAL SECTION START *****/
1277            spin_lock(&ccs_execve_list_lock);
1278            list_del(&ee->list);
1279            spin_unlock(&ccs_execve_list_lock);
1280            /***** CRITICAL SECTION END *****/
1281            ccs_free(ee->program_path);
1282            ccs_free(ee->tmp);
1283            kfree(ee->dump.data);
1284            ccs_free(ee);
1285    }
1286    
1287    /**
1288     * ccs_try_alt_exec - Try to start execute handler.
1289     *
1290     * @ee: Pointer to "struct ccs_execve_entry".
1291     *
1292     * Returns 0 on success, negative value otherwise.
1293     */
1294    static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
1295    {
1296            /*
1297             * Contents of modified bprm.
1298             * The envp[] in original bprm is moved to argv[] so that
1299             * the alternatively executed program won't be affected by
1300             * some dangerous environment variables like LD_PRELOAD.
1301             *
1302             * modified bprm->argc
1303             *    = original bprm->argc + original bprm->envc + 7
1304             * modified bprm->envc
1305             *    = 0
1306             *
1307             * modified bprm->argv[0]
1308             *    = the program's name specified by execute_handler
1309             * modified bprm->argv[1]
1310             *    = ccs_current_domain()->domainname->name
1311             * modified bprm->argv[2]
1312             *    = the current process's name
1313             * modified bprm->argv[3]
1314             *    = the current process's information (e.g. uid/gid).
1315             * modified bprm->argv[4]
1316             *    = original bprm->filename
1317             * modified bprm->argv[5]
1318             *    = original bprm->argc in string expression
1319             * modified bprm->argv[6]
1320             *    = original bprm->envc in string expression
1321             * modified bprm->argv[7]
1322             *    = original bprm->argv[0]
1323             *  ...
1324             * modified bprm->argv[bprm->argc + 6]
1325             *     = original bprm->argv[bprm->argc - 1]
1326             * modified bprm->argv[bprm->argc + 7]
1327             *     = original bprm->envp[0]
1328             *  ...
1329             * modified bprm->argv[bprm->envc + bprm->argc + 6]
1330             *     = original bprm->envp[bprm->envc - 1]
1331             */
1332            struct linux_binprm *bprm = ee->bprm;
1333            struct file *filp;
1334            int retval;
1335            const int original_argc = bprm->argc;
1336            const int original_envc = bprm->envc;
1337            struct task_struct *task = current;
1338    
1339            /* Close the requested program's dentry. */
1340            allow_write_access(bprm->file);
1341            fput(bprm->file);
1342            bprm->file = NULL;
1343    
1344            /* Invalidate page dump cache. */
1345            ee->dump.page = NULL;
1346    
1347            /* Move envp[] to argv[] */
1348            bprm->argc += bprm->envc;
1349            bprm->envc = 0;
1350    
1351            /* Set argv[6] */
1352            {
1353                    char *cp = ee->tmp;
1354                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
1355                    retval = copy_strings_kernel(1, &cp, bprm);
1356                    if (retval < 0)
1357                            goto out;
1358                    bprm->argc++;
1359            }
1360    
1361            /* Set argv[5] */
1362            {
1363                    char *cp = ee->tmp;
1364                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
1365                    retval = copy_strings_kernel(1, &cp, bprm);
1366                    if (retval < 0)
1367                            goto out;
1368                    bprm->argc++;
1369            }
1370    
1371            /* Set argv[4] */
1372            {
1373                    retval = copy_strings_kernel(1, &bprm->filename, bprm);
1374                    if (retval < 0)
1375                            goto out;
1376                    bprm->argc++;
1377            }
1378    
1379            /* Set argv[3] */
1380            {
1381                    char *cp = ee->tmp;
1382                    const u32 ccs_flags = task->ccs_flags;
1383                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1384                             "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1385                             "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1386                             "state[1]=%u state[2]=%u",
1387                             (pid_t) sys_getpid(), current_uid(), current_gid(),
1388                             current_euid(), current_egid(), current_suid(),
1389                             current_sgid(), current_fsuid(), current_fsgid(),
1390                             (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1391                             (u8) (ccs_flags >> 8));
1392                    retval = copy_strings_kernel(1, &cp, bprm);
1393                    if (retval < 0)
1394                            goto out;
1395                    bprm->argc++;
1396            }
1397    
1398            /* Set argv[2] */
1399            {
1400                    char *exe = (char *) ccs_get_exe();
1401                    if (exe) {
1402                            retval = copy_strings_kernel(1, &exe, bprm);
1403                            ccs_free(exe);
1404                    } else {
1405                            exe = ee->tmp;
1406                            strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);
1407                            retval = copy_strings_kernel(1, &exe, bprm);
1408                    }
1409                    if (retval < 0)
1410                            goto out;
1411                    bprm->argc++;
1412            }
1413    
1414            /* Set argv[1] */
1415            {
1416                    char *cp = ee->tmp;
1417                    strncpy(ee->tmp, ccs_current_domain()->domainname->name,
1418                            CCS_EXEC_TMPSIZE - 1);
1419                    retval = copy_strings_kernel(1, &cp, bprm);
1420                    if (retval < 0)
1421                            goto out;
1422                    bprm->argc++;
1423            }
1424    
1425            /* Set argv[0] */
1426            {
1427                    int depth = ccs_get_root_depth();
1428                    char *cp = ee->program_path;
1429                    strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);
1430                    ccs_unescape(cp);
1431                    retval = -ENOENT;
1432                    if (!*cp || *cp != '/')
1433                            goto out;
1434                    /* Adjust root directory for open_exec(). */
1435                    while (depth) {
1436                            cp = strchr(cp + 1, '/');
1437                            if (!cp)
1438                                    goto out;
1439                            depth--;
1440                    }
1441                    memmove(ee->program_path, cp, strlen(cp) + 1);
1442                    cp = ee->program_path;
1443                    retval = copy_strings_kernel(1, &cp, bprm);
1444                    if (retval < 0)
1445                            goto out;
1446                    bprm->argc++;
1447            }
1448    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1449    #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1450            bprm->argv_len = bprm->exec - bprm->p;
1451    #endif
1452  #endif  #endif
1453  #if defined(CONFIG_TOMOYO)  
1454          retval = FindNextDomain(bprm, &next_domain);          /* OK, now restart the process with execute handler program's dentry. */
1455            filp = open_exec(ee->program_path);
1456            if (IS_ERR(filp)) {
1457                    retval = PTR_ERR(filp);
1458                    goto out;
1459            }
1460            bprm->file = filp;
1461            bprm->filename = ee->program_path;
1462    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1463            bprm->interp = bprm->filename;
1464    #endif
1465            retval = prepare_binprm(bprm);
1466            if (retval < 0)
1467                    goto out;
1468            {
1469                    /*
1470                     * Backup ee->program_path because ccs_find_next_domain() will
1471                     * overwrite ee->program_path and ee->tmp.
1472                     */
1473                    const int len = strlen(ee->program_path) + 1;
1474                    char *cp = kmalloc(len, GFP_KERNEL);
1475                    if (!cp) {
1476                            retval = -ENOMEM;
1477                            goto out;
1478                    }
1479                    memmove(cp, ee->program_path, len);
1480                    bprm->filename = cp;
1481    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1482                    bprm->interp = bprm->filename;
1483    #endif
1484                    task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1485                    retval = ccs_find_next_domain(ee);
1486                    task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1487                    /* Restore ee->program_path for search_binary_handler(). */
1488                    memmove(ee->program_path, cp, len);
1489                    bprm->filename = ee->program_path;
1490    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1491                    bprm->interp = bprm->filename;
1492    #endif
1493                    kfree(cp);
1494            }
1495     out:
1496            return retval;
1497    }
1498    
1499    /**
1500     * ccs_find_execute_handler - Find an execute handler.
1501     *
1502     * @ee:   Pointer to "struct ccs_execve_entry".
1503     * @type: Type of execute handler.
1504     *
1505     * Returns true if found, false otherwise.
1506     */
1507    static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1508                                         const u8 type)
1509    {
1510            struct task_struct *task = current;
1511            const struct ccs_domain_info *domain = ccs_current_domain();
1512            struct ccs_acl_info *ptr;
1513            /*
1514             * Don't use execute handler if the current process is
1515             * marked as execute handler to avoid infinite execute handler loop.
1516             */
1517            if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1518                    return false;
1519            list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1520                    struct ccs_execute_handler_record *acl;
1521                    if (ptr->type != type)
1522                            continue;
1523                    acl = container_of(ptr, struct ccs_execute_handler_record,
1524                                       head);
1525                    ee->handler = acl->handler;
1526                    return true;
1527            }
1528            return false;
1529    }
1530    
1531    /**
1532     * ccs_dump_page - Dump a page to buffer.
1533     *
1534     * @bprm: Pointer to "struct linux_binprm".
1535     * @pos:  Location to dump.
1536     * @dump: Poiner to "struct ccs_page_dump".
1537     *
1538     * Returns true on success, false otherwise.
1539     */
1540    bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1541                       struct ccs_page_dump *dump)
1542    {
1543            struct page *page;
1544            /* dump->data is released by ccs_free_execve_entry(). */
1545            if (!dump->data) {
1546                    dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
1547                    if (!dump->data)
1548                            return false;
1549            }
1550            /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1551    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1552            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1553                    return false;
1554    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1555            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1556                    return false;
1557  #else  #else
1558          retval = 0; next_domain = prev_domain;          page = bprm->page[pos / PAGE_SIZE];
1559    #endif
1560            if (page != dump->page) {
1561                    const unsigned int offset = pos % PAGE_SIZE;
1562                    /*
1563                     * Maybe kmap()/kunmap() should be used here.
1564                     * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1565                     * So do I.
1566                     */
1567                    char *kaddr = kmap_atomic(page, KM_USER0);
1568                    dump->page = page;
1569                    memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1570                    kunmap_atomic(kaddr, KM_USER0);
1571            }
1572            /* Same with put_arg_page(page) in fs/exec.c */
1573    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1574            put_page(page);
1575    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1576            put_page(page);
1577  #endif  #endif
1578          if (retval == 0) {          return true;
1579                  current->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;  }
1580                  current->domain_info = next_domain;  
1581                  retval = search_binary_handler(bprm, regs);  /**
1582                  if (retval < 0) current->domain_info = prev_domain;   * ccs_fetch_next_domain - Fetch next_domain from the list.
1583                  current->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;   *
1584     * Returns pointer to "struct ccs_domain_info" which will be used if execve()
1585     * succeeds. This function does not return NULL.
1586     */
1587    struct ccs_domain_info *ccs_fetch_next_domain(void)
1588    {
1589            struct ccs_execve_entry *ee = ccs_find_execve_entry();
1590            struct ccs_domain_info *next_domain = NULL;
1591            if (ee)
1592                    next_domain = ee->next_domain;
1593            if (!next_domain)
1594                    next_domain = ccs_current_domain();
1595            return next_domain;
1596    }
1597    
1598    /**
1599     * ccs_start_execve - Prepare for execve() operation.
1600     *
1601     * @bprm: Pointer to "struct linux_binprm".
1602     *
1603     * Returns 0 on success, negative value otherwise.
1604     */
1605    int ccs_start_execve(struct linux_binprm *bprm)
1606    {
1607            int retval;
1608            struct task_struct *task = current;
1609            struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1610            if (!ccs_policy_loaded)
1611                    ccs_load_policy(bprm->filename);
1612            if (!ee)
1613                    return -ENOMEM;
1614            ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);
1615            ee->r.ee = ee;
1616            ee->bprm = bprm;
1617            ee->r.obj = &ee->obj;
1618            ee->obj.path1_dentry = bprm->file->f_dentry;
1619            ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;
1620            /* Clear manager flag. */
1621            task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1622            if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {
1623                    retval = ccs_try_alt_exec(ee);
1624                    if (!retval)
1625                            ccs_audit_execute_handler_log(ee, true);
1626                    goto ok;
1627            }
1628            retval = ccs_find_next_domain(ee);
1629            if (retval != -EPERM)
1630                    goto ok;
1631            if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {
1632                    retval = ccs_try_alt_exec(ee);
1633                    if (!retval)
1634                            ccs_audit_execute_handler_log(ee, false);
1635          }          }
1636     ok:
1637            if (retval < 0)
1638                    goto out;
1639            ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);
1640            retval = ccs_check_environ(ee);
1641            if (retval < 0)
1642                    goto out;
1643            ee->next_domain = ee->r.domain;
1644            task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1645            retval = 0;
1646     out:
1647            if (retval)
1648                    ccs_finish_execve(retval);
1649          return retval;          return retval;
1650  }  }
1651    
1652  /***** TOMOYO Linux end. *****/  /**
1653     * ccs_finish_execve - Clean up execve() operation.
1654     *
1655     * @retval: Return code of an execve() operation.
1656     */
1657    void ccs_finish_execve(int retval)
1658    {
1659            struct task_struct *task = current;
1660            struct ccs_execve_entry *ee = ccs_find_execve_entry();
1661            task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1662            if (!ee)
1663                    return;
1664            if (retval < 0)
1665                    goto out;
1666            /* Proceed to next domain if execution suceeded. */
1667            task->ccs_domain_info = ee->r.domain;
1668            mb(); /* Make domain transition visible to other CPUs. */
1669            /* Mark the current process as execute handler. */
1670            if (ee->handler)
1671                    task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1672            /* Mark the current process as normal process. */
1673            else
1674                    task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1675     out:
1676            ccs_free_execve_entry(ee);
1677    }
1678    
1679    #else
1680    
1681    /**
1682     * ccs_start_execve - Prepare for execve() operation.
1683     *
1684     * @bprm: Pointer to "struct linux_binprm".
1685     *
1686     * Returns 0.
1687     */
1688    int ccs_start_execve(struct linux_binprm *bprm)
1689    {
1690    #ifdef CONFIG_SAKURA
1691            /* Clear manager flag. */
1692            current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1693            if (!ccs_policy_loaded)
1694                    ccs_load_policy(bprm->filename);
1695    #endif
1696            return 0;
1697    }
1698    
1699    /**
1700     * ccs_finish_execve - Clean up execve() operation.
1701     */
1702    void ccs_finish_execve(int retval)
1703    {
1704    }
1705    
1706    #endif

Legend:
Removed from v.502  
changed lines
  Added in v.2393

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