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

Subversion リポジトリの参照

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

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

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

Legend:
Removed from v.512  
changed lines
  Added in v.2702

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