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

Subversion リポジトリの参照

Diff of /trunk/1.8.x/ccs-patch/security/ccsecurity/domain.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

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

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