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

Subversion リポジトリの参照

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

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

branches/ccs-patch/fs/tomoyo_domain.c revision 2702 by kumaneko, Tue Jun 30 03:49:41 2009 UTC branches/ccs-patch/security/ccsecurity/domain.c revision 3694 by kumaneko, Sun May 23 11:52:53 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Version: 1.7.2+   2010/05/05
  *  
  * Version: 1.6.8   2009/05/28  
7   *   *
8   * 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.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
10   *   *
11   */   */
12    
13  #include <linux/ccs_common.h>  #include <linux/slab.h>
 #include <linux/tomoyo.h>  
 #include <linux/realpath.h>  
14  #include <linux/highmem.h>  #include <linux/highmem.h>
15    #include <linux/version.h>
16  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17  #include <linux/namei.h>  #include <linux/namei.h>
18  #include <linux/mount.h>  #include <linux/mount.h>
# Line 23  Line 20 
20  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
21  #include <linux/fs_struct.h>  #include <linux/fs_struct.h>
22  #endif  #endif
23    #include "internal.h"
 /* For compatibility with older kernels. */  
 #ifndef for_each_process  
 #define for_each_process for_each_task  
 #endif  
24    
25  /* Variables definitions.*/  /* Variables definitions.*/
26    
# Line 37  struct ccs_domain_info ccs_kernel_domain Line 30  struct ccs_domain_info ccs_kernel_domain
30  /* The list for "struct ccs_domain_info". */  /* The list for "struct ccs_domain_info". */
31  LIST_HEAD(ccs_domain_list);  LIST_HEAD(ccs_domain_list);
32    
33  #ifdef CONFIG_TOMOYO  struct list_head ccs_policy_list[CCS_MAX_POLICY];
34    struct list_head ccs_group_list[CCS_MAX_GROUP];
35    struct list_head ccs_shared_list[CCS_MAX_LIST];
36    
37  /**  /**
38   * ccs_get_last_name - Get last component of a domainname.   * ccs_audit_execute_handler_log - Audit execute_handler log.
39   *   *
40   * @domain: Pointer to "struct ccs_domain_info".   * @ee:         Pointer to "struct ccs_execve".
41   *   *
42   * Returns the last component of the domainname.   * Returns 0 on success, negative value otherwise.
43   */   */
44  const char *ccs_get_last_name(const struct ccs_domain_info *domain)  static int ccs_audit_execute_handler_log(struct ccs_execve *ee)
45  {  {
46          const char *cp0 = domain->domainname->name;          struct ccs_request_info *r = &ee->r;
47          const char *cp1 = strrchr(cp0, ' ');          const char *handler = ee->handler->name;
48          if (cp1)          r->type = CCS_MAC_FILE_EXECUTE;
49                  return cp1 + 1;          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
50          return cp0;          return ccs_write_log(true, r, "%s %s\n", ee->handler_type ==
51                                 CCS_TYPE_DENIED_EXECUTE_HANDLER ?
52                                 CCS_KEYWORD_DENIED_EXECUTE_HANDLER :
53                                 CCS_KEYWORD_EXECUTE_HANDLER, handler);
54  }  }
55    
56  /**  /**
57   * ccs_add_domain_acl - Add the given ACL to the given domain.   * ccs_audit_domain_creation_log - Audit domain creation log.
  *  
  * @domain: Pointer to "struct ccs_domain_info". May be NULL.  
  * @acl:    Pointer to "struct ccs_acl_info".  
58   *   *
59   * Returns 0.   * Returns 0 on success, negative value otherwise.
60   */   */
61  int ccs_add_domain_acl(struct ccs_domain_info *domain, struct ccs_acl_info *acl)  static int ccs_audit_domain_creation_log(void)
62  {  {
63          if (domain) {          struct ccs_request_info r;
64                  if (acl->cond)          ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
65                          atomic_inc(&acl->cond->users);          return ccs_write_log(false, &r, "use_profile %u\n", r.profile);
                 list_add_tail_rcu(&acl->list, &domain->acl_info_list);  
         } else {  
                 acl->type &= ~ACL_DELETED;  
         }  
         ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
         return 0;  
66  }  }
67    
68  /**  int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
69   * ccs_del_domain_acl - Delete the given ACL from the domain.                        bool is_delete, const int idx, bool (*check_duplicate)
70   *                        (const struct ccs_acl_head *,
71   * @acl: Pointer to "struct ccs_acl_info". May be NULL.                         const struct ccs_acl_head *))
  *  
  * Returns 0.  
  */  
 int ccs_del_domain_acl(struct ccs_acl_info *acl)  
72  {  {
73          if (acl)          int error = is_delete ? -ENOENT : -ENOMEM;
74                  acl->type |= ACL_DELETED;          struct ccs_acl_head *entry;
75          ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);          if (mutex_lock_interruptible(&ccs_policy_lock))
76          return 0;                  return -ENOMEM;
77            list_for_each_entry_rcu(entry, &ccs_policy_list[idx], list) {
78                    if (!check_duplicate(entry, new_entry))
79                            continue;
80                    entry->is_deleted = is_delete;
81                    error = 0;
82                    break;
83            }
84            if (error && !is_delete) {
85                    entry = ccs_commit_ok(new_entry, size);
86                    if (entry) {
87                            list_add_tail_rcu(&entry->list, &ccs_policy_list[idx]);
88                            error = 0;
89                    }
90            }
91            mutex_unlock(&ccs_policy_lock);
92            return error;
93  }  }
94    
95  /**  int ccs_update_group(struct ccs_acl_head *new_entry, const int size,
96   * ccs_audit_execute_handler_log - Audit execute_handler log.                       bool is_delete, struct ccs_group *group,
97   *                       bool (*check_duplicate) (const struct ccs_acl_head *,
98   * @ee:         Pointer to "struct ccs_execve_entry".                                                const struct ccs_acl_head *))
  * @is_default: True if it is "execute_handler" log.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,  
                                          const bool is_default)  
99  {  {
100          struct ccs_request_info *r = &ee->r;          int error = is_delete ? -ENOENT : -ENOMEM;
101          const char *handler = ee->handler->name;          struct ccs_acl_head *entry;
102          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_FILE);          if (mutex_lock_interruptible(&ccs_policy_lock))
103          return ccs_write_audit_log(true, r, "%s %s\n",                  return -ENOMEM;
104                                     is_default ? KEYWORD_EXECUTE_HANDLER :          list_for_each_entry_rcu(entry, &group->member_list, list) {
105                                     KEYWORD_DENIED_EXECUTE_HANDLER, handler);                  if (!check_duplicate(entry, new_entry))
106                            continue;
107                    entry->is_deleted = is_delete;
108                    error = 0;
109                    break;
110            }
111            if (!is_delete && error) {
112                    entry = ccs_commit_ok(new_entry, size);
113                    if (entry) {
114                            list_add_tail_rcu(&entry->list, &group->member_list);
115                            error = 0;
116                    }
117            }
118            mutex_unlock(&ccs_policy_lock);
119            return error;
120  }  }
121    
122  /**  int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
123   * ccs_audit_domain_creation_log - Audit domain creation log.                        bool is_delete, struct ccs_domain_info *domain,
124   *                        bool (*check_duplicate) (const struct ccs_acl_info *,
125   * @domain:  Pointer to "struct ccs_domain_info".                                                 const struct ccs_acl_info *),
126   *                        bool (*merge_duplicate) (struct ccs_acl_info *,
127   * Returns 0 on success, negative value otherwise.                                                 struct ccs_acl_info *,
128   */                                                 const bool))
 static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  
129  {  {
130          int error;          int error = is_delete ? -ENOENT : -ENOMEM;
131          struct ccs_request_info r;          struct ccs_acl_info *entry;
132          ccs_init_request_info(&r, domain, CCS_MAC_FOR_FILE);          if (mutex_lock_interruptible(&ccs_policy_lock))
133          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);                  return error;
134            list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
135                    if (!check_duplicate(entry, new_entry))
136                            continue;
137                    if (merge_duplicate)
138                            entry->is_deleted = merge_duplicate(entry, new_entry,
139                                                                is_delete);
140                    else
141                            entry->is_deleted = is_delete;
142                    error = 0;
143                    break;
144            }
145            if (error && !is_delete) {
146                    entry = ccs_commit_ok(new_entry, size);
147                    if (entry) {
148                            ccs_add_domain_acl(domain, entry);
149                            error = 0;
150                    }
151            }
152            mutex_unlock(&ccs_policy_lock);
153          return error;          return error;
154  }  }
155    
156  /* The list for "struct ccs_domain_initializer_entry". */  static bool ccs_same_domain_initializer_entry(const struct ccs_acl_head *a,
157  LIST_HEAD(ccs_domain_initializer_list);                                                   const struct ccs_acl_head *b)
158    {
159            const struct ccs_domain_initializer *p1 =
160                    container_of(a, typeof(*p1), head);
161            const struct ccs_domain_initializer *p2 =
162                    container_of(b, typeof(*p2), head);
163            return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
164                    && p1->domainname == p2->domainname
165                    && p1->program == p2->program;
166    }
167    
168  /**  /**
169   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer" list.
170   *   *
171   * @domainname: The name of domain. May be NULL.   * @domainname: The name of domain. May be NULL.
172   * @program:    The name of program.   * @program:    The name of program.
# Line 144  static int ccs_update_domain_initializer Line 180  static int ccs_update_domain_initializer
180                                                 const bool is_not,                                                 const bool is_not,
181                                                 const bool is_delete)                                                 const bool is_delete)
182  {  {
183          struct ccs_domain_initializer_entry *entry = NULL;          struct ccs_domain_initializer e = { .is_not = is_not };
         struct ccs_domain_initializer_entry *ptr;  
         const struct ccs_path_info *saved_program;  
         const struct ccs_path_info *saved_domainname = NULL;  
184          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
185          bool is_last_name = false;          if (!ccs_correct_path(program, 1, -1, -1))
         if (!ccs_is_correct_path(program, 1, -1, -1))  
186                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
187          if (domainname) {          if (domainname) {
188                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_domain_def(domainname) &&
189                      ccs_is_correct_path(domainname, 1, -1, -1))                      ccs_correct_path(domainname, 1, -1, -1))
190                          is_last_name = true;                          e.is_last_name = true;
191                  else if (!ccs_is_correct_domain(domainname))                  else if (!ccs_correct_domain(domainname))
192                          return -EINVAL;                          return -EINVAL;
193                  saved_domainname = ccs_get_name(domainname);                  e.domainname = ccs_get_name(domainname);
194                  if (!saved_domainname)                  if (!e.domainname)
195                          return -ENOMEM;                          goto out;
         }  
         saved_program = ccs_get_name(program);  
         if (!saved_program) {  
                 ccs_put_name(saved_domainname);  
                 return -ENOMEM;  
         }  
         if (!is_delete)  
                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);  
         mutex_lock(&ccs_policy_lock);  
         list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {  
                 if (ptr->is_not != is_not ||  
                     ptr->domainname != saved_domainname ||  
                     ptr->program != saved_program)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_memory_ok(entry)) {  
                 entry->domainname = saved_domainname;  
                 saved_domainname = NULL;  
                 entry->program = saved_program;  
                 saved_program = NULL;  
                 entry->is_not = is_not;  
                 entry->is_last_name = is_last_name;  
                 list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);  
                 entry = NULL;  
                 error = 0;  
196          }          }
197          mutex_unlock(&ccs_policy_lock);          e.program = ccs_get_name(program);
198          ccs_put_name(saved_domainname);          if (!e.program)
199          ccs_put_name(saved_program);                  goto out;
200          kfree(entry);          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
201          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);                                    CCS_ID_DOMAIN_INITIALIZER,
202                                      ccs_same_domain_initializer_entry);
203     out:
204            ccs_put_name(e.domainname);
205            ccs_put_name(e.program);
206          return error;          return error;
207  }  }
208    
209  /**  /**
210   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.   * ccs_write_domain_initializer - Write "struct ccs_domain_initializer" list.
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds srcu_read_lock(&ccs_ss).  
  */  
 bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  
 {  
         struct list_head *pos;  
         bool done = true;  
         list_for_each_cookie(pos, head->read_var2,  
                              &ccs_domain_initializer_list) {  
                 const char *no;  
                 const char *from = "";  
                 const char *domain = "";  
                 struct ccs_domain_initializer_entry *ptr;  
                 ptr = list_entry(pos, struct ccs_domain_initializer_entry,  
                                   list);  
                 if (ptr->is_deleted)  
                         continue;  
                 no = ptr->is_not ? "no_" : "";  
                 if (ptr->domainname) {  
                         from = " from ";  
                         domain = ptr->domainname->name;  
                 }  
                 done = ccs_io_printf(head,  
                                      "%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n",  
                                      no, ptr->program->name, from, domain);  
                 if (!done)  
                         break;  
         }  
         return done;  
 }  
   
 /**  
  * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.  
211   *   *
212   * @data:      String to parse.   * @data:      String to parse.
  * @is_not:    True if it is "no_initialize_domain" entry.  
213   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
214   *   *
215   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
216   */   */
217  int ccs_write_domain_initializer_policy(char *data, const bool is_not,  int ccs_write_domain_initializer(char *data, const bool is_delete, const u8 flags)
                                         const bool is_delete)  
218  {  {
219          char *cp = strstr(data, " from ");          char *domainname = strstr(data, " from ");
220          if (cp) {          if (domainname) {
221                  *cp = '\0';                  *domainname = '\0';
222                  return ccs_update_domain_initializer_entry(cp + 6, data,                  domainname += 6;
                                                            is_not, is_delete);  
223          }          }
224          return ccs_update_domain_initializer_entry(NULL, data, is_not,          return ccs_update_domain_initializer_entry(domainname, data, flags,
225                                                     is_delete);                                                     is_delete);
226  }  }
227    
228  /**  /**
229   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.   * ccs_domain_initializer - Check whether the given program causes domainname reinitialization.
230   *   *
231   * @domainname: The name of domain.   * @domainname: The name of domain.
232   * @program:    The name of program.   * @program:    The name of program.
# Line 267  int ccs_write_domain_initializer_policy( Line 235  int ccs_write_domain_initializer_policy(
235   * Returns true if executing @program reinitializes domain transition,   * Returns true if executing @program reinitializes domain transition,
236   * false otherwise.   * false otherwise.
237   *   *
238   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
239   */   */
240  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,  static bool ccs_domain_initializer(const struct ccs_path_info *domainname,
241                                        const struct ccs_path_info *program,                                        const struct ccs_path_info *program,
242                                        const struct ccs_path_info *last_name)                                        const struct ccs_path_info *last_name)
243  {  {
244          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer *ptr;
245          bool flag = false;          bool flag = false;
246          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_policy_list
247                  if (ptr->is_deleted)                                  [CCS_ID_DOMAIN_INITIALIZER], head.list) {
248                    if (ptr->head.is_deleted)
249                          continue;                          continue;
250                  if (ptr->domainname) {                  if (ptr->domainname) {
251                          if (!ptr->is_last_name) {                          if (!ptr->is_last_name) {
# Line 298  static bool ccs_is_domain_initializer(co Line 267  static bool ccs_is_domain_initializer(co
267          return flag;          return flag;
268  }  }
269    
270  /* The list for "struct ccs_domain_keeper_entry". */  static bool ccs_same_domain_keeper_entry(const struct ccs_acl_head *a,
271  LIST_HEAD(ccs_domain_keeper_list);                                              const struct ccs_acl_head *b)
272    {
273            const struct ccs_domain_keeper *p1 =
274                    container_of(a, typeof(*p1), head);
275            const struct ccs_domain_keeper *p2 =
276                    container_of(b, typeof(*p2), head);
277            return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
278                    && p1->domainname == p2->domainname
279                    && p1->program == p2->program;
280    }
281    
282  /**  /**
283   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper" list.
284   *   *
285   * @domainname: The name of domain.   * @domainname: The name of domain.
286   * @program:    The name of program. May be NULL.   * @program:    The name of program. May be NULL.
# Line 316  static int ccs_update_domain_keeper_entr Line 294  static int ccs_update_domain_keeper_entr
294                                            const bool is_not,                                            const bool is_not,
295                                            const bool is_delete)                                            const bool is_delete)
296  {  {
297          struct ccs_domain_keeper_entry *entry = NULL;          struct ccs_domain_keeper e = { .is_not = is_not };
         struct ccs_domain_keeper_entry *ptr;  
         const struct ccs_path_info *saved_domainname;  
         const struct ccs_path_info *saved_program = NULL;  
298          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
299          bool is_last_name = false;          if (!ccs_domain_def(domainname) &&
300          if (!ccs_is_domain_def(domainname) &&              ccs_correct_path(domainname, 1, -1, -1))
301              ccs_is_correct_path(domainname, 1, -1, -1))                  e.is_last_name = true;
302                  is_last_name = true;          else if (!ccs_correct_domain(domainname))
         else if (!ccs_is_correct_domain(domainname))  
303                  return -EINVAL;                  return -EINVAL;
304          if (program) {          if (program) {
305                  if (!ccs_is_correct_path(program, 1, -1, -1))                  if (!ccs_correct_path(program, 1, -1, -1))
306                          return -EINVAL;                          return -EINVAL;
307                  saved_program = ccs_get_name(program);                  e.program = ccs_get_name(program);
308                  if (!saved_program)                  if (!e.program)
309                          return -ENOMEM;                          goto out;
         }  
         saved_domainname = ccs_get_name(domainname);  
         if (!saved_domainname) {  
                 ccs_put_name(saved_program);  
                 return -ENOMEM;  
         }  
         if (!is_delete)  
                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);  
         mutex_lock(&ccs_policy_lock);  
         list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {  
                 if (ptr->is_not != is_not ||  
                     ptr->domainname != saved_domainname ||  
                     ptr->program != saved_program)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_memory_ok(entry)) {  
                 entry->domainname = saved_domainname;  
                 saved_domainname = NULL;  
                 entry->program = saved_program;  
                 saved_program = NULL;  
                 entry->is_not = is_not;  
                 entry->is_last_name = is_last_name;  
                 list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);  
                 entry = NULL;  
                 error = 0;  
310          }          }
311          mutex_unlock(&ccs_policy_lock);          e.domainname = ccs_get_name(domainname);
312          ccs_put_name(saved_domainname);          if (!e.domainname)
313          ccs_put_name(saved_program);                  goto out;
314          kfree(entry);          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
315          ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);                                    CCS_ID_DOMAIN_KEEPER,
316                                      ccs_same_domain_keeper_entry);
317     out:
318            ccs_put_name(e.domainname);
319            ccs_put_name(e.program);
320          return error;          return error;
321  }  }
322    
323  /**  /**
324   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.   * ccs_write_domain_keeper - Write "struct ccs_domain_keeper" list.
325   *   *
326   * @data:      String to parse.   * @data:      String to parse.
  * @is_not:    True if it is "no_keep_domain" entry.  
327   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
328   *   *
329     * Returns 0 on success, negative value otherwise.
330   */   */
331  int ccs_write_domain_keeper_policy(char *data, const bool is_not,  int ccs_write_domain_keeper(char *data, const bool is_delete, const u8 flags)
                                    const bool is_delete)  
 {  
         char *cp = strstr(data, " from ");  
         if (cp) {  
                 *cp = '\0';  
                 return ccs_update_domain_keeper_entry(cp + 6, data,  
                                                       is_not, is_delete);  
         }  
         return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);  
 }  
   
 /**  
  * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds srcu_read_lock(&ccs_ss).  
  */  
 bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  
332  {  {
333          struct list_head *pos;          char *domainname = strstr(data, " from ");
334          bool done = true;          if (domainname) {
335          list_for_each_cookie(pos, head->read_var2,                  *domainname = '\0';
336                               &ccs_domain_keeper_list) {                  domainname += 6;
337                  struct ccs_domain_keeper_entry *ptr;          } else {
338                  const char *no;                  domainname = data;
339                  const char *from = "";                  data = NULL;
                 const char *program = "";  
                 ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);  
                 if (ptr->is_deleted)  
                         continue;  
                 no = ptr->is_not ? "no_" : "";  
                 if (ptr->program) {  
                         from = " from ";  
                         program = ptr->program->name;  
                 }  
                 done = ccs_io_printf(head,  
                                      "%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no,  
                                      program, from, ptr->domainname->name);  
                 if (!done)  
                         break;  
340          }          }
341          return done;          return ccs_update_domain_keeper_entry(domainname, data, flags,
342                                                  is_delete);
343  }  }
344    
345  /**  /**
346   * ccs_is_domain_keeper - Check whether the given program causes domain transition suppression.   * ccs_domain_keeper - Check whether the given program causes domain transition suppression.
347   *   *
348   * @domainname: The name of domain.   * @domainname: The name of domain.
349   * @program:    The name of program.   * @program:    The name of program.
# Line 436  bool ccs_read_domain_keeper_policy(struc Line 352  bool ccs_read_domain_keeper_policy(struc
352   * Returns true if executing @program supresses domain transition,   * Returns true if executing @program supresses domain transition,
353   * false otherwise.   * false otherwise.
354   *   *
355   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
356   */   */
357  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static bool ccs_domain_keeper(const struct ccs_path_info *domainname,
358                                   const struct ccs_path_info *program,                                   const struct ccs_path_info *program,
359                                   const struct ccs_path_info *last_name)                                   const struct ccs_path_info *last_name)
360  {  {
361          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper *ptr;
362          bool flag = false;          bool flag = false;
363          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_policy_list[CCS_ID_DOMAIN_KEEPER],
364                  if (ptr->is_deleted)                                  head.list) {
365                    if (ptr->head.is_deleted)
366                          continue;                          continue;
367                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
368                          if (ptr->domainname != domainname)                          if (ptr->domainname != domainname)
# Line 465  static bool ccs_is_domain_keeper(const s Line 382  static bool ccs_is_domain_keeper(const s
382          return flag;          return flag;
383  }  }
384    
385  /* The list for "struct ccs_alias_entry". */  static bool ccs_same_aggregator_entry(const struct ccs_acl_head *a,
386  LIST_HEAD(ccs_alias_list);                                           const struct ccs_acl_head *b)
   
 /**  
  * ccs_update_alias_entry - Update "struct ccs_alias_entry" list.  
  *  
  * @original_name: The original program's real name.  
  * @aliased_name:  The symbolic program's symbolic link's name.  
  * @is_delete:     True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 static int ccs_update_alias_entry(const char *original_name,  
                                   const char *aliased_name,  
                                   const bool is_delete)  
 {  
         struct ccs_alias_entry *entry = NULL;  
         struct ccs_alias_entry *ptr;  
         const struct ccs_path_info *saved_original_name;  
         const struct ccs_path_info *saved_aliased_name;  
         int error = is_delete ? -ENOENT : -ENOMEM;  
         if (!ccs_is_correct_path(original_name, 1, -1, -1) ||  
             !ccs_is_correct_path(aliased_name, 1, -1, -1))  
                 return -EINVAL; /* No patterns allowed. */  
         saved_original_name = ccs_get_name(original_name);  
         saved_aliased_name = ccs_get_name(aliased_name);  
         if (!saved_original_name || !saved_aliased_name) {  
                 ccs_put_name(saved_original_name);  
                 ccs_put_name(saved_aliased_name);  
                 return -ENOMEM;  
         }  
         if (!is_delete)  
                 entry = kzalloc(sizeof(*entry), GFP_KERNEL);  
         mutex_lock(&ccs_policy_lock);  
         list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {  
                 if (ptr->original_name != saved_original_name ||  
                     ptr->aliased_name != saved_aliased_name)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_memory_ok(entry)) {  
                 entry->original_name = saved_original_name;  
                 saved_original_name = NULL;  
                 entry->aliased_name = saved_aliased_name;  
                 saved_aliased_name = NULL;  
                 list_add_tail_rcu(&entry->list, &ccs_alias_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
         ccs_put_name(saved_original_name);  
         ccs_put_name(saved_aliased_name);  
         kfree(entry);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
         return error;  
 }  
   
 /**  
  * ccs_read_alias_policy - Read "struct ccs_alias_entry" list.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds srcu_read_lock(&ccs_ss).  
  */  
 bool ccs_read_alias_policy(struct ccs_io_buffer *head)  
387  {  {
388          struct list_head *pos;          const struct ccs_aggregator *p1 =
389          bool done = true;                  container_of(a, typeof(*p1), head);
390          list_for_each_cookie(pos, head->read_var2, &ccs_alias_list) {          const struct ccs_aggregator *p2 =
391                  struct ccs_alias_entry *ptr;                  container_of(b, typeof(*p2), head);
392                  ptr = list_entry(pos, struct ccs_alias_entry, list);          return p1->original_name == p2->original_name &&
393                  if (ptr->is_deleted)                  p1->aggregated_name == p2->aggregated_name;
                         continue;  
                 done = ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n",  
                                      ptr->original_name->name,  
                                      ptr->aliased_name->name);  
                 if (!done)  
                         break;  
         }  
         return done;  
394  }  }
395    
396  /**  /**
397   * ccs_write_alias_policy - Write "struct ccs_alias_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator" list.
  *  
  * @data:      String to parse.  
  * @is_delete: True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 int ccs_write_alias_policy(char *data, const bool is_delete)  
 {  
         char *cp = strchr(data, ' ');  
         if (!cp)  
                 return -EINVAL;  
         *cp++ = '\0';  
         return ccs_update_alias_entry(data, cp, is_delete);  
 }  
   
 /* The list for "struct ccs_aggregator_entry". */  
 LIST_HEAD(ccs_aggregator_list);  
   
 /**  
  * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.  
398   *   *
399   * @original_name:   The original program's name.   * @original_name:   The original program's name.
400   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 584  static int ccs_update_aggregator_entry(c Line 406  static int ccs_update_aggregator_entry(c
406                                         const char *aggregated_name,                                         const char *aggregated_name,
407                                         const bool is_delete)                                         const bool is_delete)
408  {  {
409          struct ccs_aggregator_entry *entry = NULL;          struct ccs_aggregator e = { };
         struct ccs_aggregator_entry *ptr;  
         const struct ccs_path_info *saved_original_name;  
         const struct ccs_path_info *saved_aggregated_name;  
410          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
411          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||          if (!ccs_correct_path(original_name, 1, 0, -1) ||
412              !ccs_is_correct_path(aggregated_name, 1, -1, -1))              !ccs_correct_path(aggregated_name, 1, -1, -1))
413                  return -EINVAL;                  return -EINVAL;
414          saved_original_name = ccs_get_name(original_name);          e.original_name = ccs_get_name(original_name);
415          saved_aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
416          if (!saved_original_name || !saved_aggregated_name) {          if (!e.original_name || !e.aggregated_name)
417                  ccs_put_name(saved_original_name);                  goto out;
418                  ccs_put_name(saved_aggregated_name);          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
419                  return -ENOMEM;                                    CCS_ID_AGGREGATOR,
420          }                                    ccs_same_aggregator_entry);
421          if (!is_delete)   out:
422                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);          ccs_put_name(e.original_name);
423          mutex_lock(&ccs_policy_lock);          ccs_put_name(e.aggregated_name);
         list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {  
                 if (ptr->original_name != saved_original_name ||  
                     ptr->aggregated_name != saved_aggregated_name)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_memory_ok(entry)) {  
                 entry->original_name = saved_original_name;  
                 saved_original_name = NULL;  
                 entry->aggregated_name = saved_aggregated_name;  
                 saved_aggregated_name = NULL;  
                 list_add_tail_rcu(&entry->list, &ccs_aggregator_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
         ccs_put_name(saved_original_name);  
         ccs_put_name(saved_aggregated_name);  
         kfree(entry);  
         ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
424          return error;          return error;
425  }  }
426    
427  /**  /**
428   * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.   * ccs_write_aggregator - Write "struct ccs_aggregator" list.
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds srcu_read_lock(&ccs_ss).  
  */  
 bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)  
 {  
         struct list_head *pos;  
         bool done = true;  
         list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {  
                 struct ccs_aggregator_entry *ptr;  
                 ptr = list_entry(pos, struct ccs_aggregator_entry, list);  
                 if (ptr->is_deleted)  
                         continue;  
                 done = ccs_io_printf(head, KEYWORD_AGGREGATOR "%s %s\n",  
                                      ptr->original_name->name,  
                                      ptr->aggregated_name->name);  
                 if (!done)  
                         break;  
         }  
         return done;  
 }  
   
 /**  
  * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.  
429   *   *
430   * @data:      String to parse.   * @data:      String to parse.
431   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
432   *   *
433   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
434   */   */
435  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator(char *data, const bool is_delete, const u8 flags)
436  {  {
437          char *cp = strchr(data, ' ');          char *w[2];
438          if (!cp)          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
439                  return -EINVAL;                  return -EINVAL;
440          *cp++ = '\0';          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
         return ccs_update_aggregator_entry(data, cp, is_delete);  
441  }  }
442    
443  /* Domain create/delete handler. */  /* Domain create/delete handler. */
# Line 686  int ccs_delete_domain(char *domainname) Line 455  int ccs_delete_domain(char *domainname)
455          struct ccs_path_info name;          struct ccs_path_info name;
456          name.name = domainname;          name.name = domainname;
457          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
458          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
459                    return 0;
460          /* Is there an active domain? */          /* Is there an active domain? */
461          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
462                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
# Line 703  int ccs_delete_domain(char *domainname) Line 473  int ccs_delete_domain(char *domainname)
473  }  }
474    
475  /**  /**
476   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_assign_domain - Create a domain.
477   *   *
478   * @domainname: The name of domain.   * @domainname: The name of domain.
479   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
480   *   *
481   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
482   */   */
483  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_assign_domain(const char *domainname,
484                                                        const u8 profile)                                            const u8 profile)
485  {  {
486          struct ccs_domain_info *entry;          struct ccs_domain_info *entry;
487          struct ccs_domain_info *domain;          struct ccs_domain_info *domain = NULL;
488          const struct ccs_path_info *saved_domainname;          const struct ccs_path_info *saved_domainname;
489          bool found = false;          bool found = false;
490    
491          if (!ccs_is_correct_domain(domainname))          if (!ccs_correct_domain(domainname))
492                  return NULL;                  return NULL;
493          saved_domainname = ccs_get_name(domainname);          saved_domainname = ccs_get_name(domainname);
494          if (!saved_domainname)          if (!saved_domainname)
495                  return NULL;                  return NULL;
496          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
497          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
498                    goto out;
499          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
500                  if (domain->is_deleted ||                  if (domain->is_deleted ||
501                      ccs_pathcmp(saved_domainname, domain->domainname))                      ccs_pathcmp(saved_domainname, domain->domainname))
# Line 732  struct ccs_domain_info *ccs_find_or_assi Line 503  struct ccs_domain_info *ccs_find_or_assi
503                  found = true;                  found = true;
504                  break;                  break;
505          }          }
506          if (!found && ccs_memory_ok(entry)) {          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
507                  INIT_LIST_HEAD(&entry->acl_info_list);                  INIT_LIST_HEAD(&entry->acl_info_list);
508                  entry->domainname = saved_domainname;                  entry->domainname = saved_domainname;
509                  saved_domainname = NULL;                  saved_domainname = NULL;
# Line 743  struct ccs_domain_info *ccs_find_or_assi Line 514  struct ccs_domain_info *ccs_find_or_assi
514                  found = true;                  found = true;
515          }          }
516          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
517     out:
518          ccs_put_name(saved_domainname);          ccs_put_name(saved_domainname);
519          kfree(entry);          kfree(entry);
520          return found ? domain : NULL;          return found ? domain : NULL;
521  }  }
522    
523  /**  /**
  * ccs_get_argv0 - Get argv[0].  
  *  
  * @ee: Pointer to "struct ccs_execve_entry".  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_get_argv0(struct ccs_execve_entry *ee)  
 {  
         struct linux_binprm *bprm = ee->bprm;  
         char *arg_ptr = ee->tmp;  
         int arg_len = 0;  
         unsigned long pos = bprm->p;  
         int offset = pos % PAGE_SIZE;  
         bool done = false;  
         if (!bprm->argc)  
                 goto out;  
         while (1) {  
                 if (!ccs_dump_page(bprm, pos, &ee->dump))  
                         goto out;  
                 pos += PAGE_SIZE - offset;  
                 /* Read. */  
                 while (offset < PAGE_SIZE) {  
                         const char *kaddr = ee->dump.data;  
                         const unsigned char c = kaddr[offset++];  
                         if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {  
                                 if (c == '\\') {  
                                         arg_ptr[arg_len++] = '\\';  
                                         arg_ptr[arg_len++] = '\\';  
                                 } else if (c == '/') {  
                                         arg_len = 0;  
                                 } else if (c > ' ' && c < 127) {  
                                         arg_ptr[arg_len++] = c;  
                                 } else {  
                                         arg_ptr[arg_len++] = '\\';  
                                         arg_ptr[arg_len++] = (c >> 6) + '0';  
                                         arg_ptr[arg_len++]  
                                                 = ((c >> 3) & 7) + '0';  
                                         arg_ptr[arg_len++] = (c & 7) + '0';  
                                 }  
                         } else {  
                                 arg_ptr[arg_len] = '\0';  
                                 done = true;  
                                 break;  
                         }  
                 }  
                 offset = 0;  
                 if (done)  
                         break;  
         }  
         return true;  
  out:  
         return false;  
 }  
   
 /**  
524   * ccs_find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
525   *   *
526   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
527   *   *
528   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
529   *   *
530   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
531   */   */
532  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve *ee)
533  {  {
534          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
535          const struct ccs_path_info *handler = ee->handler;          const struct ccs_path_info *handler = ee->handler;
536          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
537          const char *old_domain_name = r->domain->domainname->name;          struct ccs_domain_info * const old_domain = ccs_current_domain();
538            const char *old_domain_name = old_domain->domainname->name;
539          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
540          const u8 mode = r->mode;          struct task_struct *task = current;
541          const bool is_enforce = (mode == 3);          const u32 ccs_flags = task->ccs_flags;
542          const u32 ccs_flags = current->ccs_flags;          struct ccs_path_info rn = { }; /* real name */
         char *new_domain_name = NULL;  
         struct ccs_path_info rn; /* real name */  
         struct ccs_path_info sn; /* symlink name */  
543          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
544          int retval;          int retval;
545            bool need_kfree = false;
546            bool domain_created = false;
547            ln.name = ccs_last_word(old_domain_name);
548            ccs_fill_path_info(&ln);
549   retry:   retry:
550          current->ccs_flags = ccs_flags;          current->ccs_flags = ccs_flags;
551          r->cond = NULL;          r->cond = NULL;
552          /* Get realpath of program and symbolic link. */          if (need_kfree) {
553          retval = ccs_realpath_both(bprm->filename, ee);                  kfree(rn.name);
554                    need_kfree = false;
555            }
556    
557            /* Get symlink's pathname of program. */
558            retval = ccs_symlink_path(bprm->filename, &rn);
559          if (retval < 0)          if (retval < 0)
560                  goto out;                  goto out;
561            need_kfree = true;
         rn.name = ee->program_path;  
         ccs_fill_path_info(&rn);  
         sn.name = ee->tmp;  
         ccs_fill_path_info(&sn);  
         ln.name = ccs_get_last_name(r->domain);  
         ccs_fill_path_info(&ln);  
562    
563          if (handler) {          if (handler) {
564                  if (ccs_pathcmp(&rn, handler)) {                  if (ccs_pathcmp(&rn, handler)) {
# Line 853  static int ccs_find_next_domain(struct c Line 571  static int ccs_find_next_domain(struct c
571                          }                          }
572                          goto out;                          goto out;
573                  }                  }
574                  goto calculate_domain;          } else {
575          }                  struct ccs_aggregator *ptr;
576                    /* Check 'aggregator' directive. */
577          /* Check 'alias' directive. */                  list_for_each_entry_rcu(ptr,
578          if (ccs_pathcmp(&rn, &sn)) {                                          &ccs_policy_list[CCS_ID_AGGREGATOR],
579                  struct ccs_alias_entry *ptr;                                          head.list) {
580                  /* Is this program allowed to be called via symbolic links? */                          if (ptr->head.is_deleted ||
581                  list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {                              !ccs_path_matches_pattern(&rn, ptr->original_name))
                         if (ptr->is_deleted ||  
                             ccs_pathcmp(&rn, ptr->original_name) ||  
                             ccs_pathcmp(&sn, ptr->aliased_name))  
582                                  continue;                                  continue;
583                          strncpy(ee->program_path, ptr->aliased_name->name,                          kfree(rn.name);
584                                  CCS_MAX_PATHNAME_LEN - 1);                          need_kfree = false;
585                          ccs_fill_path_info(&rn);                          /* This is OK because it is read only. */
586                            rn = *ptr->aggregated_name;
587                          break;                          break;
588                  }                  }
         }  
         /* sn will be overwritten after here. */  
589    
590          /* Compare basename of program_path and argv[0] */                  /* Check execute permission. */
591          r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0);                  retval = ccs_exec_perm(r, &rn);
592          if (bprm->argc > 0 && r->mode) {                  if (retval == CCS_RETRY_REQUEST)
593                  char *base_argv0 = ee->tmp;                          goto retry;
594                  const char *base_filename;                  if (retval < 0)
                 retval = -ENOMEM;  
                 if (!ccs_get_argv0(ee))  
595                          goto out;                          goto out;
                 base_filename = strrchr(ee->program_path, '/');  
                 if (!base_filename)  
                         base_filename = ee->program_path;  
                 else  
                         base_filename++;  
                 if (strcmp(base_argv0, base_filename)) {  
                         retval = ccs_check_argv0_perm(r, &rn, base_argv0);  
                         if (retval == 1)  
                                 goto retry;  
                         if (retval < 0)  
                                 goto out;  
                 }  
         }  
   
         /* Check 'aggregator' directive. */  
         {  
                 struct ccs_aggregator_entry *ptr;  
                 /* Is this program allowed to be aggregated? */  
                 list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {  
                         if (ptr->is_deleted ||  
                             !ccs_path_matches_pattern(&rn, ptr->original_name))  
                                 continue;  
                         strncpy(ee->program_path, ptr->aggregated_name->name,  
                                 CCS_MAX_PATHNAME_LEN - 1);  
                         ccs_fill_path_info(&rn);  
                         break;  
                 }  
596          }          }
597    
598          /* Check execute permission. */          /* Calculate domain to transit to. */
599          r->mode = mode;          if (ccs_domain_initializer(old_domain->domainname, &rn, &ln)) {
         retval = ccs_check_exec_perm(r, &rn);  
         if (retval == 1)  
                 goto retry;  
         if (retval < 0)  
                 goto out;  
   
  calculate_domain:  
         new_domain_name = ee->tmp;  
         if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {  
600                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
601                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
602                           ROOT_NAME " " "%s", ee->program_path);                           rn.name);
603          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {          } else if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
604                  /*                  /*
605                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
606                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
607                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
608                   */                   */
609                  domain = r->domain;                  domain = old_domain;
610          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {          } else if (ccs_domain_keeper(old_domain->domainname, &rn, &ln)) {
611                  /* Keep current domain. */                  /* Keep current domain. */
612                  domain = r->domain;                  domain = old_domain;
613          } else {          } else {
614                  /* Normal domain transition. */                  /* Normal domain transition. */
615                  snprintf(new_domain_name, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
616                           "%s %s", old_domain_name, ee->program_path);                           old_domain_name, rn.name);
617          }          }
618          if (domain || strlen(new_domain_name) >= CCS_MAX_PATHNAME_LEN)          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
619                  goto done;                  goto done;
620          domain = ccs_find_domain(new_domain_name);          domain = ccs_find_domain(ee->tmp);
621          if (domain)          if (domain)
622                  goto done;                  goto done;
623          if (is_enforce) {          if (r->mode == CCS_CONFIG_ENFORCING) {
624                  int error = ccs_check_supervisor(r,                  int error = ccs_supervisor(r, "# wants to create domain\n"
625                                                   "# wants to create domain\n"                                             "%s\n", ee->tmp);
626                                                   "%s\n", new_domain_name);                  if (error == CCS_RETRY_REQUEST)
                 if (error == 1)  
627                          goto retry;                          goto retry;
628                  if (error < 0)                  if (error < 0)
629                          goto done;                          goto done;
630          }          }
631          domain = ccs_find_or_assign_new_domain(new_domain_name, r->profile);          domain = ccs_assign_domain(ee->tmp, r->profile);
632          if (domain)          if (domain)
633                  ccs_audit_domain_creation_log(r->domain);                  domain_created = true;
634   done:   done:
635          if (!domain) {          if (!domain) {
636                  printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
637                         new_domain_name);                  if (!old_domain->domain_transition_failed) {
638                  if (is_enforce)                          old_domain->domain_transition_failed = true;
639                          retval = -EPERM;                          ccs_write_log(false, r, CCS_KEYWORD_TRANSITION_FAILED
640                  else {                                        "\n");
641                          retval = 0;                          printk(KERN_WARNING
642                          r->domain->domain_transition_failed = true;                                 "ERROR: Domain '%s' not defined.\n", ee->tmp);
643                  }                  }
644          } else {          } else {
645                  retval = 0;                  retval = 0;
646          }          }
647   out:          if (!retval && handler)
648                    ccs_audit_execute_handler_log(ee);
649            /*
650             * Tell GC that I started execve().
651             * Also, tell open_exec() to check read permission.
652             */
653            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
654            /*
655             * Make task->ccs_flags visible to GC before changing
656             * task->ccs_domain_info .
657             */
658            smp_mb();
659            /*
660             * Proceed to the next domain in order to allow reaching via PID.
661             * It will be reverted if execve() failed. Reverting is not good.
662             * But it is better than being unable to reach via PID in interactive
663             * enforcing mode.
664             */
665          if (domain)          if (domain)
666                  r->domain = domain;                  task->ccs_domain_info = domain;
667            if (domain_created)
668                    ccs_audit_domain_creation_log();
669     out:
670            if (need_kfree)
671                    kfree(rn.name);
672          return retval;          return retval;
673  }  }
674    
675  /**  /**
676   * ccs_check_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
677   *   *
678   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
679   *   *
680   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
681   */   */
682  static int ccs_check_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve *ee)
683  {  {
684          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
685          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
686          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
687            struct ccs_page_dump env_page = { };
688            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
689          int arg_len = 0;          int arg_len = 0;
690          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
691          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 994  static int ccs_check_environ(struct ccs_ Line 693  static int ccs_check_environ(struct ccs_
693          int envp_count = bprm->envc;          int envp_count = bprm->envc;
694          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
695          int error = -ENOMEM;          int error = -ENOMEM;
696            ee->r.type = CCS_MAC_ENVIRON;
697            ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
698                                      CCS_MAC_ENVIRON);
699          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
700                  return 0;                  return 0;
701            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
702            if (!arg_ptr)
703                    goto out;
704          while (error == -ENOMEM) {          while (error == -ENOMEM) {
705                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
706                          goto out;                          goto out;
707                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
708                  /* Read. */                  /* Read. */
709                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
710                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
711                                  argv_count--;                                  argv_count--;
712                  }                  }
713                  if (argv_count) {                  if (argv_count) {
# Line 1011  static int ccs_check_environ(struct ccs_ Line 715  static int ccs_check_environ(struct ccs_
715                          continue;                          continue;
716                  }                  }
717                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
718                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
719                          const unsigned char c = kaddr[offset++];                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
                         if (c && arg_len < CCS_MAX_PATHNAME_LEN - 10) {  
720                                  if (c == '=') {                                  if (c == '=') {
721                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
722                                  } else if (c == '\\') {                                  } else if (c == '\\') {
# Line 1033  static int ccs_check_environ(struct ccs_ Line 736  static int ccs_check_environ(struct ccs_
736                          }                          }
737                          if (c)                          if (c)
738                                  continue;                                  continue;
739                          if (ccs_check_env_perm(r, arg_ptr)) {                          if (ccs_env_perm(r, arg_ptr)) {
740                                  error = -EPERM;                                  error = -EPERM;
741                                  break;                                  break;
742                          }                          }
# Line 1048  static int ccs_check_environ(struct ccs_ Line 751  static int ccs_check_environ(struct ccs_
751   out:   out:
752          if (r->mode != 3)          if (r->mode != 3)
753                  error = 0;                  error = 0;
754            kfree(env_page.data);
755            kfree(arg_ptr);
756          return error;          return error;
757  }  }
758    
# Line 1098  static void ccs_unescape(unsigned char * Line 803  static void ccs_unescape(unsigned char *
803   *   *
804   * Returns number of directories to strip.   * Returns number of directories to strip.
805   */   */
806  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
807  {  {
808          int depth = 0;          int depth = 0;
         /***** CRITICAL SECTION START *****/  
809          ccs_realpath_lock();          ccs_realpath_lock();
810          for (;;) {          for (;;) {
811                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
# Line 1116  static inline int ccs_root_depth(struct Line 820  static inline int ccs_root_depth(struct
820                  depth++;                  depth++;
821          }          }
822          ccs_realpath_unlock();          ccs_realpath_unlock();
         /***** CRITICAL SECTION END *****/  
823          return depth;          return depth;
824  }  }
825    
# Line 1133  static int ccs_get_root_depth(void) Line 836  static int ccs_get_root_depth(void)
836  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
837          struct path root;          struct path root;
838  #endif  #endif
         /***** CRITICAL SECTION START *****/  
839          read_lock(&current->fs->lock);          read_lock(&current->fs->lock);
840  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
841          root = current->fs->root;          root = current->fs->root;
# Line 1145  static int ccs_get_root_depth(void) Line 847  static int ccs_get_root_depth(void)
847          vfsmnt = mntget(current->fs->rootmnt);          vfsmnt = mntget(current->fs->rootmnt);
848  #endif  #endif
849          read_unlock(&current->fs->lock);          read_unlock(&current->fs->lock);
         /***** CRITICAL SECTION END *****/  
850          depth = ccs_root_depth(dentry, vfsmnt);          depth = ccs_root_depth(dentry, vfsmnt);
851  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
852          path_put(&root);          path_put(&root);
# Line 1156  static int ccs_get_root_depth(void) Line 857  static int ccs_get_root_depth(void)
857          return depth;          return depth;
858  }  }
859    
 static LIST_HEAD(ccs_execve_list);  
 static DEFINE_SPINLOCK(ccs_execve_list_lock);  
   
 /**  
  * ccs_allocate_execve_entry - Allocate memory for execve().  
  *  
  * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.  
  */  
 static struct ccs_execve_entry *ccs_allocate_execve_entry(void)  
 {  
         struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false);  
         if (!ee)  
                 return NULL;  
         memset(ee, 0, sizeof(*ee));  
         ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);  
         ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);  
         if (!ee->program_path || !ee->tmp) {  
                 ccs_free(ee->program_path);  
                 ccs_free(ee->tmp);  
                 ccs_free(ee);  
                 return NULL;  
         }  
         ee->srcu_idx = srcu_read_lock(&ccs_ss);  
         /* ee->dump->data is allocated by ccs_dump_page(). */  
         ee->task = current;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_add(&ee->list, &ccs_execve_list);  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         return ee;  
 }  
   
 /**  
  * ccs_find_execve_entry - Find ccs_execve_entry of current process.  
  *  
  * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.  
  */  
 static struct ccs_execve_entry *ccs_find_execve_entry(void)  
 {  
         struct task_struct *task = current;  
         struct ccs_execve_entry *ee = NULL;  
         struct ccs_execve_entry *p;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_for_each_entry(p, &ccs_execve_list, list) {  
                 if (p->task != task)  
                         continue;  
                 ee = p;  
                 break;  
         }  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         return ee;  
 }  
   
 /**  
  * ccs_free_execve_entry - Free memory for execve().  
  *  
  * @ee: Pointer to "struct ccs_execve_entry".  
  */  
 static void ccs_free_execve_entry(struct ccs_execve_entry *ee)  
 {  
         if (!ee)  
                 return;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_execve_list_lock);  
         list_del(&ee->list);  
         spin_unlock(&ccs_execve_list_lock);  
         /***** CRITICAL SECTION END *****/  
         ccs_free(ee->program_path);  
         ccs_free(ee->tmp);  
         kfree(ee->dump.data);  
         srcu_read_unlock(&ccs_ss, ee->srcu_idx);  
         ccs_free(ee);  
 }  
   
860  /**  /**
861   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
862   *   *
863   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
864   *   *
865   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
866   */   */
867  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)  static int ccs_try_alt_exec(struct ccs_execve *ee)
868  {  {
869          /*          /*
870           * Contents of modified bprm.           * Contents of modified bprm.
# Line 1286  static int ccs_try_alt_exec(struct ccs_e Line 910  static int ccs_try_alt_exec(struct ccs_e
910          struct task_struct *task = current;          struct task_struct *task = current;
911    
912          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
913            ee->obj.path1.dentry = NULL;
914            ee->obj.path1.mnt = NULL;
915            ee->obj.validate_done = false;
916          allow_write_access(bprm->file);          allow_write_access(bprm->file);
917          fput(bprm->file);          fput(bprm->file);
918          bprm->file = NULL;          bprm->file = NULL;
# Line 1333  static int ccs_try_alt_exec(struct ccs_e Line 960  static int ccs_try_alt_exec(struct ccs_e
960                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
961                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
962                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
963                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           (pid_t) ccsecurity_exports.sys_getpid(),
964                           current_euid(), current_egid(), current_suid(),                           current_uid(), current_gid(), current_euid(),
965                           current_sgid(), current_fsuid(), current_fsgid(),                           current_egid(), current_suid(), current_sgid(),
966                             current_fsuid(), current_fsgid(),
967                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
968                           (u8) (ccs_flags >> 8));                           (u8) (ccs_flags >> 8));
969                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
# Line 1349  static int ccs_try_alt_exec(struct ccs_e Line 977  static int ccs_try_alt_exec(struct ccs_e
977                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
978                  if (exe) {                  if (exe) {
979                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
980                          ccs_free(exe);                          kfree(exe);
981                  } else {                  } else {
982                          exe = ee->tmp;                          exe = ee->tmp;
983                          strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1);                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
984                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = copy_strings_kernel(1, &exe, bprm);
985                  }                  }
986                  if (retval < 0)                  if (retval < 0)
# Line 1363  static int ccs_try_alt_exec(struct ccs_e Line 991  static int ccs_try_alt_exec(struct ccs_e
991          /* Set argv[1] */          /* Set argv[1] */
992          {          {
993                  char *cp = ee->tmp;                  char *cp = ee->tmp;
994                  strncpy(ee->tmp, ccs_current_domain()->domainname->name,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
995                          CCS_EXEC_TMPSIZE - 1);                           ccs_current_domain()->domainname->name);
996                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
997                  if (retval < 0)                  if (retval < 0)
998                          goto out;                          goto out;
# Line 1374  static int ccs_try_alt_exec(struct ccs_e Line 1002  static int ccs_try_alt_exec(struct ccs_e
1002          /* Set argv[0] */          /* Set argv[0] */
1003          {          {
1004                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
1005                  char *cp = ee->program_path;                  int len = ee->handler->total_len + 1;
1006                  strncpy(cp, ee->handler->name, CCS_MAX_PATHNAME_LEN - 1);                  char *cp = kmalloc(len, CCS_GFP_FLAGS);
1007                    if (!cp) {
1008                            retval = -ENOMEM;
1009                            goto out;
1010                    }
1011                    ee->handler_path = cp;
1012                    memmove(cp, ee->handler->name, len);
1013                  ccs_unescape(cp);                  ccs_unescape(cp);
1014                  retval = -ENOENT;                  retval = -ENOENT;
1015                  if (!*cp || *cp != '/')                  if (!*cp || *cp != '/')
# Line 1387  static int ccs_try_alt_exec(struct ccs_e Line 1021  static int ccs_try_alt_exec(struct ccs_e
1021                                  goto out;                                  goto out;
1022                          depth--;                          depth--;
1023                  }                  }
1024                  memmove(ee->program_path, cp, strlen(cp) + 1);                  memmove(ee->handler_path, cp, strlen(cp) + 1);
1025                  cp = ee->program_path;                  cp = ee->handler_path;
1026                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
1027                  if (retval < 0)                  if (retval < 0)
1028                          goto out;                          goto out;
# Line 1400  static int ccs_try_alt_exec(struct ccs_e Line 1034  static int ccs_try_alt_exec(struct ccs_e
1034  #endif  #endif
1035  #endif  #endif
1036    
1037          /* OK, now restart the process with execute handler program's dentry. */          /*
1038          filp = open_exec(ee->program_path);           * OK, now restart the process with execute handler program's dentry.
1039             */
1040            filp = open_exec(ee->handler_path);
1041          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1042                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1043                  goto out;                  goto out;
1044          }          }
1045            ee->obj.path1.dentry = filp->f_dentry;
1046            ee->obj.path1.mnt = filp->f_vfsmnt;
1047          bprm->file = filp;          bprm->file = filp;
1048          bprm->filename = ee->program_path;          bprm->filename = ee->handler_path;
1049  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1050          bprm->interp = bprm->filename;          bprm->interp = bprm->filename;
1051  #endif  #endif
1052          retval = prepare_binprm(bprm);          retval = prepare_binprm(bprm);
1053          if (retval < 0)          if (retval < 0)
1054                  goto out;                  goto out;
1055          {          task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1056                  /*          retval = ccs_find_next_domain(ee);
1057                   * Backup ee->program_path because ccs_find_next_domain() will          task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
                  * overwrite ee->program_path and ee->tmp.  
                  */  
                 const int len = strlen(ee->program_path) + 1;  
                 char *cp = kmalloc(len, GFP_KERNEL);  
                 if (!cp) {  
                         retval = -ENOMEM;  
                         goto out;  
                 }  
                 memmove(cp, ee->program_path, len);  
                 bprm->filename = cp;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
                 bprm->interp = bprm->filename;  
 #endif  
                 task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
                 retval = ccs_find_next_domain(ee);  
                 task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;  
                 /* Restore ee->program_path for search_binary_handler(). */  
                 memmove(ee->program_path, cp, len);  
                 bprm->filename = ee->program_path;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
                 bprm->interp = bprm->filename;  
 #endif  
                 kfree(cp);  
         }  
1058   out:   out:
1059          return retval;          return retval;
1060  }  }
# Line 1448  static int ccs_try_alt_exec(struct ccs_e Line 1062  static int ccs_try_alt_exec(struct ccs_e
1062  /**  /**
1063   * ccs_find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1064   *   *
1065   * @ee:   Pointer to "struct ccs_execve_entry".   * @ee:   Pointer to "struct ccs_execve".
1066   * @type: Type of execute handler.   * @type: Type of execute handler.
1067   *   *
1068   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1069   *   *
1070   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
1071   */   */
1072  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,  static bool ccs_find_execute_handler(struct ccs_execve *ee,
1073                                       const u8 type)                                       const u8 type)
1074  {  {
1075          struct task_struct *task = current;          struct task_struct *task = current;
1076          const struct ccs_domain_info *domain = ccs_current_domain();          const struct ccs_domain_info * const domain = ccs_current_domain();
1077          struct ccs_acl_info *ptr;          struct ccs_acl_info *ptr;
1078          bool found = false;          bool found = false;
1079          /*          /*
# Line 1475  static bool ccs_find_execute_handler(str Line 1089  static bool ccs_find_execute_handler(str
1089                  acl = container_of(ptr, struct ccs_execute_handler_record,                  acl = container_of(ptr, struct ccs_execute_handler_record,
1090                                     head);                                     head);
1091                  ee->handler = acl->handler;                  ee->handler = acl->handler;
1092                    ee->handler_type = type;
1093                  found = true;                  found = true;
1094                  break;                  break;
1095          }          }
# Line 1494  bool ccs_dump_page(struct linux_binprm * Line 1109  bool ccs_dump_page(struct linux_binprm *
1109                     struct ccs_page_dump *dump)                     struct ccs_page_dump *dump)
1110  {  {
1111          struct page *page;          struct page *page;
1112          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_finish_execve(). */
1113          if (!dump->data) {          if (!dump->data) {
1114                  dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1115                  if (!dump->data)                  if (!dump->data)
1116                          return false;                          return false;
1117          }          }
# Line 1504  bool ccs_dump_page(struct linux_binprm * Line 1119  bool ccs_dump_page(struct linux_binprm *
1119  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1120          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1121                  return false;                  return false;
1122  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1123            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1124                    return false;
1125    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1126          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)          if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1127                  return false;                  return false;
1128  #else  #else
# Line 1519  bool ccs_dump_page(struct linux_binprm * Line 1137  bool ccs_dump_page(struct linux_binprm *
1137                   */                   */
1138                  char *kaddr = kmap_atomic(page, KM_USER0);                  char *kaddr = kmap_atomic(page, KM_USER0);
1139                  dump->page = page;                  dump->page = page;
1140                  memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);                  memcpy(dump->data + offset, kaddr + offset,
1141                           PAGE_SIZE - offset);
1142                  kunmap_atomic(kaddr, KM_USER0);                  kunmap_atomic(kaddr, KM_USER0);
1143          }          }
1144          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1145  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1146          put_page(page);          put_page(page);
1147  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3 && defined(CONFIG_MMU)
1148            put_page(page);
1149    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1150          put_page(page);          put_page(page);
1151  #endif  #endif
1152          return true;          return true;
1153  }  }
1154    
1155  /**  /**
  * ccs_fetch_next_domain - Fetch next_domain from the list.  
  *  
  * Returns pointer to "struct ccs_domain_info" which will be used if execve()  
  * succeeds. This function does not return NULL.  
  */  
 struct ccs_domain_info *ccs_fetch_next_domain(void)  
 {  
         struct ccs_execve_entry *ee = ccs_find_execve_entry();  
         struct ccs_domain_info *next_domain = NULL;  
         if (ee)  
                 next_domain = ee->r.domain;  
         if (!next_domain)  
                 next_domain = ccs_current_domain();  
         return next_domain;  
 }  
   
 /**  
1156   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1157   *   *
1158   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1159     * @eep:  Pointer to "struct ccs_execve *".
1160   *   *
1161   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1162   */   */
1163  int ccs_start_execve(struct linux_binprm *bprm)  static int ccs_start_execve(struct linux_binprm *bprm,
1164                                struct ccs_execve **eep)
1165  {  {
1166          int retval;          int retval;
1167          struct task_struct *task = current;          struct task_struct *task = current;
1168          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();          struct ccs_execve *ee;
1169          if (!ccs_policy_loaded)          *eep = NULL;
1170                  ccs_load_policy(bprm->filename);          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1171          if (!ee)          if (!ee)
1172                  return -ENOMEM;                  return -ENOMEM;
1173          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FOR_FILE);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1174            if (!ee->tmp) {
1175                    kfree(ee);
1176                    return -ENOMEM;
1177            }
1178            ee->reader_idx = ccs_read_lock();
1179            /* ee->dump->data is allocated by ccs_dump_page(). */
1180            ee->previous_domain = task->ccs_domain_info;
1181            /* Clear manager flag. */
1182            task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1183            *eep = ee;
1184            ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1185          ee->r.ee = ee;          ee->r.ee = ee;
1186          ee->bprm = bprm;          ee->bprm = bprm;
1187          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1188          ee->obj.path1_dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1189          ee->obj.path1_vfsmnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1190          /* Clear manager flag. */          /*
1191          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;           * No need to call ccs_environ() for execute handler because envp[] is
1192          if (ccs_find_execute_handler(ee, TYPE_EXECUTE_HANDLER)) {           * moved to argv[].
1193                  retval = ccs_try_alt_exec(ee);           */
1194                  if (!retval)          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER))
1195                          ccs_audit_execute_handler_log(ee, true);                  return ccs_try_alt_exec(ee);
                 goto ok;  
         }  
1196          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1197          if (retval != -EPERM)          if (retval == -EPERM) {
1198                  goto ok;                  if (ccs_find_execute_handler(ee,
1199          if (ccs_find_execute_handler(ee, TYPE_DENIED_EXECUTE_HANDLER)) {                                               CCS_TYPE_DENIED_EXECUTE_HANDLER))
1200                  retval = ccs_try_alt_exec(ee);                          return ccs_try_alt_exec(ee);
                 if (!retval)  
                         ccs_audit_execute_handler_log(ee, false);  
1201          }          }
1202   ok:          if (!retval)
1203          if (retval < 0)                  retval = ccs_environ(ee);
                 goto out;  
         ee->r.mode = ccs_check_flags(ee->r.domain, CCS_MAC_FOR_ENV);  
         retval = ccs_check_environ(ee);  
         if (retval < 0)  
                 goto out;  
         task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;  
         retval = 0;  
  out:  
         if (retval)  
                 ccs_finish_execve(retval);  
1204          return retval;          return retval;
1205  }  }
1206    
# Line 1605  int ccs_start_execve(struct linux_binprm Line 1208  int ccs_start_execve(struct linux_binprm
1208   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1209   *   *
1210   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1211     * @ee:     Pointer to "struct ccs_execve".
1212   *   *
1213   * Caller holds srcu_read_lock(&ccs_ss).   * Caller holds ccs_read_lock().
1214   */   */
1215  void ccs_finish_execve(int retval)  static void ccs_finish_execve(int retval, struct ccs_execve *ee)
1216  {  {
1217          struct task_struct *task = current;          struct task_struct *task = current;
         struct ccs_execve_entry *ee = ccs_find_execve_entry();  
         task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;  
1218          if (!ee)          if (!ee)
1219                  return;                  return;
1220          if (retval < 0)          if (retval < 0) {
1221                  goto out;                  task->ccs_domain_info = ee->previous_domain;
1222          /* Proceed to next domain if execution suceeded. */                  /*
1223          task->ccs_domain_info = ee->r.domain;                   * Make task->ccs_domain_info visible to GC before changing
1224          /* Mark the current process as execute handler. */                   * task->ccs_flags .
1225          if (ee->handler)                   */
1226                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  smp_mb();
1227          /* Mark the current process as normal process. */          } else {
1228          else                  /* Mark the current process as execute handler. */
1229                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                  if (ee->handler)
1230   out:                          task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1231          ccs_free_execve_entry(ee);                  /* Mark the current process as normal process. */
1232                    else
1233                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1234            }
1235            /* Tell GC that I finished execve(). */
1236            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1237            ccs_read_unlock(ee->reader_idx);
1238            kfree(ee->handler_path);
1239            kfree(ee->tmp);
1240            kfree(ee->dump.data);
1241            kfree(ee);
1242  }  }
1243    
 #else  
   
1244  /**  /**
1245   * ccs_start_execve - Prepare for execve() operation.   * ccs_may_transit - Check permission and do domain transition without execve().
1246   *   *
1247   * @bprm: Pointer to "struct linux_binprm".   * @domainname: Domainname to transit to.
1248     * @pathname: Pathname to check.
1249   *   *
1250   * Returns 0.   * Returns 0 on success, negative value otherwise.
1251     *
1252     * Caller holds ccs_read_lock().
1253   */   */
1254  int ccs_start_execve(struct linux_binprm *bprm)  int ccs_may_transit(const char *domainname, const char *pathname)
1255  {  {
1256  #ifdef CONFIG_SAKURA          struct ccs_path_info name;
1257          /* Clear manager flag. */          struct ccs_request_info r;
1258          current->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          struct ccs_domain_info *domain;
1259          if (!ccs_policy_loaded)          int error;
1260                  ccs_load_policy(bprm->filename);          bool domain_created = false;
1261  #endif          name.name = pathname;
1262          return 0;          ccs_fill_path_info(&name);
1263            /* Check allow_transit permission. */
1264            ccs_init_request_info(&r, CCS_MAC_FILE_TRANSIT);
1265            error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1266            if (error)
1267                    return error;
1268            /* Check destination domain. */
1269            domain = ccs_find_domain(domainname);
1270            if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1271                strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1272                    domain = ccs_assign_domain(domainname, r.profile);
1273                    if (domain)
1274                            domain_created = true;
1275            }
1276            if (domain) {
1277                    error = 0;
1278                    current->ccs_domain_info = domain;
1279                    if (domain_created)
1280                            ccs_audit_domain_creation_log();
1281            } else {
1282                    error = -ENOENT;
1283            }
1284            return error;
1285  }  }
1286    
1287  /**  static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1288   * ccs_finish_execve - Clean up execve() operation.                                         struct pt_regs *regs)
  */  
 void ccs_finish_execve(int retval)  
1289  {  {
1290            struct ccs_execve *ee;
1291            int retval;
1292            if (!ccs_policy_loaded)
1293                    ccsecurity_exports.load_policy(bprm->filename);
1294            retval = ccs_start_execve(bprm, &ee);
1295            if (!retval)
1296                    retval = search_binary_handler(bprm, regs);
1297            ccs_finish_execve(retval, ee);
1298            return retval;
1299  }  }
1300    
1301  #endif  void __init ccs_domain_init(void)
1302    {
1303            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1304    }

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

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