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

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

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

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