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

Subversion リポジトリの参照

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

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

trunk/1.7.x/ccs-patch/security/ccsecurity/domain.c revision 2951 by kumaneko, Tue Aug 25 04:26:20 2009 UTC trunk/1.8.x/ccs-patch/security/ccsecurity/domain.c revision 3968 by kumaneko, Wed Sep 8 05:42:22 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Version: 1.7.0-pre   2009/08/24   * Version: 1.8.0-pre   2010/09/01
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.
# Line 22  Line 22 
22  #endif  #endif
23  #include "internal.h"  #include "internal.h"
24    
 /* For compatibility with older kernels. */  
 #ifndef for_each_process  
 #define for_each_process for_each_task  
 #endif  
   
25  /* Variables definitions.*/  /* Variables definitions.*/
26    
27    /* The global domain. */
28    struct ccs_domain_info ccs_acl_group[CCS_MAX_ACL_GROUPS];
29    
30  /* The initial domain. */  /* The initial domain. */
31  struct ccs_domain_info ccs_kernel_domain;  struct ccs_domain_info ccs_kernel_domain;
32    
33  /* The list for "struct ccs_domain_info". */  /* The list for "struct ccs_domain_info". */
34  LIST_HEAD(ccs_domain_list);  LIST_HEAD(ccs_domain_list);
35    
36  /**  struct list_head ccs_policy_list[CCS_MAX_POLICY];
37   * ccs_audit_execute_handler_log - Audit execute_handler log.  struct list_head ccs_group_list[CCS_MAX_GROUP];
38   *  struct list_head ccs_shared_list[CCS_MAX_LIST];
  * @ee:         Pointer to "struct ccs_execve_entry".  
  * @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)  
 {  
         struct ccs_request_info *r = &ee->r;  
         const char *handler = ee->handler->name;  
         r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);  
         return ccs_write_audit_log(true, r, "%s %s\n",  
                                    is_default ? CCS_KEYWORD_EXECUTE_HANDLER :  
                                    CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);  
 }  
39    
40  /**  /**
41   * ccs_audit_domain_creation_log - Audit domain creation log.   * ccs_update_policy - Update an entry for exception policy.
42   *   *
43   * @domain:  Pointer to "struct ccs_domain_info".   * @new_entry:       Pointer to "struct ccs_acl_info".
44     * @size:            Size of @new_entry in bytes.
45     * @is_delete:       True if it is a delete request.
46     * @list:            Pointer to "struct list_head".
47     * @check_duplicate: Callback function to find duplicated entry.
48   *   *
49   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
50     *
51     * Caller holds ccs_read_lock().
52   */   */
53  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
54                          bool is_delete, struct list_head *list,
55                          bool (*check_duplicate) (const struct ccs_acl_head *,
56                                                   const struct ccs_acl_head *))
57  {  {
58          int error;          int error = is_delete ? -ENOENT : -ENOMEM;
59          struct ccs_request_info r;          struct ccs_acl_head *entry;
60          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);          if (mutex_lock_interruptible(&ccs_policy_lock))
61          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);                  return -ENOMEM;
62            list_for_each_entry_rcu(entry, list, list) {
63                    if (!check_duplicate(entry, new_entry))
64                            continue;
65                    entry->is_deleted = is_delete;
66                    error = 0;
67                    break;
68            }
69            if (error && !is_delete) {
70                    entry = ccs_commit_ok(new_entry, size);
71                    if (entry) {
72                            list_add_tail_rcu(&entry->list, list);
73                            error = 0;
74                    }
75            }
76            mutex_unlock(&ccs_policy_lock);
77          return error;          return error;
78  }  }
79    
80  /* The list for "struct ccs_domain_initializer_entry". */  static inline bool ccs_same_acl_head(const struct ccs_acl_info *p1,
81  LIST_HEAD(ccs_domain_initializer_list);                                       const struct ccs_acl_info *p2)
82    {
83            return p1->type == p2->type && p1->cond == p2->cond;
84    }
85    
86  /**  /**
87   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.   * ccs_update_domain - Update an entry for domain policy.
88   *   *
89   * @domainname: The name of domain. May be NULL.   * @new_entry:       Pointer to "struct ccs_acl_info".
90   * @program:    The name of program.   * @size:            Size of @new_entry in bytes.
91   * @is_not:     True if it is "no_initialize_domain" entry.   * @param:           Pointer to "struct ccs_acl_param".
92   * @is_delete:  True if it is a delete request.   * @check_duplicate: Callback function to find duplicated entry.
93     * @merge_duplicate: Callback function to merge duplicated entry. Maybe NULL.
94   *   *
95   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
96     *
97     * Caller holds ccs_read_lock().
98   */   */
99  static int ccs_update_domain_initializer_entry(const char *domainname,  int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
100                                                 const char *program,                        struct ccs_acl_param *param,
101                                                 const bool is_not,                        bool (*check_duplicate) (const struct ccs_acl_info *,
102                                                 const bool is_delete)                                                 const struct ccs_acl_info *),
103  {                        bool (*merge_duplicate) (struct ccs_acl_info *,
104          struct ccs_domain_initializer_entry *entry = NULL;                                                 struct ccs_acl_info *,
105          struct ccs_domain_initializer_entry *ptr;                                                 const bool))
106          struct ccs_domain_initializer_entry e = { .is_not = is_not };  {
107          int error = is_delete ? -ENOENT : -ENOMEM;          int error = param->is_delete ? -ENOENT : -ENOMEM;
108          if (!ccs_is_correct_path(program, 1, -1, -1))          struct ccs_acl_info *entry;
109                  return -EINVAL; /* No patterns allowed. */          const u8 type = new_entry->type;
110          if (domainname) {          const u8 i = type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
111                  if (!ccs_is_domain_def(domainname) &&                  type == CCS_TYPE_DENIED_EXECUTE_HANDLER ||
112                      ccs_is_correct_path(domainname, 1, -1, -1))                  type == CCS_TYPE_AUTO_TASK_ACL;
113                          e.is_last_name = true;          const bool is_delete = param->is_delete;
114                  else if (!ccs_is_correct_domain(domainname))          struct ccs_domain_info * const domain = param->domain;
115            if (param->data[0]) {
116                    new_entry->cond = ccs_get_condition(param->data);
117                    if (!new_entry->cond)
118                          return -EINVAL;                          return -EINVAL;
                 e.domainname = ccs_get_name(domainname);  
                 if (!e.domainname)  
                         goto out;  
119          }          }
120          e.program = ccs_get_name(program);          if (mutex_lock_interruptible(&ccs_policy_lock))
         if (!e.program)  
121                  goto out;                  goto out;
122          if (!is_delete)          list_for_each_entry_rcu(entry, &domain->acl_info_list[i], list) {
123                  entry = kmalloc(sizeof(e), GFP_KERNEL);                  if (!ccs_same_acl_head(entry, new_entry) ||
124          mutex_lock(&ccs_policy_lock);                      !check_duplicate(entry, new_entry))
         list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {  
                 if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),  
                                sizeof(e)))  
125                          continue;                          continue;
126                  ptr->is_deleted = is_delete;                  if (merge_duplicate)
127                            entry->is_deleted = merge_duplicate(entry, new_entry,
128                                                                is_delete);
129                    else
130                            entry->is_deleted = is_delete;
131                  error = 0;                  error = 0;
132                  break;                  break;
133          }          }
134          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {          if (error && !is_delete) {
135                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);                  entry = ccs_commit_ok(new_entry, size);
136                  entry = NULL;                  if (entry) {
137                  error = 0;                          list_add_tail_rcu(&entry->list,
138                                              &domain->acl_info_list[i]);
139                            error = 0;
140                    }
141          }          }
142          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
143   out:   out:
144          ccs_put_name(e.domainname);          ccs_put_condition(new_entry->cond);
         ccs_put_name(e.program);  
         kfree(entry);  
145          return error;          return error;
146  }  }
147    
148  /**  void ccs_check_acl(struct ccs_request_info *r,
149   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.                     bool (*check_entry) (struct ccs_request_info *,
150   *                                          const struct ccs_acl_info *))
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds ccs_read_lock().  
  */  
 bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  
151  {  {
152          struct list_head *pos;          const struct ccs_domain_info *domain = ccs_current_domain();
153          bool done = true;          struct ccs_acl_info *ptr;
154          list_for_each_cookie(pos, head->read_var2,          bool retried = false;
155                               &ccs_domain_initializer_list) {          const u8 i = !check_entry;
156                  const char *no;   retry:
157                  const char *from = "";          list_for_each_entry_rcu(ptr, &domain->acl_info_list[i], list) {
                 const char *domain = "";  
                 struct ccs_domain_initializer_entry *ptr;  
                 ptr = list_entry(pos, struct ccs_domain_initializer_entry,  
                                  list);  
158                  if (ptr->is_deleted)                  if (ptr->is_deleted)
159                          continue;                          continue;
160                  no = ptr->is_not ? "no_" : "";                  if (ptr->type != r->param_type)
                 if (ptr->domainname) {  
                         from = " from ";  
                         domain = ptr->domainname->name;  
                 }  
                 done = ccs_io_printf(head, "%s" CCS_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.  
  *  
  * @data:      String to parse.  
  * @is_not:    True if it is "no_initialize_domain" entry.  
  * @is_delete: True if it is a delete request.  
  *  
  * Returns 0 on success, negative value otherwise.  
  */  
 int ccs_write_domain_initializer_policy(char *data, const bool is_not,  
                                         const bool is_delete)  
 {  
         char *cp = strstr(data, " from ");  
         if (cp) {  
                 *cp = '\0';  
                 return ccs_update_domain_initializer_entry(cp + 6, data,  
                                                            is_not, is_delete);  
         }  
         return ccs_update_domain_initializer_entry(NULL, data, is_not,  
                                                    is_delete);  
 }  
   
 /**  
  * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.  
  *  
  * @domainname: The name of domain.  
  * @program:    The name of program.  
  * @last_name:  The last component of @domainname.  
  *  
  * Returns true if executing @program reinitializes domain transition,  
  * false otherwise.  
  *  
  * Caller holds ccs_read_lock().  
  */  
 static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,  
                                       const struct ccs_path_info *program,  
                                       const struct ccs_path_info *last_name)  
 {  
         struct ccs_domain_initializer_entry *ptr;  
         bool flag = false;  
         list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {  
                 if (ptr->is_deleted)  
161                          continue;                          continue;
162                  if (ptr->domainname) {                  if (check_entry && !check_entry(r, ptr))
                         if (!ptr->is_last_name) {  
                                 if (ptr->domainname != domainname)  
                                         continue;  
                         } else {  
                                 if (ccs_pathcmp(ptr->domainname, last_name))  
                                         continue;  
                         }  
                 }  
                 if (ccs_pathcmp(ptr->program, program))  
163                          continue;                          continue;
164                  if (ptr->is_not) {                  if (!ccs_condition(r, ptr->cond))
165                          flag = false;                          continue;
166                          break;                  r->matched_acl = ptr;
167                  }                  r->granted = true;
168                  flag = true;                  return;
169            }
170            if (!retried) {
171                    retried = true;
172                    domain = &ccs_acl_group[domain->group];
173                    goto retry;
174          }          }
175          return flag;          r->granted = false;
176  }  }
177    
178  /* The list for "struct ccs_domain_keeper_entry". */  static bool ccs_same_transition_control(const struct ccs_acl_head *a,
179  LIST_HEAD(ccs_domain_keeper_list);                                          const struct ccs_acl_head *b)
180    {
181            const struct ccs_transition_control *p1 = container_of(a, typeof(*p1),
182                                                                   head);
183            const struct ccs_transition_control *p2 = container_of(b, typeof(*p2),
184                                                                   head);
185            return p1->type == p2->type && p1->is_last_name == p2->is_last_name
186                    && p1->domainname == p2->domainname
187                    && p1->program == p2->program;
188    }
189    
190  /**  /**
191   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.   * ccs_update_transition_control_entry - Update "struct ccs_transition_control" list.
192   *   *
193   * @domainname: The name of domain.   * @domainname: The name of domain. Maybe NULL.
194   * @program:    The name of program. May be NULL.   * @program:    The name of program. Maybe NULL.
195   * @is_not:     True if it is "no_keep_domain" entry.   * @type:       Type of transition.
196   * @is_delete:  True if it is a delete request.   * @is_delete:  True if it is a delete request.
197   *   *
198   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
199   */   */
200  static int ccs_update_domain_keeper_entry(const char *domainname,  static int ccs_update_transition_control_entry(const char *domainname,
201                                            const char *program,                                                 const char *program,
202                                            const bool is_not,                                                 const u8 type,
203                                            const bool is_delete)                                                 const bool is_delete)
204  {  {
205          struct ccs_domain_keeper_entry *entry = NULL;          struct ccs_transition_control e = { .type = type };
         struct ccs_domain_keeper_entry *ptr;  
         struct ccs_domain_keeper_entry e = { .is_not = is_not };  
206          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
207          if (!ccs_is_domain_def(domainname) &&          if (program && strcmp(program, "any")) {
208              ccs_is_correct_path(domainname, 1, -1, -1))                  if (!ccs_correct_path(program))
                 e.is_last_name = true;  
         else if (!ccs_is_correct_domain(domainname))  
                 return -EINVAL;  
         if (program) {  
                 if (!ccs_is_correct_path(program, 1, -1, -1))  
209                          return -EINVAL;                          return -EINVAL;
210                  e.program = ccs_get_name(program);                  e.program = ccs_get_name(program);
211                  if (!e.program)                  if (!e.program)
212                          goto out;                          goto out;
213          }          }
214          e.domainname = ccs_get_name(domainname);          if (domainname && strcmp(domainname, "any")) {
215          if (!e.domainname)                  if (!ccs_correct_domain(domainname)) {
216                  goto out;                          if (!ccs_correct_path(domainname))
217          if (!is_delete)                                  goto out;
218                  entry = kmalloc(sizeof(e), GFP_KERNEL);                          e.is_last_name = true;
219          mutex_lock(&ccs_policy_lock);                  }
220          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {                  e.domainname = ccs_get_name(domainname);
221                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),                  if (!e.domainname)
222                                 sizeof(e)))                          goto out;
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {  
                 list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);  
                 entry = NULL;  
                 error = 0;  
223          }          }
224          mutex_unlock(&ccs_policy_lock);          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
225                                      &ccs_policy_list[CCS_ID_TRANSITION_CONTROL],
226                                      ccs_same_transition_control);
227   out:   out:
228          ccs_put_name(e.domainname);          ccs_put_name(e.domainname);
229          ccs_put_name(e.program);          ccs_put_name(e.program);
         kfree(entry);  
230          return error;          return error;
231  }  }
232    
233  /**  /**
234   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.   * ccs_write_transition_control - Write "struct ccs_transition_control" list.
235   *   *
236   * @data:      String to parse.   * @data:      String to parse.
  * @is_not:    True if it is "no_keep_domain" entry.  
237   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
238     * @type:      Type of this entry.
239   *   *
240     * Returns 0 on success, negative value otherwise.
241   */   */
242  int ccs_write_domain_keeper_policy(char *data, const bool is_not,  int ccs_write_transition_control(char *data, const bool is_delete,
243                                     const bool is_delete)                                   const u8 type)
 {  
         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 ccs_read_lock().  
  */  
 bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  
244  {  {
245          struct list_head *pos;          char *domainname = strstr(data, " from ");
246          bool done = true;          if (domainname) {
247          list_for_each_cookie(pos, head->read_var2,                  *domainname = '\0';
248                               &ccs_domain_keeper_list) {                  domainname += 6;
249                  struct ccs_domain_keeper_entry *ptr;          } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
250                  const char *no;                     type == CCS_TRANSITION_CONTROL_KEEP) {
251                  const char *from = "";                  domainname = data;
252                  const char *program = "";                  data = NULL;
                 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" CCS_KEYWORD_KEEP_DOMAIN  
                                      "%s%s%s\n", no, program, from,  
                                      ptr->domainname->name);  
                 if (!done)  
                         break;  
253          }          }
254          return done;          return ccs_update_transition_control_entry(domainname, data, type,
255                                                       is_delete);
256  }  }
257    
258  /**  /**
259   * ccs_is_domain_keeper - Check whether the given program causes domain transition suppression.   * ccs_transition_type - Get domain transition type.
260   *   *
261   * @domainname: The name of domain.   * @domainname: The name of domain.
262   * @program:    The name of program.   * @program:    The name of program.
  * @last_name:  The last component of @domainname.  
263   *   *
264   * Returns true if executing @program supresses domain transition,   * Returns CCS_TRANSITION_CONTROL_INITIALIZE if executing @program
265   * false otherwise.   * reinitializes domain transition, CCS_TRANSITION_CONTROL_KEEP if executing
266     * @program suppresses domain transition, others otherwise.
267   *   *
268   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
269   */   */
270  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static u8 ccs_transition_type(const struct ccs_path_info *domainname,
271                                   const struct ccs_path_info *program,                                const struct ccs_path_info *program)
272                                   const struct ccs_path_info *last_name)  {
273  {          const struct ccs_transition_control *ptr;
274          struct ccs_domain_keeper_entry *ptr;          const char *last_name = ccs_last_word(domainname->name);
275          bool flag = false;          u8 type;
276          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {          for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) {
277                  if (ptr->is_deleted)   next:
278                          continue;                  list_for_each_entry_rcu(ptr, &ccs_policy_list
279                  if (!ptr->is_last_name) {                                          [CCS_ID_TRANSITION_CONTROL],
280                          if (ptr->domainname != domainname)                                          head.list) {
281                            if (ptr->head.is_deleted || ptr->type != type)
282                                  continue;                                  continue;
283                  } else {                          if (ptr->domainname) {
284                          if (ccs_pathcmp(ptr->domainname, last_name))                                  if (!ptr->is_last_name) {
285                                            if (ptr->domainname != domainname)
286                                                    continue;
287                                    } else {
288                                            /*
289                                             * Use direct strcmp() since this is
290                                             * unlikely used.
291                                             */
292                                            if (strcmp(ptr->domainname->name,
293                                                       last_name))
294                                                    continue;
295                                    }
296                            }
297                            if (ptr->program && ccs_pathcmp(ptr->program, program))
298                                  continue;                                  continue;
299                            if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) {
300                                    /*
301                                     * Do not check for initialize_domain if
302                                     * no_initialize_domain matched.
303                                     */
304                                    type = CCS_TRANSITION_CONTROL_NO_KEEP;
305                                    goto next;
306                            }
307                            goto done;
308                  }                  }
                 if (ptr->program && ccs_pathcmp(ptr->program, program))  
                         continue;  
                 if (ptr->is_not) {  
                         flag = false;  
                         break;  
                 }  
                 flag = true;  
309          }          }
310          return flag;   done:
311            return type;
312  }  }
313    
314  /* The list for "struct ccs_aggregator_entry". */  static bool ccs_same_aggregator(const struct ccs_acl_head *a,
315  LIST_HEAD(ccs_aggregator_list);                                  const struct ccs_acl_head *b)
316    {
317            const struct ccs_aggregator *p1 = container_of(a, typeof(*p1), head);
318            const struct ccs_aggregator *p2 = container_of(b, typeof(*p2), head);
319            return p1->original_name == p2->original_name &&
320                    p1->aggregated_name == p2->aggregated_name;
321    }
322    
323  /**  /**
324   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator" list.
325   *   *
326   * @original_name:   The original program's name.   * @original_name:   The original program's name.
327   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 403  static int ccs_update_aggregator_entry(c Line 333  static int ccs_update_aggregator_entry(c
333                                         const char *aggregated_name,                                         const char *aggregated_name,
334                                         const bool is_delete)                                         const bool is_delete)
335  {  {
336          struct ccs_aggregator_entry *entry = NULL;          struct ccs_aggregator e = { };
         struct ccs_aggregator_entry *ptr;  
         struct ccs_aggregator_entry e = { };  
337          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
338          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||          if (!ccs_correct_word(original_name) ||
339              !ccs_is_correct_path(aggregated_name, 1, -1, -1))              !ccs_correct_path(aggregated_name))
340                  return -EINVAL;                  return -EINVAL;
341          e.original_name = ccs_get_name(original_name);          e.original_name = ccs_get_name(original_name);
342          e.aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
343          if (!e.original_name || !e.aggregated_name)          if (!e.original_name || !e.aggregated_name ||
344                e.aggregated_name->is_patterned) /* No patterns allowed. */
345                  goto out;                  goto out;
346          if (!is_delete)          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
347                  entry = kmalloc(sizeof(e), GFP_KERNEL);                                    &ccs_policy_list[CCS_ID_AGGREGATOR],
348          mutex_lock(&ccs_policy_lock);                                    ccs_same_aggregator);
         list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {  
                 if (ccs_memcmp(ptr, &e, offsetof(typeof(e), original_name),  
                                sizeof(e)))  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {  
                 list_add_tail_rcu(&entry->list, &ccs_aggregator_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
349   out:   out:
350          ccs_put_name(e.original_name);          ccs_put_name(e.original_name);
351          ccs_put_name(e.aggregated_name);          ccs_put_name(e.aggregated_name);
         kfree(entry);  
352          return error;          return error;
353  }  }
354    
355  /**  /**
356   * 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 ccs_read_lock().  
  */  
 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, CCS_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.  
357   *   *
358   * @data:      String to parse.   * @data:      String to parse.
359   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
360   *   *
361   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
362   */   */
363  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator(char *data, const bool is_delete)
364  {  {
365          char *w[2];          char *w[2];
366          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
# Line 496  int ccs_delete_domain(char *domainname) Line 383  int ccs_delete_domain(char *domainname)
383          struct ccs_path_info name;          struct ccs_path_info name;
384          name.name = domainname;          name.name = domainname;
385          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
386          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
387                    return 0;
388          /* Is there an active domain? */          /* Is there an active domain? */
389          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
390                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
# Line 513  int ccs_delete_domain(char *domainname) Line 401  int ccs_delete_domain(char *domainname)
401  }  }
402    
403  /**  /**
404   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_assign_domain - Create a domain.
405   *   *
406   * @domainname: The name of domain.   * @domainname: The name of domain.
407   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
408     * @group:      Group number to assign if the domain was newly created.
409     * @transit:    True if transit to domain found or created.
410   *   *
411   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
412     *
413     * Caller holds ccs_read_lock().
414   */   */
415  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_assign_domain(const char *domainname,
416                                                        const u8 profile)                                            const u8 profile, const u8 group,
417  {                                            const bool transit)
418          struct ccs_domain_info *entry;  {
419          struct ccs_domain_info *domain;          struct ccs_domain_info e = { };
420          const struct ccs_path_info *saved_domainname;          struct ccs_domain_info *entry = ccs_find_domain(domainname);
421          bool found = false;          bool created = false;
422            if (entry)
423          if (!ccs_is_correct_domain(domainname))                  goto out;
424            if (strlen(domainname) >= CCS_EXEC_TMPSIZE - 10 ||
425                !ccs_correct_domain(domainname))
426                  return NULL;                  return NULL;
427          saved_domainname = ccs_get_name(domainname);          e.profile = profile;
428          if (!saved_domainname)          e.group = group;
429            e.domainname = ccs_get_name(domainname);
430            if (!e.domainname)
431                  return NULL;                  return NULL;
432          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          if (mutex_lock_interruptible(&ccs_policy_lock))
433          mutex_lock(&ccs_policy_lock);                  goto out;
434          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          entry = ccs_find_domain(domainname);
435                  if (domain->is_deleted ||          if (!entry) {
436                      ccs_pathcmp(saved_domainname, domain->domainname))                  entry = ccs_commit_ok(&e, sizeof(e));
437                          continue;                  if (entry) {
438                  found = true;                          INIT_LIST_HEAD(&entry->acl_info_list[0]);
439                  break;                          INIT_LIST_HEAD(&entry->acl_info_list[1]);
440          }                          list_add_tail_rcu(&entry->list, &ccs_domain_list);
441          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {                          created = true;
442                  INIT_LIST_HEAD(&entry->acl_info_list);                  }
                 entry->domainname = saved_domainname;  
                 saved_domainname = NULL;  
                 entry->profile = profile;  
                 list_add_tail_rcu(&entry->list, &ccs_domain_list);  
                 domain = entry;  
                 entry = NULL;  
                 found = true;  
443          }          }
444          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
445          ccs_put_name(saved_domainname);   out:
446          kfree(entry);          ccs_put_name(e.domainname);
447          return found ? domain : NULL;          if (entry && transit) {
448                    current->ccs_domain_info = entry;
449                    if (created) {
450                            struct ccs_request_info r;
451                            ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
452                            r.granted = false;
453                            ccs_write_log(&r, "use_profile %u\n", r.profile);
454                    }
455            }
456            return entry;
457  }  }
458    
459  /**  /**
460   * ccs_find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
461   *   *
462   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
463   *   *
464   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
465   *   *
466   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
467   */   */
468  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve *ee)
469  {  {
470          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
471          const struct ccs_path_info *handler = ee->handler;          const struct ccs_path_info *handler = ee->handler;
472          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
473          const char *old_domain_name = r->domain->domainname->name;          struct ccs_domain_info * const old_domain = ccs_current_domain();
474          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
475          const u32 ccs_flags = current->ccs_flags;          struct task_struct *task = current;
476          struct ccs_path_info rn = { }; /* real name */          struct ccs_path_info rn = { }; /* real name */
         struct ccs_path_info ln; /* last name */  
477          int retval;          int retval;
478          bool need_kfree = false;          bool need_kfree = false;
         ln.name = ccs_last_word(old_domain_name);  
         ccs_fill_path_info(&ln);  
479   retry:   retry:
480          current->ccs_flags = ccs_flags;          r->matched_acl = NULL;
         r->cond = NULL;  
481          if (need_kfree) {          if (need_kfree) {
482                  kfree(rn.name);                  kfree(rn.name);
483                  need_kfree = false;                  need_kfree = false;
# Line 607  static int ccs_find_next_domain(struct c Line 501  static int ccs_find_next_domain(struct c
501                          goto out;                          goto out;
502                  }                  }
503          } else {          } else {
504                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator *ptr;
505                  /* Check 'aggregator' directive. */                  /* Check 'aggregator' directive. */
506                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {                  list_for_each_entry_rcu(ptr,
507                          if (ptr->is_deleted ||                                          &ccs_policy_list[CCS_ID_AGGREGATOR],
508                                            head.list) {
509                            if (ptr->head.is_deleted ||
510                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
511                                  continue;                                  continue;
512                          kfree(rn.name);                          kfree(rn.name);
# Line 621  static int ccs_find_next_domain(struct c Line 517  static int ccs_find_next_domain(struct c
517                  }                  }
518    
519                  /* Check execute permission. */                  /* Check execute permission. */
520                  retval = ccs_exec_perm(r, &rn);                  retval = ccs_path_permission(r, CCS_TYPE_EXECUTE, &rn);
521                  if (retval == 1)                  if (retval == CCS_RETRY_REQUEST)
522                          goto retry;                          goto retry;
523                  if (retval < 0)                  if (retval < 0)
524                          goto out;                          goto out;
525                    /*
526                     * To be able to specify domainnames with wildcards, use the
527                     * pathname specified in the policy (which may contain
528                     * wildcard) rather than the pathname passed to execve()
529                     * (which never contains wildcard).
530                     */
531                    if (r->param.path.matched_path) {
532                            if (need_kfree)
533                                    kfree(rn.name);
534                            need_kfree = false;
535                            /* This is OK because it is read only. */
536                            rn = *r->param.path.matched_path;
537                    }
538          }          }
539    
540          /* Calculate domain to transit to. */          /* Calculate domain to transit to. */
541          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {          switch (ccs_transition_type(old_domain->domainname, &rn)) {
542            case CCS_TRANSITION_CONTROL_INITIALIZE:
543                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
544                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, CCS_ROOT_NAME " " "%s",
545                           rn.name);                           rn.name);
546          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {                  break;
547                  /*          case CCS_TRANSITION_CONTROL_KEEP:
                  * Needn't to transit from kernel domain before starting  
                  * /sbin/init. But transit from kernel domain if executing  
                  * initializers because they might start before /sbin/init.  
                  */  
                 domain = r->domain;  
         } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {  
548                  /* Keep current domain. */                  /* Keep current domain. */
549                  domain = r->domain;                  domain = old_domain;
550          } else {                  break;
551                  /* Normal domain transition. */          default:
552                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",                  if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
553                           old_domain_name, rn.name);                          /*
554          }                           * Needn't to transit from kernel domain before
555          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)                           * starting /sbin/init. But transit from kernel domain
556                  goto done;                           * if executing initializers because they might start
557          domain = ccs_find_domain(ee->tmp);                           * before /sbin/init.
558          if (domain)                           */
559                  goto done;                          domain = old_domain;
560          if (r->mode == CCS_MAC_MODE_ENFORCING) {                  } else {
561                  int error = ccs_supervisor(r, "# wants to create domain\n"                          /* Normal domain transition. */
562                                             "%s\n", ee->tmp);                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
563                  if (error == 1)                                   old_domain->domainname->name, rn.name);
564                          goto retry;                  }
565                  if (error < 0)                  break;
                         goto done;  
566          }          }
567          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);          /*
568             * Tell GC that I started execve().
569             * Also, tell open_exec() to check read permission.
570             */
571            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
572            /*
573             * Make task->ccs_flags visible to GC before changing
574             * task->ccs_domain_info .
575             */
576            smp_mb();
577            /*
578             * Proceed to the next domain in order to allow reaching via PID.
579             * It will be reverted if execve() failed. Reverting is not good.
580             * But it is better than being unable to reach via PID in interactive
581             * enforcing mode.
582             */
583            if (!domain)
584                    domain = ccs_assign_domain(ee->tmp, r->profile,
585                                               old_domain->group, true);
586          if (domain)          if (domain)
                 ccs_audit_domain_creation_log(r->domain);  
  done:  
         if (!domain) {  
                 printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",  
                        ee->tmp);  
                 if (r->mode == CCS_MAC_MODE_ENFORCING)  
                         retval = -EPERM;  
                 else {  
                         retval = 0;  
                         r->domain->domain_transition_failed = true;  
                 }  
         } else {  
587                  retval = 0;                  retval = 0;
588            else if (r->mode == CCS_CONFIG_ENFORCING)
589                    retval = -ENOMEM;
590            else {
591                    retval = 0;
592                    if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) {
593                            old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true;
594                            r->granted = false;
595                            ccs_write_log(r, "%s",
596                                          ccs_dif[CCS_DIF_TRANSITION_FAILED]);
597                            printk(KERN_WARNING
598                                   "ERROR: Domain '%s' not defined.\n", ee->tmp);
599                    }
600          }          }
601   out:   out:
         if (domain)  
                 r->domain = domain;  
602          if (need_kfree)          if (need_kfree)
603                  kfree(rn.name);                  kfree(rn.name);
604          return retval;          return retval;
# Line 688  static int ccs_find_next_domain(struct c Line 607  static int ccs_find_next_domain(struct c
607  /**  /**
608   * ccs_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
609   *   *
610   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
611   *   *
612   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
613   */   */
614  static int ccs_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve *ee)
615  {  {
616          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
617          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
618          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
619            struct ccs_page_dump env_page = { };
620            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
621          int arg_len = 0;          int arg_len = 0;
622          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
623          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 704  static int ccs_environ(struct ccs_execve Line 625  static int ccs_environ(struct ccs_execve
625          int envp_count = bprm->envc;          int envp_count = bprm->envc;
626          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
627          int error = -ENOMEM;          int error = -ENOMEM;
628            ee->r.type = CCS_MAC_ENVIRON;
629            ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
630                                      CCS_MAC_ENVIRON);
631          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
632                  return 0;                  return 0;
633            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
634            if (!arg_ptr)
635                    goto out;
636          while (error == -ENOMEM) {          while (error == -ENOMEM) {
637                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
638                          goto out;                          goto out;
639                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
640                  /* Read. */                  /* Read. */
641                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
642                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
643                                  argv_count--;                                  argv_count--;
644                  }                  }
645                  if (argv_count) {                  if (argv_count) {
# Line 721  static int ccs_environ(struct ccs_execve Line 647  static int ccs_environ(struct ccs_execve
647                          continue;                          continue;
648                  }                  }
649                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
650                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
                         const unsigned char c = kaddr[offset++];  
651                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
652                                  if (c == '=') {                                  if (c == '=') {
653                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
# Line 758  static int ccs_environ(struct ccs_execve Line 683  static int ccs_environ(struct ccs_execve
683   out:   out:
684          if (r->mode != 3)          if (r->mode != 3)
685                  error = 0;                  error = 0;
686            kfree(env_page.data);
687            kfree(arg_ptr);
688          return error;          return error;
689  }  }
690    
# Line 800  static void ccs_unescape(unsigned char * Line 727  static void ccs_unescape(unsigned char *
727          *dest = '\0';          *dest = '\0';
728  }  }
729    
730  /**  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
731   * ccs_root_depth - Get number of directories to strip.  static int ccs_copy_argv(const char *arg, struct linux_binprm *bprm)
  *  
  * @dentry: Pointer to "struct dentry".  
  * @vfsmnt: Pointer to "struct vfsmount".  
  *  
  * Returns number of directories to strip.  
  */  
 static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  
732  {  {
733          int depth = 0;          const int ret = copy_strings_kernel(1, &arg, bprm);
734          ccs_realpath_lock();          if (ret >= 0)
735          for (;;) {                  bprm->argc++;
736                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {          return ret;
                         /* Global root? */  
                         if (vfsmnt->mnt_parent == vfsmnt)  
                                 break;  
                         dentry = vfsmnt->mnt_mountpoint;  
                         vfsmnt = vfsmnt->mnt_parent;  
                         continue;  
                 }  
                 dentry = dentry->d_parent;  
                 depth++;  
         }  
         ccs_realpath_unlock();  
         return depth;  
737  }  }
   
 /**  
  * ccs_get_root_depth - return the depth of root directory.  
  *  
  * Returns number of directories to strip.  
  */  
 static int ccs_get_root_depth(void)  
 {  
         int depth;  
         struct dentry *dentry;  
         struct vfsmount *vfsmnt;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  
         struct path root;  
 #endif  
         read_lock(&current->fs->lock);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  
         root = current->fs->root;  
         path_get(&current->fs->root);  
         dentry = root.dentry;  
         vfsmnt = root.mnt;  
 #else  
         dentry = dget(current->fs->root);  
         vfsmnt = mntget(current->fs->rootmnt);  
 #endif  
         read_unlock(&current->fs->lock);  
         depth = ccs_root_depth(dentry, vfsmnt);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  
         path_put(&root);  
738  #else  #else
739          dput(dentry);  static int ccs_copy_argv(char *arg, struct linux_binprm *bprm)
         mntput(vfsmnt);  
 #endif  
         return depth;  
 }  
   
 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 = kzalloc(sizeof(*ee), GFP_KERNEL);  
         if (!ee)  
                 return NULL;  
         ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);  
         if (!ee->tmp) {  
                 kfree(ee);  
                 return NULL;  
         }  
         ee->reader_idx = ccs_read_lock();  
         /* ee->dump->data is allocated by ccs_dump_page(). */  
         ee->task = current;  
         spin_lock(&ccs_execve_list_lock);  
         list_add(&ee->list, &ccs_execve_list);  
         spin_unlock(&ccs_execve_list_lock);  
         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;  
         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);  
         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)  
740  {  {
741          if (!ee)          const int ret = copy_strings_kernel(1, &arg, bprm);
742                  return;          if (ret >= 0)
743          spin_lock(&ccs_execve_list_lock);                  bprm->argc++;
744          list_del(&ee->list);          return ret;
         spin_unlock(&ccs_execve_list_lock);  
         kfree(ee->handler_path);  
         kfree(ee->tmp);  
         kfree(ee->dump.data);  
         ccs_read_unlock(ee->reader_idx);  
         kfree(ee);  
745  }  }
746    #endif
747    
748  /**  /**
749   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
750   *   *
751   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
752   *   *
753   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
754   */   */
755  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)  static int ccs_try_alt_exec(struct ccs_execve *ee)
756  {  {
757          /*          /*
758           * Contents of modified bprm.           * Contents of modified bprm.
# Line 950  static int ccs_try_alt_exec(struct ccs_e Line 766  static int ccs_try_alt_exec(struct ccs_e
766           *    = 0           *    = 0
767           *           *
768           * modified bprm->argv[0]           * modified bprm->argv[0]
769           *    = the program's name specified by execute_handler           *    = the program's name specified by *_execute_handler
770           * modified bprm->argv[1]           * modified bprm->argv[1]
771           *    = ccs_current_domain()->domainname->name           *    = ccs_current_domain()->domainname->name
772           * modified bprm->argv[2]           * modified bprm->argv[2]
# Line 982  static int ccs_try_alt_exec(struct ccs_e Line 798  static int ccs_try_alt_exec(struct ccs_e
798          struct task_struct *task = current;          struct task_struct *task = current;
799    
800          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
801            ee->obj.path1.dentry = NULL;
802            ee->obj.path1.mnt = NULL;
803            ee->obj.validate_done = false;
804          allow_write_access(bprm->file);          allow_write_access(bprm->file);
805          fput(bprm->file);          fput(bprm->file);
806          bprm->file = NULL;          bprm->file = NULL;
# Line 995  static int ccs_try_alt_exec(struct ccs_e Line 814  static int ccs_try_alt_exec(struct ccs_e
814    
815          /* Set argv[6] */          /* Set argv[6] */
816          {          {
                 char *cp = ee->tmp;  
817                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
818                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = ccs_copy_argv(ee->tmp, bprm);
819                  if (retval < 0)                  if (retval < 0)
820                          goto out;                          goto out;
                 bprm->argc++;  
821          }          }
822    
823          /* Set argv[5] */          /* Set argv[5] */
824          {          {
                 char *cp = ee->tmp;  
825                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
826                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = ccs_copy_argv(ee->tmp, bprm);
827                  if (retval < 0)                  if (retval < 0)
828                          goto out;                          goto out;
                 bprm->argc++;  
829          }          }
830    
831          /* Set argv[4] */          /* Set argv[4] */
832          {          {
833                  retval = copy_strings_kernel(1, &bprm->filename, bprm);                  retval = ccs_copy_argv(bprm->filename, bprm);
834                  if (retval < 0)                  if (retval < 0)
835                          goto out;                          goto out;
                 bprm->argc++;  
836          }          }
837    
838          /* Set argv[3] */          /* Set argv[3] */
839          {          {
                 char *cp = ee->tmp;  
                 const u32 ccs_flags = task->ccs_flags;  
840                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
841                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
842                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d",
843                           "state[1]=%u state[2]=%u",                           (pid_t) ccsecurity_exports.sys_getpid(),
844                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           current_uid(), current_gid(), current_euid(),
845                           current_euid(), current_egid(), current_suid(),                           current_egid(), current_suid(), current_sgid(),
846                           current_sgid(), current_fsuid(), current_fsgid(),                           current_fsuid(), current_fsgid());
847                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                  retval = ccs_copy_argv(ee->tmp, bprm);
                          (u8) (ccs_flags >> 8));  
                 retval = copy_strings_kernel(1, &cp, bprm);  
848                  if (retval < 0)                  if (retval < 0)
849                          goto out;                          goto out;
                 bprm->argc++;  
850          }          }
851    
852          /* Set argv[2] */          /* Set argv[2] */
853          {          {
854                  char *exe = (char *) ccs_get_exe();                  char *exe = (char *) ccs_get_exe();
855                  if (exe) {                  if (exe) {
856                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = ccs_copy_argv(exe, bprm);
857                          kfree(exe);                          kfree(exe);
858                  } else {                  } else {
859                          exe = ee->tmp;  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
860                            retval = ccs_copy_argv("<unknown>", bprm);
861    #else
862                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");                          snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
863                          retval = copy_strings_kernel(1, &exe, bprm);                          retval = ccs_copy_argv(ee->tmp, bprm);
864    #endif
865                  }                  }
866                  if (retval < 0)                  if (retval < 0)
867                          goto out;                          goto out;
                 bprm->argc++;  
868          }          }
869    
870          /* Set argv[1] */          /* Set argv[1] */
871          {          {
872                  char *cp = ee->tmp;  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
873                    retval = ccs_copy_argv(ccs_current_domain()->domainname->name,
874                                           bprm);
875    #else
876                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
877                           ccs_current_domain()->domainname->name);                           ccs_current_domain()->domainname->name);
878                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = ccs_copy_argv(ee->tmp, bprm);
879    #endif
880                  if (retval < 0)                  if (retval < 0)
881                          goto out;                          goto out;
                 bprm->argc++;  
882          }          }
883    
884          /* Set argv[0] */          /* Set argv[0] */
885          {          {
886                  int depth = ccs_get_root_depth();                  struct path root;
887                  int len = ee->handler->total_len + 1;                  char *cp;
888                  char *cp = kmalloc(len, GFP_KERNEL);                  int root_len;
889                    int handler_len;
890                    get_fs_root(current->fs, &root);
891                    cp = ccs_realpath_from_path(&root);
892                    path_put(&root);
893                  if (!cp) {                  if (!cp) {
894                          retval = ENOMEM;                          retval = -ENOMEM;
895                            goto out;
896                    }
897                    root_len = strlen(cp);
898                    retval = strncmp(ee->handler->name, cp, root_len);
899                    root_len--;
900                    kfree(cp);
901                    if (retval) {
902                            retval = -ENOENT;
903                          goto out;                          goto out;
904                  }                  }
905                    handler_len = ee->handler->total_len + 1;
906                    cp = kmalloc(handler_len, CCS_GFP_FLAGS);
907                    if (!cp) {
908                            retval = -ENOMEM;
909                            goto out;
910                    }
911                    /* ee->handler_path is released by ccs_finish_execve(). */
912                  ee->handler_path = cp;                  ee->handler_path = cp;
913                  memmove(cp, ee->handler->name, len);                  /* Adjust root directory for open_exec(). */
914                    memmove(cp, ee->handler->name + root_len,
915                            handler_len - root_len);
916                  ccs_unescape(cp);                  ccs_unescape(cp);
917                  retval = -ENOENT;                  retval = -ENOENT;
918                  if (!*cp || *cp != '/')                  if (!*cp || *cp != '/')
919                          goto out;                          goto out;
920                  /* Adjust root directory for open_exec(). */                  retval = ccs_copy_argv(cp, bprm);
                 while (depth) {  
                         cp = strchr(cp + 1, '/');  
                         if (!cp)  
                                 goto out;  
                         depth--;  
                 }  
                 memmove(ee->handler_path, cp, strlen(cp) + 1);  
                 cp = ee->handler_path;  
                 retval = copy_strings_kernel(1, &cp, bprm);  
921                  if (retval < 0)                  if (retval < 0)
922                          goto out;                          goto out;
                 bprm->argc++;  
923          }          }
924  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
925  #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)  #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
# Line 1102  static int ccs_try_alt_exec(struct ccs_e Line 927  static int ccs_try_alt_exec(struct ccs_e
927  #endif  #endif
928  #endif  #endif
929    
930          /* OK, now restart the process with execute handler program's dentry. */          /*
931             * OK, now restart the process with execute handler program's dentry.
932             */
933          filp = open_exec(ee->handler_path);          filp = open_exec(ee->handler_path);
934          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
935                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
936                  goto out;                  goto out;
937          }          }
938            ee->obj.path1.dentry = filp->f_dentry;
939            ee->obj.path1.mnt = filp->f_vfsmnt;
940          bprm->file = filp;          bprm->file = filp;
941          bprm->filename = ee->handler_path;          bprm->filename = ee->handler_path;
942  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
# Line 1126  static int ccs_try_alt_exec(struct ccs_e Line 955  static int ccs_try_alt_exec(struct ccs_e
955  /**  /**
956   * ccs_find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
957   *   *
958   * @ee:   Pointer to "struct ccs_execve_entry".   * @ee:   Pointer to "struct ccs_execve".
959   * @type: Type of execute handler.   * @type: Type of execute handler.
960   *   *
961   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
962   *   *
963   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
964   */   */
965  static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,  static bool ccs_find_execute_handler(struct ccs_execve *ee, const u8 type)
                                      const u8 type)  
966  {  {
967          struct task_struct *task = current;          struct ccs_request_info *r = &ee->r;
         const struct ccs_domain_info *domain = ccs_current_domain();  
         struct ccs_acl_info *ptr;  
         bool found = false;  
968          /*          /*
969           * Don't use execute handler if the current process is           * To avoid infinite execute handler loop, don't use execute handler
970           * marked as execute handler to avoid infinite execute handler loop.           * if the current process is marked as execute handler .
971           */           */
972          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)          if (current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
973                  return false;                  return false;
974          list_for_each_entry(ptr, &domain->acl_info_list, list) {          r->param_type = type;
975                  struct ccs_execute_handler_record *acl;          ccs_check_acl(r, NULL);
976                  if (ptr->type != type)          if (!r->granted)
977                          continue;                  return false;
978                  acl = container_of(ptr, struct ccs_execute_handler_record,          ee->handler = container_of(r->matched_acl, struct ccs_handler_acl,
979                                     head);                                     head)->handler;
980                  ee->handler = acl->handler;          return true;
                 found = true;  
                 break;  
         }  
         return found;  
981  }  }
982    
983    #ifdef CONFIG_MMU
984    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
985    #define CCS_BPRM_MMU
986    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3
987    #define CCS_BPRM_MMU
988    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2
989    #define CCS_BPRM_MMU
990    #endif
991    #endif
992    
993  /**  /**
994   * ccs_dump_page - Dump a page to buffer.   * ccs_dump_page - Dump a page to buffer.
995   *   *
# Line 1172  bool ccs_dump_page(struct linux_binprm * Line 1003  bool ccs_dump_page(struct linux_binprm *
1003                     struct ccs_page_dump *dump)                     struct ccs_page_dump *dump)
1004  {  {
1005          struct page *page;          struct page *page;
1006          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_finish_execve(). */
1007          if (!dump->data) {          if (!dump->data) {
1008                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1009                  if (!dump->data)                  if (!dump->data)
1010                          return false;                          return false;
1011          }          }
1012          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1013  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #ifdef CCS_BPRM_MMU
         if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)  
                 return false;  
 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  
1014          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)
1015                  return false;                  return false;
1016  #else  #else
# Line 1197  bool ccs_dump_page(struct linux_binprm * Line 1025  bool ccs_dump_page(struct linux_binprm *
1025                   */                   */
1026                  char *kaddr = kmap_atomic(page, KM_USER0);                  char *kaddr = kmap_atomic(page, KM_USER0);
1027                  dump->page = page;                  dump->page = page;
1028                  memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);                  memcpy(dump->data + offset, kaddr + offset,
1029                           PAGE_SIZE - offset);
1030                  kunmap_atomic(kaddr, KM_USER0);                  kunmap_atomic(kaddr, KM_USER0);
1031          }          }
1032          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1033  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #ifdef CCS_BPRM_MMU
         put_page(page);  
 #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)  
1034          put_page(page);          put_page(page);
1035  #endif  #endif
1036          return true;          return true;
1037  }  }
1038    
1039  /**  /**
  * 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;  
 }  
   
 /**  
1040   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1041   *   *
1042   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1043     * @eep:  Pointer to "struct ccs_execve *".
1044   *   *
1045   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1046   */   */
1047  int ccs_start_execve(struct linux_binprm *bprm)  static int ccs_start_execve(struct linux_binprm *bprm,
1048                                struct ccs_execve **eep)
1049  {  {
1050          int retval;          int retval;
1051          struct task_struct *task = current;          struct task_struct *task = current;
1052          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();          struct ccs_execve *ee;
1053          if (!ccs_policy_loaded)          *eep = NULL;
1054                  ccs_load_policy(bprm->filename);          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1055          if (!ee)          if (!ee)
1056                  return -ENOMEM;                  return -ENOMEM;
1057          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1058            if (!ee->tmp) {
1059                    kfree(ee);
1060                    return -ENOMEM;
1061            }
1062            ee->reader_idx = ccs_read_lock();
1063            /* ee->dump->data is allocated by ccs_dump_page(). */
1064            ee->previous_domain = task->ccs_domain_info;
1065            /* Clear manager flag. */
1066            task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1067            *eep = ee;
1068            ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1069          ee->r.ee = ee;          ee->r.ee = ee;
1070          ee->bprm = bprm;          ee->bprm = bprm;
1071          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1072          ee->obj.path1.dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1073          ee->obj.path1.mnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1074          /* Clear manager flag. */          /*
1075          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;           * No need to call ccs_environ() for execute handler because envp[] is
1076          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {           * moved to argv[].
1077                  retval = ccs_try_alt_exec(ee);           */
1078                  if (!retval)          if (ccs_find_execute_handler(ee, CCS_TYPE_AUTO_EXECUTE_HANDLER))
1079                          ccs_audit_execute_handler_log(ee, true);                  return ccs_try_alt_exec(ee);
                 goto ok;  
         }  
1080          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1081          if (retval != -EPERM)          if (retval == -EPERM) {
1082                  goto ok;                  if (ccs_find_execute_handler(ee,
1083          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {                                               CCS_TYPE_DENIED_EXECUTE_HANDLER))
1084                  retval = ccs_try_alt_exec(ee);                          return ccs_try_alt_exec(ee);
                 if (!retval)  
                         ccs_audit_execute_handler_log(ee, false);  
1085          }          }
1086   ok:          if (!retval)
1087          if (retval < 0)                  retval = ccs_environ(ee);
                 goto out;  
         ee->r.mode = ccs_get_mode(ee->r.profile, CCS_MAC_ENVIRON);  
         retval = ccs_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);  
1088          return retval;          return retval;
1089  }  }
1090    
# Line 1283  int ccs_start_execve(struct linux_binprm Line 1092  int ccs_start_execve(struct linux_binprm
1092   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1093   *   *
1094   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1095     * @ee:     Pointer to "struct ccs_execve".
1096   *   *
1097   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1098   */   */
1099  void ccs_finish_execve(int retval)  static void ccs_finish_execve(int retval, struct ccs_execve *ee)
1100  {  {
1101          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;  
1102          if (!ee)          if (!ee)
1103                  return;                  return;
1104          if (retval < 0)          if (retval < 0) {
1105                  goto out;                  task->ccs_domain_info = ee->previous_domain;
1106          /* Proceed to next domain if execution suceeded. */                  /*
1107          task->ccs_domain_info = ee->r.domain;                   * Make task->ccs_domain_info visible to GC before changing
1108          /* Mark the current process as execute handler. */                   * task->ccs_flags .
1109          if (ee->handler)                   */
1110                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  smp_mb();
1111          /* Mark the current process as normal process. */          } else {
1112          else                  /* Mark the current process as execute handler. */
1113                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                  if (ee->handler)
1114   out:                          task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1115          ccs_free_execve_entry(ee);                  /* Mark the current process as normal process. */
1116                    else
1117                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1118            }
1119            /* Tell GC that I finished execve(). */
1120            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1121            ccs_read_unlock(ee->reader_idx);
1122            kfree(ee->handler_path);
1123            kfree(ee->tmp);
1124            kfree(ee->dump.data);
1125            kfree(ee);
1126    }
1127    
1128    static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1129                                           struct pt_regs *regs)
1130    {
1131            struct ccs_execve *ee;
1132            int retval;
1133            if (!ccs_policy_loaded)
1134                    ccsecurity_exports.load_policy(bprm->filename);
1135            retval = ccs_start_execve(bprm, &ee);
1136            if (!retval)
1137                    retval = search_binary_handler(bprm, regs);
1138            ccs_finish_execve(retval, ee);
1139            return retval;
1140    }
1141    
1142    void __init ccs_domain_init(void)
1143    {
1144            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1145  }  }

Legend:
Removed from v.2951  
changed lines
  Added in v.3968

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