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

Subversion リポジトリの参照

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

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

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

Legend:
Removed from v.1032  
changed lines
  Added in v.1052

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