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

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

Legend:
Removed from v.111  
changed lines
  Added in v.1498

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