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

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 329 by kumaneko, Wed Aug 8 11:15:09 2007 UTC trunk/1.6.x/ccs-patch/fs/tomoyo_domain.c revision 1561 by kumaneko, Tue Sep 9 04:29:07 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-pre   2007/08/06   * Version: 1.6.5-pre   2008/09/09
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(). */
         u8 is_oldstyle;  
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  int IsDomainDef(const unsigned char *buffer)   * Returns nothing.
90     */
91    void ccs_set_domain_flag(struct domain_info *domain, const bool is_delete,
92                             const u8 flags)
93  {  {
94          /* while (*buffer && (*buffer <= ' ' || *buffer >= 127)) buffer++; */          mutex_lock(&new_domain_assign_lock);
95          return strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN) == 0;          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 ReadSelfDomain(struct io_buffer *head)  /**
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          if (!head->read_eof) {          if (domain)
128                  io_printf(head, "%s", current->domain_info->domainname->name);                  list1_add_tail_mb(&acl->list, &domain->acl_info_list);
129                  head->read_eof = 1;          else
130          }                  acl->type &= ~ACL_DELETED;
131            ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
132          return 0;          return 0;
133  }  }
134    
135  int AddDomainACL(struct acl_info *ptr, struct domain_info *domain, struct acl_info *new_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          mb(); /* Instead of using spinlock. */          if (acl)
145          if (!ptr) domain->first_acl_ptr = (struct acl_info *) new_ptr;                  acl->type |= ACL_DELETED;
146          else ptr->next = (struct acl_info *) new_ptr;          ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
         UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
147          return 0;          return 0;
148  }  }
149    
150  int DelDomainACL(struct acl_info *ptr)  /**
151  {   * audit_execute_handler_log - Audit execute_handler log.
152          ptr->is_deleted = 1;   *
153          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);   * @is_default: True if it is "execute_handler" log.
154          return 0;   * @handler:    The realpath of the handler.
155     * @bprm:       Pointer to "struct linux_binprm".
156     *
157     * Returns 0 on success, negative value otherwise.
158     */
159    static int audit_execute_handler_log(const bool is_default,
160                                         const char *handler,
161                                         struct linux_binprm *bprm)
162    {
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  int TooManyDomainACL(struct domain_info * const domain) {  /**
184          unsigned int count = 0;   * audit_domain_creation_log - Audit domain creation log.
185          struct acl_info *ptr;   *
186          for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {   * @domainname: The name of newly created domain.
187                  if (!ptr->is_deleted) count++;   * @mode:       Access control mode used.
188          }   * @profile:    Profile number used.
189          /* If there are so many entries, don't append if learning mode. */   *
190          if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 0;   * Returns 0 on success, negative value otherwise.
191          if (!domain->quota_warned) {   */
192                  printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);  static int audit_domain_creation_log(const char *domainname, const u8 mode,
193                  domain->quota_warned = 1;                                       const u8 profile)
194          }  {
195          return 1;          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    /* The list for "struct domain_initializer_entry". */
218    static LIST1_HEAD(domain_initializer_list);
219    
220  /*************************  DOMAIN INITIALIZER HANDLER  *************************/  /**
221     * update_domain_initializer_entry - Update "struct domain_initializer_entry" list.
222  static struct domain_initializer_entry *domain_initializer_list = NULL;   *
223     * @domainname: The name of domain. May be NULL.
224  static int AddDomainInitializerEntry(const char *domainname, const char *program, const int is_not, const int is_delete, const int is_oldstyle)   * @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->is_oldstyle == is_oldstyle && 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          new_entry->is_oldstyle = is_oldstyle;          list1_add_tail_mb(&new_entry->list, &domain_initializer_list);
         mb(); /* Instead of using spinlock. */  
         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%s%s from %s\n", ptr->is_not ? "no_" : "", ptr->is_oldstyle ? KEYWORD_INITIALIZER : KEYWORD_INITIALIZE_DOMAIN, 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%s%s\n", ptr->is_not ? "no_" : "", ptr->is_oldstyle ? KEYWORD_INITIALIZER : KEYWORD_INITIALIZE_DOMAIN, 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, const int is_oldstyle)  /**
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, is_oldstyle);                  return update_domain_initializer_entry(cp + 6, data, is_not,
335          } else {                                                         is_delete);
                 return AddDomainInitializerEntry(NULL, data, is_not, is_delete, is_oldstyle);  
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);
379    
380  static struct domain_keeper_entry *domain_keeper_list = NULL;  /**
381     * update_domain_keeper_entry - Update "struct domain_keeper_entry" list.
382  static int AddDomainKeeperEntry(const char *domainname, const char *program, const int is_not, const int is_delete)   *
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 *FindDomain(const char *domainname0)   *
838  {   * @domainname: The name of domain.
839          struct domain_info *domain;   * @profile:    Profile number to assign if the domain was newly created.
840          static int first = 1;   *
841          struct path_info domainname;   * Returns pointer to "struct domain_info" on success, NULL otherwise.
842          domainname.name = domainname0;   */
843          fill_path_info(&domainname);  struct domain_info *ccs_find_or_assign_new_domain(const char *domainname,
844          if (first) {                                                    const u8 profile)
                 KERNEL_DOMAIN.domainname = SaveName(ROOT_NAME);  
                 first = 0;  
         }  
         for (domain = &KERNEL_DOMAIN; domain; domain = domain->next) {  
                 if (!domain->is_deleted && !pathcmp(&domainname, domain->domainname)) return domain;  
         }  
         return NULL;  
 }  
   
 struct domain_info *FindOrAssignNewDomain(const char *domainname, 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            const u32 tomoyo_flags = current->tomoyo_flags;
1018    
1019          {          {
1020                  /*                  /*
1021                   * Built-in initializers. This is needed because policies are not loaded until starting /sbin/init .                   * Built-in initializers. This is needed because policies are
1022                     * not loaded until starting /sbin/init.
1023                   */                   */
1024                  static int first = 1;                  static bool first = true;
1025                  if (first) {                  if (first) {
1026                          AddDomainInitializerEntry(NULL, "/sbin/hotplug", 0, 0, 0);                          update_domain_initializer_entry(NULL, "/sbin/hotplug",
1027                          AddDomainInitializerEntry(NULL, "/sbin/modprobe", 0, 0, 0);                                                          false, false);
1028                          first = 0;                          update_domain_initializer_entry(NULL, "/sbin/modprobe",
1029                                                            false, false);
1030                            first = false;
1031                  }                  }
1032          }          }
1033    
1034          /* Get realpath of program. */   retry:
1035          retval = -ENOENT; /* I hope realpath() won't fail with -ENOMEM. */          current->tomoyo_flags = tomoyo_flags;
1036          if ((real_program_name = realpath(original_name)) == NULL) goto out;          /* Get ccs_realpath of program. */
1037          /* Get realpath of symbolic link. */          retval = -ENOENT; /* I hope ccs_realpath() won't fail with -ENOMEM. */
1038          if ((symlink_program_name = realpath_nofollow(original_name)) == NULL) goto out;          ccs_free(real_program_name);
1039            real_program_name = ccs_realpath(original_name);
1040            if (!real_program_name)
1041                    goto out;
1042            /* Get ccs_realpath of symbolic link. */
1043            ccs_free(symlink_program_name);
1044            symlink_program_name = ccs_realpath_nofollow(original_name);
1045            if (!symlink_program_name)
1046                    goto out;
1047    
1048          r.name = real_program_name;          r.name = real_program_name;
1049          fill_path_info(&r);          ccs_fill_path_info(&r);
1050          s.name = symlink_program_name;          s.name = symlink_program_name;
1051          fill_path_info(&s);          ccs_fill_path_info(&s);
1052          if ((l.name = strrchr(old_domain_name, ' ')) != NULL) l.name++;          l.name = ccs_get_last_name(old_domain);
1053          else l.name = old_domain_name;          ccs_fill_path_info(&l);
1054          fill_path_info(&l);  
1055            if (path_to_verify) {
1056                    if (ccs_pathcmp(&r, path_to_verify)) {
1057                            /* Failed to verify execute handler. */
1058                            static u8 counter = 20;
1059                            if (counter) {
1060                                    counter--;
1061                                    printk(KERN_WARNING "Failed to verify: %s\n",
1062                                           path_to_verify->name);
1063                            }
1064                            goto out;
1065                    }
1066                    goto calculate_domain;
1067            }
1068    
1069          /* Check 'alias' directive. */          /* Check 'alias' directive. */
1070          if (pathcmp(&r, &s)) {          if (ccs_pathcmp(&r, &s)) {
1071                  struct alias_entry *ptr;                  struct alias_entry *ptr;
1072                  /* Is this program allowed to be called via symbolic links? */                  /* Is this program allowed to be called via symbolic links? */
1073                  for (ptr = alias_list; ptr; ptr = ptr->next) {                  list1_for_each_entry(ptr, &alias_list, list) {
1074                          if (ptr->is_deleted || pathcmp(&r, ptr->original_name) || pathcmp(&s, ptr->aliased_name)) continue;                          if (ptr->is_deleted ||
1075                                ccs_pathcmp(&r, ptr->original_name) ||
1076                                ccs_pathcmp(&s, ptr->aliased_name))
1077                                    continue;
1078                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
1079                          strncpy(real_program_name, ptr->aliased_name->name, CCS_MAX_PATHNAME_LEN - 1);                          strncpy(real_program_name, ptr->aliased_name->name,
1080                          fill_path_info(&r);                                  CCS_MAX_PATHNAME_LEN - 1);
1081                            ccs_fill_path_info(&r);
1082                          break;                          break;
1083                  }                  }
1084          }          }
1085            
1086          /* Compare basename of real_program_name and argv[0] */          /* Compare basename of real_program_name and argv[0] */
1087          if (bprm->argc > 0 && CheckCCSFlags(CCS_TOMOYO_MAC_FOR_ARGV0)) {          if (bprm->argc > 0 && ccs_check_flags(CCS_TOMOYO_MAC_FOR_ARGV0)) {
1088                  char *org_argv0 = get_argv0(bprm);                  char *base_argv0 = tmp->buffer;
1089                    const char *base_filename;
1090                  retval = -ENOMEM;                  retval = -ENOMEM;
1091                  if (org_argv0) {                  if (!get_argv0(bprm, tmp))
1092                          const int len = strlen(org_argv0);                          goto out;
1093                          char *printable_argv0 = ccs_alloc(len * 4 + 8);                  base_filename = strrchr(real_program_name, '/');
1094                          if (printable_argv0 && Escape(printable_argv0, org_argv0, len * 4 + 8) == 0) {                  if (!base_filename)
1095                                  const char *base_argv0, *base_filename;                          base_filename = real_program_name;
1096                                  if ((base_argv0 = strrchr(printable_argv0, '/')) == NULL) base_argv0 = printable_argv0; else base_argv0++;                  else
1097                                  if ((base_filename = strrchr(real_program_name, '/')) == NULL) base_filename = real_program_name; else base_filename++;                          base_filename++;
1098                                  if (strcmp(base_argv0, base_filename)) retval = CheckArgv0Perm(&r, base_argv0);                  if (strcmp(base_argv0, base_filename)) {
1099                                  else retval = 0;                          retval = ccs_check_argv0_perm(&r, base_argv0);
1100                          }                          if (retval == 1)
1101                          ccs_free(printable_argv0);                                  goto retry;
1102                          ccs_free(org_argv0);                          if (retval < 0)
1103                                    goto out;
1104                  }                  }
                 if (retval) goto out;  
1105          }          }
1106            
1107          /* Check 'aggregator' directive. */          /* Check 'aggregator' directive. */
1108          {          {
1109                  struct aggregator_entry *ptr;                  struct aggregator_entry *ptr;
1110                  /* Is this program allowed to be aggregated? */                  /* Is this program allowed to be aggregated? */
1111                  for (ptr = aggregator_list; ptr; ptr = ptr->next) {                  list1_for_each_entry(ptr, &aggregator_list, list) {
1112                          if (ptr->is_deleted || !PathMatchesToPattern(&r, ptr->original_name)) continue;                          if (ptr->is_deleted ||
1113                                !ccs_path_matches_pattern(&r, ptr->original_name))
1114                                    continue;
1115                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);
1116                          strncpy(real_program_name, ptr->aggregated_name->name, CCS_MAX_PATHNAME_LEN - 1);                          strncpy(real_program_name, ptr->aggregated_name->name,
1117                          fill_path_info(&r);                                  CCS_MAX_PATHNAME_LEN - 1);
1118                            ccs_fill_path_info(&r);
1119                          break;                          break;
1120                  }                  }
1121          }          }
1122    
1123          /* Check execute permission. */          /* Check execute permission. */
1124          if ((retval = CheckExecPerm(&r, filp)) < 0) goto out;          retval = ccs_check_exec_perm(&r, bprm, tmp);
1125            if (retval == 1)
1126                    goto retry;
1127            if (retval < 0)
1128                    goto out;
1129    
1130          /* Allocate memory for calcurating domain name. */   calculate_domain:
1131          retval = -ENOMEM;          new_domain_name = tmp->buffer;
1132          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)) {  
1133                  /* Transit to the child of KERNEL_DOMAIN domain. */                  /* Transit to the child of KERNEL_DOMAIN domain. */
1134                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1, ROOT_NAME " " "%s", real_program_name);                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1,
1135                             ROOT_NAME " " "%s", real_program_name);
1136          } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {          } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {
1137                  /*                  /*
1138                   * Needn't to transit from kernel domain before starting /sbin/init .                   * Needn't to transit from kernel domain before starting
1139                   * But transit from kernel domain if executing initializers, for they might start before /sbin/init .                   * /sbin/init. But transit from kernel domain if executing
1140                     * initializers because they might start before /sbin/init.
1141                   */                   */
1142                  domain = old_domain;                  domain = old_domain;
1143          } else if (IsDomainKeeper(old_domain->domainname, &r, &l)) {          } else if (is_domain_keeper(old_domain->domainname, &r, &l)) {
1144                  /* Keep current domain. */                  /* Keep current domain. */
1145                  domain = old_domain;                  domain = old_domain;
1146          } else {          } else {
1147                  /* Normal domain transition. */                  /* Normal domain transition. */
1148                  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,
1149          }                           "%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);  
                 }  
1150          }          }
1151            if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)
1152                    goto done;
1153            domain = ccs_find_domain(new_domain_name);
1154            if (domain)
1155                    goto done;
1156            if (is_enforce) {
1157                    int error = ccs_check_supervisor(NULL,
1158                                                     "# wants to create domain\n"
1159                                                     "%s\n", new_domain_name);
1160                    if (error == 1)
1161                            goto retry;
1162                    if (error < 0)
1163                            goto done;
1164            }
1165            domain = ccs_find_or_assign_new_domain(new_domain_name,
1166                                                   old_domain->profile);
1167            if (domain)
1168                    audit_domain_creation_log(new_domain_name, mode,
1169                                              domain->profile);
1170     done:
1171          if (!domain) {          if (!domain) {
1172                  printk("TOMOYO-ERROR: Domain '%s' not defined.\n", new_domain_name);                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
1173                  if (is_enforce) retval = -EPERM;                         new_domain_name);
1174                    if (is_enforce)
1175                            retval = -EPERM;
1176                    else {
1177                            retval = 0;
1178                            ccs_set_domain_flag(old_domain, false,
1179                                                DOMAIN_FLAGS_TRANSITION_FAILED);
1180                    }
1181          } else {          } else {
1182                  retval = 0;                  retval = 0;
1183          }          }
1184   out: ;   out:
         ccs_free(new_domain_name);  
1185          ccs_free(real_program_name);          ccs_free(real_program_name);
1186          ccs_free(symlink_program_name);          ccs_free(symlink_program_name);
1187          *next_domain = domain ? domain : old_domain;          *next_domain = domain ? domain : old_domain;
1188          return retval;          return retval;
1189  }  }
1190    
1191    /**
1192     * check_environ - Check permission for environment variable names.
1193     *
1194     * @bprm: Pointer to "struct linux_binprm".
1195     * @tmp:  Buffer for temporal use.
1196     *
1197     * Returns 0 on success, negative value otherwise.
1198     */
1199    static int check_environ(struct linux_binprm *bprm, struct ccs_page_buffer *tmp)
1200    {
1201            const u8 profile = current->domain_info->profile;
1202            const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_ENV);
1203            char *arg_ptr = tmp->buffer;
1204            int arg_len = 0;
1205            unsigned long pos = bprm->p;
1206            int i = pos / PAGE_SIZE;
1207            int offset = pos % PAGE_SIZE;
1208            int argv_count = bprm->argc;
1209            int envp_count = bprm->envc;
1210            /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
1211            int error = -ENOMEM;
1212            if (!mode || !envp_count)
1213                    return 0;
1214            while (error == -ENOMEM) {
1215                    struct page *page;
1216                    const char *kaddr;
1217    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1218                    if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page,
1219                                       NULL) <= 0)
1220                            goto out;
1221                    pos += PAGE_SIZE - offset;
1222    #else
1223                    page = bprm->page[i];
1224    #endif
1225                    /* Map. */
1226                    kaddr = kmap(page);
1227                    if (!kaddr) { /* Mapping failed. */
1228    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1229                            put_page(page);
1230    #endif
1231                            goto out;
1232                    }
1233                    /* Read. */
1234                    while (argv_count && offset < PAGE_SIZE) {
1235                            if (!kaddr[offset++])
1236                                    argv_count--;
1237                    }
1238                    if (argv_count)
1239                            goto unmap_page;
1240                    while (offset < PAGE_SIZE) {
1241                            const unsigned char c = kaddr[offset++];
1242                            if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {
1243                                    if (c == '=') {
1244                                            arg_ptr[arg_len++] = '\0';
1245                                    } else if (c == '\\') {
1246                                            arg_ptr[arg_len++] = '\\';
1247                                            arg_ptr[arg_len++] = '\\';
1248                                    } else if (c > ' ' && c < 127) {
1249                                            arg_ptr[arg_len++] = c;
1250                                    } else {
1251                                            arg_ptr[arg_len++] = '\\';
1252                                            arg_ptr[arg_len++] = (c >> 6) + '0';
1253                                            arg_ptr[arg_len++]
1254                                                    = ((c >> 3) & 7) + '0';
1255                                            arg_ptr[arg_len++] = (c & 7) + '0';
1256                                    }
1257                            } else {
1258                                    arg_ptr[arg_len] = '\0';
1259                            }
1260                            if (c)
1261                                    continue;
1262                            if (ccs_check_env_perm(arg_ptr, profile, mode)) {
1263                                    error = -EPERM;
1264                                    break;
1265                            }
1266                            if (!--envp_count) {
1267                                    error = 0;
1268                                    break;
1269                            }
1270                            arg_len = 0;
1271                    }
1272     unmap_page:
1273                    /* Unmap. */
1274                    kunmap(page);
1275    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1276                    put_page(page);
1277  #endif  #endif
1278                    i++;
1279                    offset = 0;
1280            }
1281     out:
1282            if (error && mode != 3)
1283                    error = 0;
1284            return error;
1285    }
1286    
1287  int search_binary_handler_with_transition(struct linux_binprm *bprm, struct pt_regs *regs)  /**
1288     * unescape - Unescape escaped string.
1289     *
1290     * @dest: String to unescape.
1291     *
1292     * Returns nothing.
1293     */
1294    static void unescape(unsigned char *dest)
1295  {  {
1296          struct domain_info *next_domain = NULL, *prev_domain = current->domain_info;          unsigned char *src = dest;
1297          int retval;          unsigned char c;
1298  #if defined(CONFIG_SAKURA) || defined(CONFIG_TOMOYO)          unsigned char d;
1299          extern void CCS_LoadPolicy(const char *filename);          unsigned char e;
1300          CCS_LoadPolicy(bprm->filename);          while ((c = *src++) != '\0') {
1301                    if (c != '\\') {
1302                            *dest++ = c;
1303                            continue;
1304                    }
1305                    c = *src++;
1306                    if (c == '\\') {
1307                            *dest++ = c;
1308                            continue;
1309                    }
1310                    if (c < '0' || c > '3')
1311                            break;
1312                    d = *src++;
1313                    if (d < '0' || d > '7')
1314                            break;
1315                    e = *src++;
1316                    if (e < '0' || e > '7')
1317                            break;
1318                    *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
1319            }
1320            *dest = '\0';
1321    }
1322    
1323    /**
1324     * root_depth - Get number of directories to strip.
1325     *
1326     * @dentry: Pointer to "struct dentry".
1327     * @vfsmnt: Pointer to "struct vfsmount".
1328     *
1329     * Returns number of directories to strip.
1330     */
1331    static inline int root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
1332    {
1333            int depth = 0;
1334            /***** CRITICAL SECTION START *****/
1335            ccs_realpath_lock();
1336            for (;;) {
1337                    if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
1338                            /* Global root? */
1339                            if (vfsmnt->mnt_parent == vfsmnt)
1340                                    break;
1341                            dentry = vfsmnt->mnt_mountpoint;
1342                            vfsmnt = vfsmnt->mnt_parent;
1343                            continue;
1344                    }
1345                    dentry = dentry->d_parent;
1346                    depth++;
1347            }
1348            ccs_realpath_unlock();
1349            /***** CRITICAL SECTION END *****/
1350            return depth;
1351    }
1352    
1353    /**
1354     * get_root_depth - return the depth of root directory.
1355     *
1356     * Returns number of directories to strip.
1357     */
1358    static int get_root_depth(void)
1359    {
1360            int depth;
1361            struct dentry *dentry;
1362            struct vfsmount *vfsmnt;
1363    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1364            struct path root;
1365  #endif  #endif
1366  #if defined(CONFIG_TOMOYO)          /***** CRITICAL SECTION START *****/
1367          retval = FindNextDomain(bprm, &next_domain);          read_lock(&current->fs->lock);
1368    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1369            root = current->fs->root;
1370            path_get(&current->fs->root);
1371            dentry = root.dentry;
1372            vfsmnt = root.mnt;
1373  #else  #else
1374          retval = 0; next_domain = prev_domain;          dentry = dget(current->fs->root);
1375            vfsmnt = mntget(current->fs->rootmnt);
1376  #endif  #endif
1377          if (retval == 0) {          read_unlock(&current->fs->lock);
1378                  current->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;          /***** CRITICAL SECTION END *****/
1379                  current->domain_info = next_domain;          depth = root_depth(dentry, vfsmnt);
1380                  retval = search_binary_handler(bprm, regs);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
1381                  if (retval < 0) current->domain_info = prev_domain;          path_put(&root);
1382                  current->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;  #else
1383            dput(dentry);
1384            mntput(vfsmnt);
1385    #endif
1386            return depth;
1387    }
1388    
1389    /**
1390     * try_alt_exec - Try to start execute handler.
1391     *
1392     * @bprm:        Pointer to "struct linux_binprm".
1393     * @handler:     Pointer to the name of execute handler.
1394     * @eh_path:     Pointer to pointer to the name of execute handler.
1395     * @next_domain: Pointer to pointer to "struct domain_info".
1396     * @tmp:         Buffer for temporal use.
1397     *
1398     * Returns 0 on success, negative value otherwise.
1399     */
1400    static int try_alt_exec(struct linux_binprm *bprm,
1401                            const struct path_info *handler, char **eh_path,
1402                            struct domain_info **next_domain,
1403                            struct ccs_page_buffer *tmp)
1404    {
1405            /*
1406             * Contents of modified bprm.
1407             * The envp[] in original bprm is moved to argv[] so that
1408             * the alternatively executed program won't be affected by
1409             * some dangerous environment variables like LD_PRELOAD.
1410             *
1411             * modified bprm->argc
1412             *    = original bprm->argc + original bprm->envc + 7
1413             * modified bprm->envc
1414             *    = 0
1415             *
1416             * modified bprm->argv[0]
1417             *    = the program's name specified by execute_handler
1418             * modified bprm->argv[1]
1419             *    = current->domain_info->domainname->name
1420             * modified bprm->argv[2]
1421             *    = the current process's name
1422             * modified bprm->argv[3]
1423             *    = the current process's information (e.g. uid/gid).
1424             * modified bprm->argv[4]
1425             *    = original bprm->filename
1426             * modified bprm->argv[5]
1427             *    = original bprm->argc in string expression
1428             * modified bprm->argv[6]
1429             *    = original bprm->envc in string expression
1430             * modified bprm->argv[7]
1431             *    = original bprm->argv[0]
1432             *  ...
1433             * modified bprm->argv[bprm->argc + 6]
1434             *     = original bprm->argv[bprm->argc - 1]
1435             * modified bprm->argv[bprm->argc + 7]
1436             *     = original bprm->envp[0]
1437             *  ...
1438             * modified bprm->argv[bprm->envc + bprm->argc + 6]
1439             *     = original bprm->envp[bprm->envc - 1]
1440             */
1441            struct file *filp;
1442            int retval;
1443            const int original_argc = bprm->argc;
1444            const int original_envc = bprm->envc;
1445            struct task_struct *task = current;
1446            char *buffer = tmp->buffer;
1447            /* Allocate memory for execute handler's pathname. */
1448            char *execute_handler = ccs_alloc(sizeof(struct ccs_page_buffer));
1449            *eh_path = execute_handler;
1450            if (!execute_handler)
1451                    return -ENOMEM;
1452            strncpy(execute_handler, handler->name,
1453                    sizeof(struct ccs_page_buffer) - 1);
1454            unescape(execute_handler);
1455    
1456            /* Close the requested program's dentry. */
1457            allow_write_access(bprm->file);
1458            fput(bprm->file);
1459            bprm->file = NULL;
1460    
1461            { /* Adjust root directory for open_exec(). */
1462                    int depth = get_root_depth();
1463                    char *cp = execute_handler;
1464                    if (!*cp || *cp != '/')
1465                            return -ENOENT;
1466                    while (depth) {
1467                            cp = strchr(cp + 1, '/');
1468                            if (!cp)
1469                                    return -ENOENT;
1470                            depth--;
1471                    }
1472                    memmove(execute_handler, cp, strlen(cp) + 1);
1473            }
1474    
1475            /* Move envp[] to argv[] */
1476            bprm->argc += bprm->envc;
1477            bprm->envc = 0;
1478    
1479            /* Set argv[6] */
1480            {
1481                    snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1482                             original_envc);
1483                    retval = copy_strings_kernel(1, &buffer, bprm);
1484                    if (retval < 0)
1485                            goto out;
1486                    bprm->argc++;
1487            }
1488    
1489            /* Set argv[5] */
1490            {
1491                    snprintf(buffer, sizeof(struct ccs_page_buffer) - 1, "%d",
1492                             original_argc);
1493                    retval = copy_strings_kernel(1, &buffer, bprm);
1494                    if (retval < 0)
1495                            goto out;
1496                    bprm->argc++;
1497            }
1498    
1499            /* Set argv[4] */
1500            {
1501                    retval = copy_strings_kernel(1, &bprm->filename, bprm);
1502                    if (retval < 0)
1503                            goto out;
1504                    bprm->argc++;
1505            }
1506    
1507            /* Set argv[3] */
1508            {
1509                    const u32 tomoyo_flags = task->tomoyo_flags;
1510                    snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1511                             "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1512                             "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1513                             "state[1]=%u state[2]=%u",
1514                             task->pid, task->uid, task->gid, task->euid,
1515                             task->egid, task->suid, task->sgid, task->fsuid,
1516                             task->fsgid, (u8) (tomoyo_flags >> 24),
1517                             (u8) (tomoyo_flags >> 16), (u8) (tomoyo_flags >> 8));
1518                    retval = copy_strings_kernel(1, &buffer, bprm);
1519                    if (retval < 0)
1520                            goto out;
1521                    bprm->argc++;
1522            }
1523    
1524            /* Set argv[2] */
1525            {
1526                    char *exe = (char *) ccs_get_exe();
1527                    if (exe) {
1528                            retval = copy_strings_kernel(1, &exe, bprm);
1529                            ccs_free(exe);
1530                    } else {
1531                            snprintf(buffer, sizeof(struct ccs_page_buffer) - 1,
1532                                     "<unknown>");
1533                            retval = copy_strings_kernel(1, &buffer, bprm);
1534                    }
1535                    if (retval < 0)
1536                            goto out;
1537                    bprm->argc++;
1538            }
1539    
1540            /* Set argv[1] */
1541            {
1542                    strncpy(buffer, task->domain_info->domainname->name,
1543                            sizeof(struct ccs_page_buffer) - 1);
1544                    retval = copy_strings_kernel(1, &buffer, bprm);
1545                    if (retval < 0)
1546                            goto out;
1547                    bprm->argc++;
1548          }          }
1549    
1550            /* Set argv[0] */
1551            {
1552                    retval = copy_strings_kernel(1, &execute_handler, bprm);
1553                    if (retval < 0)
1554                            goto out;
1555                    bprm->argc++;
1556            }
1557    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1558    #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1559            bprm->argv_len = bprm->exec - bprm->p;
1560    #endif
1561    #endif
1562    
1563            /* OK, now restart the process with execute handler program's dentry. */
1564            filp = open_exec(execute_handler);
1565            if (IS_ERR(filp)) {
1566                    retval = PTR_ERR(filp);
1567                    goto out;
1568            }
1569            bprm->file = filp;
1570            bprm->filename = execute_handler;
1571    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1572            bprm->interp = execute_handler;
1573    #endif
1574            retval = prepare_binprm(bprm);
1575            if (retval < 0)
1576                    goto out;
1577            task->tomoyo_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1578            retval = find_next_domain(bprm, next_domain, handler, tmp);
1579            task->tomoyo_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1580     out:
1581          return retval;          return retval;
1582  }  }
1583    
1584  /***** TOMOYO Linux end. *****/  /**
1585     * find_execute_handler - Find an execute handler.
1586     *
1587     * @type: Type of execute handler.
1588     *
1589     * Returns pointer to "struct path_info" if found, NULL otherwise.
1590     */
1591    static const struct path_info *find_execute_handler(const u8 type)
1592    {
1593            struct task_struct *task = current;
1594            const struct domain_info *domain = task->domain_info;
1595            struct acl_info *ptr;
1596            /*
1597             * Don't use execute handler if the current process is
1598             * marked as execute handler to avoid infinite execute handler loop.
1599             */
1600            if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)
1601                    return NULL;
1602            list1_for_each_entry(ptr, &domain->acl_info_list, list) {
1603                    struct execute_handler_record *acl;
1604                    if (ptr->type != type)
1605                            continue;
1606                    acl = container_of(ptr, struct execute_handler_record, head);
1607                    return acl->handler;
1608            }
1609            return NULL;
1610    }
1611    
1612    /**
1613     * search_binary_handler_with_transition - Perform domain transition.
1614     *
1615     * @bprm: Pointer to "struct linux_binprm".
1616     * @regs: Pointer to "struct pt_regs".
1617     *
1618     * Returns result of search_binary_handler() on success,
1619     * negative value otherwise.
1620     */
1621    int search_binary_handler_with_transition(struct linux_binprm *bprm,
1622                                              struct pt_regs *regs)
1623    {
1624            struct task_struct *task = current;
1625            struct domain_info *next_domain = NULL;
1626            struct domain_info *prev_domain = task->domain_info;
1627            const struct path_info *handler;
1628            int retval;
1629            /*
1630             * "eh_path" holds path to execute handler program.
1631             * Thus, keep valid until search_binary_handler() finishes.
1632             */
1633            char *eh_path = NULL;
1634            struct ccs_page_buffer *tmp = ccs_alloc(sizeof(struct ccs_page_buffer));
1635            ccs_load_policy(bprm->filename);
1636            if (!tmp)
1637                    return -ENOMEM;
1638            /* printk(KERN_DEBUG "rootdepth=%d\n", get_root_depth()); */
1639            handler = find_execute_handler(TYPE_EXECUTE_HANDLER);
1640            if (handler) {
1641                    retval = try_alt_exec(bprm, handler, &eh_path, &next_domain,
1642                                          tmp);
1643                    if (!retval)
1644                            audit_execute_handler_log(true, handler->name, bprm);
1645                    goto ok;
1646            }
1647            retval = find_next_domain(bprm, &next_domain, NULL, tmp);
1648            if (retval != -EPERM)
1649                    goto ok;
1650            handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER);
1651            if (handler) {
1652                    retval = try_alt_exec(bprm, handler, &eh_path, &next_domain,
1653                                          tmp);
1654                    if (!retval)
1655                            audit_execute_handler_log(false, handler->name, bprm);
1656            }
1657     ok:
1658            if (retval < 0)
1659                    goto out;
1660            task->domain_info = next_domain;
1661            retval = check_environ(bprm, tmp);
1662            if (retval < 0)
1663                    goto out;
1664            task->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1665            retval = search_binary_handler(bprm, regs);
1666            task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;
1667     out:
1668            /* Return to previous domain if execution failed. */
1669            if (retval < 0)
1670                    task->domain_info = prev_domain;
1671            /* Mark the current process as execute handler. */
1672            else if (handler)
1673                    task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER;
1674            /* Mark the current process as normal process. */
1675            else
1676                    task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER;
1677            ccs_free(eh_path);
1678            ccs_free(tmp);
1679            return retval;
1680    }
1681    
1682    #else
1683    
1684    /**
1685     * search_binary_handler_with_transition - Wrapper for search_binary_handler().
1686     *
1687     * @bprm: Pointer to "struct linux_binprm".
1688     * @regs: Pointer to "struct pt_regs".
1689     *
1690     * Returns the result of search_binary_handler().
1691     */
1692    int search_binary_handler_with_transition(struct linux_binprm *bprm,
1693                                              struct pt_regs *regs)
1694    {
1695    #ifdef CONFIG_SAKURA
1696            ccs_load_policy(bprm->filename);
1697    #endif
1698            return search_binary_handler(bprm, regs);
1699    }
1700    
1701    #endif

Legend:
Removed from v.329  
changed lines
  Added in v.1561

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