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

Subversion リポジトリの参照

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

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

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

Legend:
Removed from v.150  
changed lines
  Added in v.1719

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