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

Subversion リポジトリの参照

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

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

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

Legend:
Removed from v.987  
changed lines
  Added in v.1800

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