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

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 branches/ccs-patch/security/ccsecurity/domain.c revision 3697 by kumaneko, Tue May 25 08:24:59 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.7.2+   2010/05/05
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_global_domain;
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    struct list_head ccs_group_list[CCS_MAX_GROUP];
38    struct list_head ccs_shared_list[CCS_MAX_LIST];
39    
40  /**  /**
41   * ccs_audit_execute_handler_log - Audit execute_handler log.   * ccs_audit_execute_handler_log - Audit execute_handler log.
42   *   *
43   * @ee:         Pointer to "struct ccs_execve_entry".   * @ee:         Pointer to "struct ccs_execve".
  * @is_default: True if it is "execute_handler" log.  
44   *   *
45   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
46   */   */
47  static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,  static int ccs_audit_execute_handler_log(struct ccs_execve *ee)
                                          const bool is_default)  
48  {  {
49          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
50          const char *handler = ee->handler->name;          const char *handler = ee->handler->name;
51            r->type = CCS_MAC_FILE_EXECUTE;
52          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
53          return ccs_write_audit_log(true, r, "%s %s\n",          return ccs_write_log(true, r, "%s %s\n", ee->handler_type ==
54                                     is_default ? CCS_KEYWORD_EXECUTE_HANDLER :                               CCS_TYPE_DENIED_EXECUTE_HANDLER ?
55                                     CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);                               CCS_KEYWORD_DENIED_EXECUTE_HANDLER :
56                                 CCS_KEYWORD_EXECUTE_HANDLER, handler);
57  }  }
58    
59  /**  /**
60   * ccs_audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
61   *   *
  * @domain:  Pointer to "struct ccs_domain_info".  
  *  
62   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
63   */   */
64  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  static int ccs_audit_domain_creation_log(void)
65  {  {
         int error;  
66          struct ccs_request_info r;          struct ccs_request_info r;
67          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);          ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
68          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);          return ccs_write_log(false, &r, "use_profile %u\n", r.profile);
69    }
70    
71    int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
72                          bool is_delete, const int idx, bool (*check_duplicate)
73                          (const struct ccs_acl_head *,
74                           const struct ccs_acl_head *))
75    {
76            int error = is_delete ? -ENOENT : -ENOMEM;
77            struct ccs_acl_head *entry;
78            if (mutex_lock_interruptible(&ccs_policy_lock))
79                    return -ENOMEM;
80            list_for_each_entry_rcu(entry, &ccs_policy_list[idx], list) {
81                    if (!check_duplicate(entry, new_entry))
82                            continue;
83                    entry->is_deleted = is_delete;
84                    error = 0;
85                    break;
86            }
87            if (error && !is_delete) {
88                    entry = ccs_commit_ok(new_entry, size);
89                    if (entry) {
90                            list_add_tail_rcu(&entry->list, &ccs_policy_list[idx]);
91                            error = 0;
92                    }
93            }
94            mutex_unlock(&ccs_policy_lock);
95          return error;          return error;
96  }  }
97    
98  /* The list for "struct ccs_domain_initializer_entry". */  int ccs_update_group(struct ccs_acl_head *new_entry, const int size,
99  LIST_HEAD(ccs_domain_initializer_list);                       bool is_delete, struct ccs_group *group,
100                         bool (*check_duplicate) (const struct ccs_acl_head *,
101                                                  const struct ccs_acl_head *))
102    {
103            int error = is_delete ? -ENOENT : -ENOMEM;
104            struct ccs_acl_head *entry;
105            if (mutex_lock_interruptible(&ccs_policy_lock))
106                    return -ENOMEM;
107            list_for_each_entry_rcu(entry, &group->member_list, list) {
108                    if (!check_duplicate(entry, new_entry))
109                            continue;
110                    entry->is_deleted = is_delete;
111                    error = 0;
112                    break;
113            }
114            if (!is_delete && error) {
115                    entry = ccs_commit_ok(new_entry, size);
116                    if (entry) {
117                            list_add_tail_rcu(&entry->list, &group->member_list);
118                            error = 0;
119                    }
120            }
121            mutex_unlock(&ccs_policy_lock);
122            return error;
123    }
124    
125    static void ccs_delete_type(struct ccs_domain_info *domain, u8 type)
126    {
127            struct ccs_acl_info *ptr;
128            list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
129                    if (ptr->type == type)
130                            ptr->is_deleted = true;
131            }
132    }
133    
134    int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
135                          bool is_delete, struct ccs_domain_info *domain,
136                          bool (*check_duplicate) (const struct ccs_acl_info *,
137                                                   const struct ccs_acl_info *),
138                          bool (*merge_duplicate) (struct ccs_acl_info *,
139                                                   struct ccs_acl_info *,
140                                                   const bool))
141    {
142            int error = is_delete ? -ENOENT : -ENOMEM;
143            struct ccs_acl_info *entry;
144            /*
145             * Only one "execute_handler" and "denied_execute_handler" can exist
146             * in a domain.
147             */
148            const u8 type = new_entry->type;
149            const bool exclusive = !is_delete &&
150                    (type == CCS_TYPE_EXECUTE_HANDLER ||
151                     type == CCS_TYPE_DENIED_EXECUTE_HANDLER);
152            if (mutex_lock_interruptible(&ccs_policy_lock))
153                    return error;
154            list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
155                    if (!check_duplicate(entry, new_entry))
156                            continue;
157                    if (exclusive)
158                            ccs_delete_type(domain, type);
159                    if (merge_duplicate)
160                            entry->is_deleted = merge_duplicate(entry, new_entry,
161                                                                is_delete);
162                    else
163                            entry->is_deleted = is_delete;
164                    error = 0;
165                    break;
166            }
167            if (error && !is_delete) {
168                    entry = ccs_commit_ok(new_entry, size);
169                    if (entry) {
170                            if (exclusive)
171                                    ccs_delete_type(domain, type);
172                            ccs_add_domain_acl(domain, entry);
173                            error = 0;
174                    }
175            }
176            mutex_unlock(&ccs_policy_lock);
177            return error;
178    }
179    
180    static bool ccs_same_domain_initializer_entry(const struct ccs_acl_head *a,
181                                                  const struct ccs_acl_head *b)
182    {
183            const struct ccs_domain_initializer *p1 = container_of(a, typeof(*p1),
184                                                                   head);
185            const struct ccs_domain_initializer *p2 = container_of(b, typeof(*p2),
186                                                                   head);
187            return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
188                    && p1->domainname == p2->domainname
189                    && p1->program == p2->program;
190    }
191    
192  /**  /**
193   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.   * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer" list.
194   *   *
195   * @domainname: The name of domain. May be NULL.   * @domainname: The name of domain. May be NULL.
196   * @program:    The name of program.   * @program:    The name of program.
# Line 88  static int ccs_update_domain_initializer Line 204  static int ccs_update_domain_initializer
204                                                 const bool is_not,                                                 const bool is_not,
205                                                 const bool is_delete)                                                 const bool is_delete)
206  {  {
207          struct ccs_domain_initializer_entry *entry = NULL;          struct ccs_domain_initializer e = { .is_not = is_not };
         struct ccs_domain_initializer_entry *ptr;  
         struct ccs_domain_initializer_entry e = { .is_not = is_not };  
208          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
209          if (!ccs_is_correct_path(program, 1, -1, -1))          if (!ccs_correct_path(program, 1, -1, -1))
210                  return -EINVAL; /* No patterns allowed. */                  return -EINVAL; /* No patterns allowed. */
211          if (domainname) {          if (domainname) {
212                  if (!ccs_is_domain_def(domainname) &&                  if (!ccs_domain_def(domainname) &&
213                      ccs_is_correct_path(domainname, 1, -1, -1))                      ccs_correct_path(domainname, 1, -1, -1))
214                          e.is_last_name = true;                          e.is_last_name = true;
215                  else if (!ccs_is_correct_domain(domainname))                  else if (!ccs_correct_domain(domainname))
216                          return -EINVAL;                          return -EINVAL;
217                  e.domainname = ccs_get_name(domainname);                  e.domainname = ccs_get_name(domainname);
218                  if (!e.domainname)                  if (!e.domainname)
# Line 107  static int ccs_update_domain_initializer Line 221  static int ccs_update_domain_initializer
221          e.program = ccs_get_name(program);          e.program = ccs_get_name(program);
222          if (!e.program)          if (!e.program)
223                  goto out;                  goto out;
224          if (!is_delete)          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
225                  entry = kmalloc(sizeof(e), GFP_KERNEL);                                    CCS_ID_DOMAIN_INITIALIZER,
226          mutex_lock(&ccs_policy_lock);                                    ccs_same_domain_initializer_entry);
         list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {  
                 if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),  
                                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_domain_initializer_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
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_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 ccs_read_lock().  
  */  
 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" 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.  
235   *   *
236   * @data:      String to parse.   * @data:      String to parse.
  * @is_not:    True if it is "no_initialize_domain" entry.  
237   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
238   *   *
239   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
240   */   */
241  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)  
242  {  {
243          char *cp = strstr(data, " from ");          char *domainname = strstr(data, " from ");
244          if (cp) {          if (domainname) {
245                  *cp = '\0';                  *domainname = '\0';
246                  return ccs_update_domain_initializer_entry(cp + 6, data,                  domainname += 6;
                                                            is_not, is_delete);  
247          }          }
248          return ccs_update_domain_initializer_entry(NULL, data, is_not,          return ccs_update_domain_initializer_entry(domainname, data, flags,
249                                                     is_delete);                                                     is_delete);
250  }  }
251    
252  /**  /**
253   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.   * ccs_domain_initializer - Check whether the given program causes domainname reinitialization.
254   *   *
255   * @domainname: The name of domain.   * @domainname: The name of domain.
256   * @program:    The name of program.   * @program:    The name of program.
# Line 202  int ccs_write_domain_initializer_policy( Line 261  int ccs_write_domain_initializer_policy(
261   *   *
262   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
263   */   */
264  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,  static bool ccs_domain_initializer(const struct ccs_path_info *domainname,
265                                        const struct ccs_path_info *program,                                        const struct ccs_path_info *program,
266                                        const struct ccs_path_info *last_name)                                        const struct ccs_path_info *last_name)
267  {  {
268          struct ccs_domain_initializer_entry *ptr;          struct ccs_domain_initializer *ptr;
269          bool flag = false;          bool flag = false;
270          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {          list_for_each_entry_rcu(ptr, &ccs_policy_list
271                  if (ptr->is_deleted)                                  [CCS_ID_DOMAIN_INITIALIZER], head.list) {
272                    if (ptr->head.is_deleted)
273                          continue;                          continue;
274                  if (ptr->domainname) {                  if (ptr->domainname) {
275                          if (!ptr->is_last_name) {                          if (!ptr->is_last_name) {
# Line 231  static bool ccs_is_domain_initializer(co Line 291  static bool ccs_is_domain_initializer(co
291          return flag;          return flag;
292  }  }
293    
294  /* The list for "struct ccs_domain_keeper_entry". */  static bool ccs_same_domain_keeper_entry(const struct ccs_acl_head *a,
295  LIST_HEAD(ccs_domain_keeper_list);                                           const struct ccs_acl_head *b)
296    {
297            const struct ccs_domain_keeper *p1 = container_of(a, typeof(*p1),
298                                                              head);
299            const struct ccs_domain_keeper *p2 = container_of(b, typeof(*p2),
300                                                              head);
301            return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
302                    && p1->domainname == p2->domainname
303                    && p1->program == p2->program;
304    }
305    
306  /**  /**
307   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper" list.
308   *   *
309   * @domainname: The name of domain.   * @domainname: The name of domain.
310   * @program:    The name of program. May be NULL.   * @program:    The name of program. May be NULL.
# Line 249  static int ccs_update_domain_keeper_entr Line 318  static int ccs_update_domain_keeper_entr
318                                            const bool is_not,                                            const bool is_not,
319                                            const bool is_delete)                                            const bool is_delete)
320  {  {
321          struct ccs_domain_keeper_entry *entry = NULL;          struct ccs_domain_keeper e = { .is_not = is_not };
         struct ccs_domain_keeper_entry *ptr;  
         struct ccs_domain_keeper_entry e = { .is_not = is_not };  
322          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
323          if (!ccs_is_domain_def(domainname) &&          if (!ccs_domain_def(domainname) &&
324              ccs_is_correct_path(domainname, 1, -1, -1))              ccs_correct_path(domainname, 1, -1, -1))
325                  e.is_last_name = true;                  e.is_last_name = true;
326          else if (!ccs_is_correct_domain(domainname))          else if (!ccs_correct_domain(domainname))
327                  return -EINVAL;                  return -EINVAL;
328          if (program) {          if (program) {
329                  if (!ccs_is_correct_path(program, 1, -1, -1))                  if (!ccs_correct_path(program, 1, -1, -1))
330                          return -EINVAL;                          return -EINVAL;
331                  e.program = ccs_get_name(program);                  e.program = ccs_get_name(program);
332                  if (!e.program)                  if (!e.program)
# Line 268  static int ccs_update_domain_keeper_entr Line 335  static int ccs_update_domain_keeper_entr
335          e.domainname = ccs_get_name(domainname);          e.domainname = ccs_get_name(domainname);
336          if (!e.domainname)          if (!e.domainname)
337                  goto out;                  goto out;
338          if (!is_delete)          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
339                  entry = kmalloc(sizeof(e), GFP_KERNEL);                                    CCS_ID_DOMAIN_KEEPER,
340          mutex_lock(&ccs_policy_lock);                                    ccs_same_domain_keeper_entry);
         list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {  
                 if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),  
                                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_domain_keeper_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
341   out:   out:
342          ccs_put_name(e.domainname);          ccs_put_name(e.domainname);
343          ccs_put_name(e.program);          ccs_put_name(e.program);
         kfree(entry);  
344          return error;          return error;
345  }  }
346    
347  /**  /**
348   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.   * ccs_write_domain_keeper - Write "struct ccs_domain_keeper" list.
349   *   *
350   * @data:      String to parse.   * @data:      String to parse.
  * @is_not:    True if it is "no_keep_domain" entry.  
351   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
352   *   *
353     * Returns 0 on success, negative value otherwise.
354   */   */
355  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 ccs_read_lock().  
  */  
 bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)  
356  {  {
357          struct list_head *pos;          char *domainname = strstr(data, " from ");
358          bool done = true;          if (domainname) {
359          list_for_each_cookie(pos, head->read_var2,                  *domainname = '\0';
360                               &ccs_domain_keeper_list) {                  domainname += 6;
361                  struct ccs_domain_keeper_entry *ptr;          } else {
362                  const char *no;                  domainname = data;
363                  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" CCS_KEYWORD_KEEP_DOMAIN  
                                      "%s%s%s\n", no, program, from,  
                                      ptr->domainname->name);  
                 if (!done)  
                         break;  
364          }          }
365          return done;          return ccs_update_domain_keeper_entry(domainname, data, flags,
366                                                  is_delete);
367  }  }
368    
369  /**  /**
370   * 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.
371   *   *
372   * @domainname: The name of domain.   * @domainname: The name of domain.
373   * @program:    The name of program.   * @program:    The name of program.
# Line 360  bool ccs_read_domain_keeper_policy(struc Line 378  bool ccs_read_domain_keeper_policy(struc
378   *   *
379   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
380   */   */
381  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static bool ccs_domain_keeper(const struct ccs_path_info *domainname,
382                                   const struct ccs_path_info *program,                                   const struct ccs_path_info *program,
383                                   const struct ccs_path_info *last_name)                                   const struct ccs_path_info *last_name)
384  {  {
385          struct ccs_domain_keeper_entry *ptr;          struct ccs_domain_keeper *ptr;
386          bool flag = false;          bool flag = false;
387          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {          list_for_each_entry_rcu(ptr, &ccs_policy_list[CCS_ID_DOMAIN_KEEPER],
388                  if (ptr->is_deleted)                                  head.list) {
389                    if (ptr->head.is_deleted)
390                          continue;                          continue;
391                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
392                          if (ptr->domainname != domainname)                          if (ptr->domainname != domainname)
# Line 387  static bool ccs_is_domain_keeper(const s Line 406  static bool ccs_is_domain_keeper(const s
406          return flag;          return flag;
407  }  }
408    
409  /* The list for "struct ccs_aggregator_entry". */  static bool ccs_same_aggregator_entry(const struct ccs_acl_head *a,
410  LIST_HEAD(ccs_aggregator_list);                                        const struct ccs_acl_head *b)
411    {
412            const struct ccs_aggregator *p1 = container_of(a, typeof(*p1), head);
413            const struct ccs_aggregator *p2 = container_of(b, typeof(*p2), head);
414            return p1->original_name == p2->original_name &&
415                    p1->aggregated_name == p2->aggregated_name;
416    }
417    
418  /**  /**
419   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator" list.
420   *   *
421   * @original_name:   The original program's name.   * @original_name:   The original program's name.
422   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 403  static int ccs_update_aggregator_entry(c Line 428  static int ccs_update_aggregator_entry(c
428                                         const char *aggregated_name,                                         const char *aggregated_name,
429                                         const bool is_delete)                                         const bool is_delete)
430  {  {
431          struct ccs_aggregator_entry *entry = NULL;          struct ccs_aggregator e = { };
         struct ccs_aggregator_entry *ptr;  
         struct ccs_aggregator_entry e = { };  
432          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
433          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||          if (!ccs_correct_path(original_name, 1, 0, -1) ||
434              !ccs_is_correct_path(aggregated_name, 1, -1, -1))              !ccs_correct_path(aggregated_name, 1, -1, -1))
435                  return -EINVAL;                  return -EINVAL;
436          e.original_name = ccs_get_name(original_name);          e.original_name = ccs_get_name(original_name);
437          e.aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
438          if (!e.original_name || !e.aggregated_name)          if (!e.original_name || !e.aggregated_name)
439                  goto out;                  goto out;
440          if (!is_delete)          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
441                  entry = kmalloc(sizeof(e), GFP_KERNEL);                                    CCS_ID_AGGREGATOR,
442          mutex_lock(&ccs_policy_lock);                                    ccs_same_aggregator_entry);
         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);  
443   out:   out:
444          ccs_put_name(e.original_name);          ccs_put_name(e.original_name);
445          ccs_put_name(e.aggregated_name);          ccs_put_name(e.aggregated_name);
         kfree(entry);  
446          return error;          return error;
447  }  }
448    
449  /**  /**
450   * 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.  
451   *   *
452   * @data:      String to parse.   * @data:      String to parse.
453   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
454   *   *
455   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
456   */   */
457  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator(char *data, const bool is_delete, const u8 flags)
458  {  {
459          char *w[2];          char *w[2];
460          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 477  int ccs_delete_domain(char *domainname)
477          struct ccs_path_info name;          struct ccs_path_info name;
478          name.name = domainname;          name.name = domainname;
479          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
480          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
481                    return 0;
482          /* Is there an active domain? */          /* Is there an active domain? */
483          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
484                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
# Line 513  int ccs_delete_domain(char *domainname) Line 495  int ccs_delete_domain(char *domainname)
495  }  }
496    
497  /**  /**
498   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_assign_domain - Create a domain.
499   *   *
500   * @domainname: The name of domain.   * @domainname: The name of domain.
501   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
502   *   *
503   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
504   */   */
505  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_assign_domain(const char *domainname,
506                                                        const u8 profile)                                            const u8 profile)
507  {  {
508          struct ccs_domain_info *entry;          struct ccs_domain_info e = { };
509          struct ccs_domain_info *domain;          struct ccs_domain_info *entry = NULL;
         const struct ccs_path_info *saved_domainname;  
510          bool found = false;          bool found = false;
511    
512          if (!ccs_is_correct_domain(domainname))          if (!ccs_correct_domain(domainname))
513                  return NULL;                  return NULL;
514          saved_domainname = ccs_get_name(domainname);          e.profile = profile;
515          if (!saved_domainname)          e.domainname = ccs_get_name(domainname);
516            if (!e.domainname)
517                  return NULL;                  return NULL;
518          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          if (mutex_lock_interruptible(&ccs_policy_lock))
519          mutex_lock(&ccs_policy_lock);                  goto out;
520          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(entry, &ccs_domain_list, list) {
521                  if (domain->is_deleted ||                  if (entry->is_deleted ||
522                      ccs_pathcmp(saved_domainname, domain->domainname))                      ccs_pathcmp(e.domainname, entry->domainname))
523                          continue;                          continue;
524                  found = true;                  found = true;
525                  break;                  break;
526          }          }
527          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {          if (!found) {
528                  INIT_LIST_HEAD(&entry->acl_info_list);                  entry = ccs_commit_ok(&e, sizeof(e));
529                  entry->domainname = saved_domainname;                  if (entry) {
530                  saved_domainname = NULL;                          INIT_LIST_HEAD(&entry->acl_info_list);
531                  entry->profile = profile;                          list_add_tail_rcu(&entry->list, &ccs_domain_list);
532                  list_add_tail_rcu(&entry->list, &ccs_domain_list);                          found = true;
533                  domain = entry;                  }
                 entry = NULL;  
                 found = true;  
534          }          }
535          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
536          ccs_put_name(saved_domainname);   out:
537          kfree(entry);          ccs_put_name(e.domainname);
538          return found ? domain : NULL;          return found ? entry : NULL;
539  }  }
540    
541  /**  /**
542   * ccs_find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
543   *   *
544   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
545   *   *
546   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
547   *   *
548   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
549   */   */
550  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve *ee)
551  {  {
552          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
553          const struct ccs_path_info *handler = ee->handler;          const struct ccs_path_info *handler = ee->handler;
554          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
555          const char *old_domain_name = r->domain->domainname->name;          struct ccs_domain_info * const old_domain = ccs_current_domain();
556            const char *old_domain_name = old_domain->domainname->name;
557          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
558          const u32 ccs_flags = current->ccs_flags;          struct task_struct *task = current;
559            const u32 ccs_flags = task->ccs_flags;
560          struct ccs_path_info rn = { }; /* real name */          struct ccs_path_info rn = { }; /* real name */
561          struct ccs_path_info ln; /* last name */          struct ccs_path_info ln; /* last name */
562          int retval;          int retval;
563          bool need_kfree = false;          bool need_kfree = false;
564            bool domain_created = false;
565          ln.name = ccs_last_word(old_domain_name);          ln.name = ccs_last_word(old_domain_name);
566          ccs_fill_path_info(&ln);          ccs_fill_path_info(&ln);
567   retry:   retry:
# Line 607  static int ccs_find_next_domain(struct c Line 590  static int ccs_find_next_domain(struct c
590                          goto out;                          goto out;
591                  }                  }
592          } else {          } else {
593                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator *ptr;
594                  /* Check 'aggregator' directive. */                  /* Check 'aggregator' directive. */
595                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {                  list_for_each_entry_rcu(ptr,
596                          if (ptr->is_deleted ||                                          &ccs_policy_list[CCS_ID_AGGREGATOR],
597                                            head.list) {
598                            if (ptr->head.is_deleted ||
599                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
600                                  continue;                                  continue;
601                          kfree(rn.name);                          kfree(rn.name);
# Line 622  static int ccs_find_next_domain(struct c Line 607  static int ccs_find_next_domain(struct c
607    
608                  /* Check execute permission. */                  /* Check execute permission. */
609                  retval = ccs_exec_perm(r, &rn);                  retval = ccs_exec_perm(r, &rn);
610                  if (retval == 1)                  if (retval == CCS_RETRY_REQUEST)
611                          goto retry;                          goto retry;
612                  if (retval < 0)                  if (retval < 0)
613                          goto out;                          goto out;
614          }          }
615    
616          /* Calculate domain to transit to. */          /* Calculate domain to transit to. */
617          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {          if (ccs_domain_initializer(old_domain->domainname, &rn, &ln)) {
618                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
619                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
620                           rn.name);                           rn.name);
621          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {          } else if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
622                  /*                  /*
623                   * Needn't to transit from kernel domain before starting                   * Needn't to transit from kernel domain before starting
624                   * /sbin/init. But transit from kernel domain if executing                   * /sbin/init. But transit from kernel domain if executing
625                   * initializers because they might start before /sbin/init.                   * initializers because they might start before /sbin/init.
626                   */                   */
627                  domain = r->domain;                  domain = old_domain;
628          } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {          } else if (ccs_domain_keeper(old_domain->domainname, &rn, &ln)) {
629                  /* Keep current domain. */                  /* Keep current domain. */
630                  domain = r->domain;                  domain = old_domain;
631          } else {          } else {
632                  /* Normal domain transition. */                  /* Normal domain transition. */
633                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
# Line 653  static int ccs_find_next_domain(struct c Line 638  static int ccs_find_next_domain(struct c
638          domain = ccs_find_domain(ee->tmp);          domain = ccs_find_domain(ee->tmp);
639          if (domain)          if (domain)
640                  goto done;                  goto done;
641          if (r->mode == CCS_MAC_MODE_ENFORCING) {          if (r->mode == CCS_CONFIG_ENFORCING) {
642                  int error = ccs_supervisor(r, "# wants to create domain\n"                  int error = ccs_supervisor(r, "# wants to create domain\n"
643                                             "%s\n", ee->tmp);                                             "%s\n", ee->tmp);
644                  if (error == 1)                  if (error == CCS_RETRY_REQUEST)
645                          goto retry;                          goto retry;
646                  if (error < 0)                  if (error < 0)
647                          goto done;                          goto done;
648          }          }
649          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);          domain = ccs_assign_domain(ee->tmp, r->profile);
650          if (domain)          if (domain)
651                  ccs_audit_domain_creation_log(r->domain);                  domain_created = true;
652   done:   done:
653          if (!domain) {          if (!domain) {
654                  printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
655                         ee->tmp);                  if (!old_domain->domain_transition_failed) {
656                  if (r->mode == CCS_MAC_MODE_ENFORCING)                          old_domain->domain_transition_failed = true;
657                          retval = -EPERM;                          ccs_write_log(false, r, CCS_KEYWORD_TRANSITION_FAILED
658                  else {                                        "\n");
659                          retval = 0;                          printk(KERN_WARNING
660                          r->domain->domain_transition_failed = true;                                 "ERROR: Domain '%s' not defined.\n", ee->tmp);
661                  }                  }
662          } else {          } else {
663                  retval = 0;                  retval = 0;
664          }          }
665   out:          if (!retval && handler)
666                    ccs_audit_execute_handler_log(ee);
667            /*
668             * Tell GC that I started execve().
669             * Also, tell open_exec() to check read permission.
670             */
671            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
672            /*
673             * Make task->ccs_flags visible to GC before changing
674             * task->ccs_domain_info .
675             */
676            smp_mb();
677            /*
678             * Proceed to the next domain in order to allow reaching via PID.
679             * It will be reverted if execve() failed. Reverting is not good.
680             * But it is better than being unable to reach via PID in interactive
681             * enforcing mode.
682             */
683          if (domain)          if (domain)
684                  r->domain = domain;                  task->ccs_domain_info = domain;
685            if (domain_created)
686                    ccs_audit_domain_creation_log();
687     out:
688          if (need_kfree)          if (need_kfree)
689                  kfree(rn.name);                  kfree(rn.name);
690          return retval;          return retval;
# Line 688  static int ccs_find_next_domain(struct c Line 693  static int ccs_find_next_domain(struct c
693  /**  /**
694   * ccs_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
695   *   *
696   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
697   *   *
698   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
699   */   */
700  static int ccs_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve *ee)
701  {  {
702          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
703          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
704          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
705            struct ccs_page_dump env_page = { };
706            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
707          int arg_len = 0;          int arg_len = 0;
708          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
709          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 704  static int ccs_environ(struct ccs_execve Line 711  static int ccs_environ(struct ccs_execve
711          int envp_count = bprm->envc;          int envp_count = bprm->envc;
712          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
713          int error = -ENOMEM;          int error = -ENOMEM;
714            ee->r.type = CCS_MAC_ENVIRON;
715            ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
716                                      CCS_MAC_ENVIRON);
717          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
718                  return 0;                  return 0;
719            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
720            if (!arg_ptr)
721                    goto out;
722          while (error == -ENOMEM) {          while (error == -ENOMEM) {
723                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
724                          goto out;                          goto out;
725                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
726                  /* Read. */                  /* Read. */
727                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
728                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
729                                  argv_count--;                                  argv_count--;
730                  }                  }
731                  if (argv_count) {                  if (argv_count) {
# Line 721  static int ccs_environ(struct ccs_execve Line 733  static int ccs_environ(struct ccs_execve
733                          continue;                          continue;
734                  }                  }
735                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
736                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
                         const unsigned char c = kaddr[offset++];  
737                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
738                                  if (c == '=') {                                  if (c == '=') {
739                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
# Line 758  static int ccs_environ(struct ccs_execve Line 769  static int ccs_environ(struct ccs_execve
769   out:   out:
770          if (r->mode != 3)          if (r->mode != 3)
771                  error = 0;                  error = 0;
772            kfree(env_page.data);
773            kfree(arg_ptr);
774          return error;          return error;
775  }  }
776    
# Line 808  static void ccs_unescape(unsigned char * Line 821  static void ccs_unescape(unsigned char *
821   *   *
822   * Returns number of directories to strip.   * Returns number of directories to strip.
823   */   */
824  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
825  {  {
826          int depth = 0;          int depth = 0;
827          ccs_realpath_lock();          ccs_realpath_lock();
# Line 862  static int ccs_get_root_depth(void) Line 875  static int ccs_get_root_depth(void)
875          return depth;          return depth;
876  }  }
877    
 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)  
 {  
         if (!ee)  
                 return;  
         spin_lock(&ccs_execve_list_lock);  
         list_del(&ee->list);  
         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);  
 }  
   
878  /**  /**
879   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
880   *   *
881   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
882   *   *
883   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
884   */   */
885  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)  static int ccs_try_alt_exec(struct ccs_execve *ee)
886  {  {
887          /*          /*
888           * Contents of modified bprm.           * Contents of modified bprm.
# Line 982  static int ccs_try_alt_exec(struct ccs_e Line 928  static int ccs_try_alt_exec(struct ccs_e
928          struct task_struct *task = current;          struct task_struct *task = current;
929    
930          /* Close the requested program's dentry. */          /* Close the requested program's dentry. */
931            ee->obj.path1.dentry = NULL;
932            ee->obj.path1.mnt = NULL;
933            ee->obj.validate_done = false;
934          allow_write_access(bprm->file);          allow_write_access(bprm->file);
935          fput(bprm->file);          fput(bprm->file);
936          bprm->file = NULL;          bprm->file = NULL;
# Line 1029  static int ccs_try_alt_exec(struct ccs_e Line 978  static int ccs_try_alt_exec(struct ccs_e
978                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
979                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
980                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
981                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           (pid_t) ccsecurity_exports.sys_getpid(),
982                           current_euid(), current_egid(), current_suid(),                           current_uid(), current_gid(), current_euid(),
983                           current_sgid(), current_fsuid(), current_fsgid(),                           current_egid(), current_suid(), current_sgid(),
984                             current_fsuid(), current_fsgid(),
985                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
986                           (u8) (ccs_flags >> 8));                           (u8) (ccs_flags >> 8));
987                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
# Line 1071  static int ccs_try_alt_exec(struct ccs_e Line 1021  static int ccs_try_alt_exec(struct ccs_e
1021          {          {
1022                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
1023                  int len = ee->handler->total_len + 1;                  int len = ee->handler->total_len + 1;
1024                  char *cp = kmalloc(len, GFP_KERNEL);                  char *cp = kmalloc(len, CCS_GFP_FLAGS);
1025                  if (!cp) {                  if (!cp) {
1026                          retval = ENOMEM;                          retval = -ENOMEM;
1027                          goto out;                          goto out;
1028                  }                  }
1029                  ee->handler_path = cp;                  ee->handler_path = cp;
# Line 1102  static int ccs_try_alt_exec(struct ccs_e Line 1052  static int ccs_try_alt_exec(struct ccs_e
1052  #endif  #endif
1053  #endif  #endif
1054    
1055          /* OK, now restart the process with execute handler program's dentry. */          /*
1056             * OK, now restart the process with execute handler program's dentry.
1057             */
1058          filp = open_exec(ee->handler_path);          filp = open_exec(ee->handler_path);
1059          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1060                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
1061                  goto out;                  goto out;
1062          }          }
1063            ee->obj.path1.dentry = filp->f_dentry;
1064            ee->obj.path1.mnt = filp->f_vfsmnt;
1065          bprm->file = filp;          bprm->file = filp;
1066          bprm->filename = ee->handler_path;          bprm->filename = ee->handler_path;
1067  #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 1080  static int ccs_try_alt_exec(struct ccs_e
1080  /**  /**
1081   * ccs_find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1082   *   *
1083   * @ee:   Pointer to "struct ccs_execve_entry".   * @ee:   Pointer to "struct ccs_execve".
1084   * @type: Type of execute handler.   * @type: Type of execute handler.
1085   *   *
1086   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1087   *   *
1088   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1089   */   */
1090  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)  
1091  {  {
1092          struct task_struct *task = current;          struct task_struct *task = current;
1093          const struct ccs_domain_info *domain = ccs_current_domain();          const struct ccs_domain_info * const domain = ccs_current_domain();
1094          struct ccs_acl_info *ptr;          struct ccs_acl_info *ptr;
1095          bool found = false;          bool found = false;
1096          /*          /*
# Line 1146  static bool ccs_find_execute_handler(str Line 1099  static bool ccs_find_execute_handler(str
1099           */           */
1100          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1101                  return false;                  return false;
1102          list_for_each_entry(ptr, &domain->acl_info_list, list) {          list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1103                  struct ccs_execute_handler_record *acl;                  struct ccs_execute_handler *acl;
1104                  if (ptr->type != type)                  if (ptr->type != type)
1105                          continue;                          continue;
1106                  acl = container_of(ptr, struct ccs_execute_handler_record,                  acl = container_of(ptr, struct ccs_execute_handler, head);
                                    head);  
1107                  ee->handler = acl->handler;                  ee->handler = acl->handler;
1108                    ee->handler_type = type;
1109                  found = true;                  found = true;
1110                  break;                  break;
1111          }          }
# Line 1172  bool ccs_dump_page(struct linux_binprm * Line 1125  bool ccs_dump_page(struct linux_binprm *
1125                     struct ccs_page_dump *dump)                     struct ccs_page_dump *dump)
1126  {  {
1127          struct page *page;          struct page *page;
1128          /* dump->data is released by ccs_free_execve_entry(). */          /* dump->data is released by ccs_finish_execve(). */
1129          if (!dump->data) {          if (!dump->data) {
1130                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1131                  if (!dump->data)                  if (!dump->data)
1132                          return false;                          return false;
1133          }          }
# Line 1182  bool ccs_dump_page(struct linux_binprm * Line 1135  bool ccs_dump_page(struct linux_binprm *
1135  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1136          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)
1137                  return false;                  return false;
1138  #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)
1139            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1140                    return false;
1141    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1142          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)
1143                  return false;                  return false;
1144  #else  #else
# Line 1197  bool ccs_dump_page(struct linux_binprm * Line 1153  bool ccs_dump_page(struct linux_binprm *
1153                   */                   */
1154                  char *kaddr = kmap_atomic(page, KM_USER0);                  char *kaddr = kmap_atomic(page, KM_USER0);
1155                  dump->page = page;                  dump->page = page;
1156                  memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);                  memcpy(dump->data + offset, kaddr + offset,
1157                           PAGE_SIZE - offset);
1158                  kunmap_atomic(kaddr, KM_USER0);                  kunmap_atomic(kaddr, KM_USER0);
1159          }          }
1160          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1161  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1162          put_page(page);          put_page(page);
1163  #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)
1164            put_page(page);
1165    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)
1166          put_page(page);          put_page(page);
1167  #endif  #endif
1168          return true;          return true;
1169  }  }
1170    
1171  /**  /**
  * 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;  
 }  
   
 /**  
1172   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1173   *   *
1174   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1175     * @eep:  Pointer to "struct ccs_execve *".
1176   *   *
1177   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1178   */   */
1179  int ccs_start_execve(struct linux_binprm *bprm)  static int ccs_start_execve(struct linux_binprm *bprm,
1180                                struct ccs_execve **eep)
1181  {  {
1182          int retval;          int retval;
1183          struct task_struct *task = current;          struct task_struct *task = current;
1184          struct ccs_execve_entry *ee = ccs_allocate_execve_entry();          struct ccs_execve *ee;
1185          if (!ccs_policy_loaded)          *eep = NULL;
1186                  ccs_load_policy(bprm->filename);          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
1187          if (!ee)          if (!ee)
1188                  return -ENOMEM;                  return -ENOMEM;
1189          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1190            if (!ee->tmp) {
1191                    kfree(ee);
1192                    return -ENOMEM;
1193            }
1194            ee->reader_idx = ccs_read_lock();
1195            /* ee->dump->data is allocated by ccs_dump_page(). */
1196            ee->previous_domain = task->ccs_domain_info;
1197            /* Clear manager flag. */
1198            task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
1199            *eep = ee;
1200            ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1201          ee->r.ee = ee;          ee->r.ee = ee;
1202          ee->bprm = bprm;          ee->bprm = bprm;
1203          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1204          ee->obj.path1.dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1205          ee->obj.path1.mnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1206          /* Clear manager flag. */          /*
1207          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;           * No need to call ccs_environ() for execute handler because envp[] is
1208          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {           * moved to argv[].
1209                  retval = ccs_try_alt_exec(ee);           */
1210                  if (!retval)          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER))
1211                          ccs_audit_execute_handler_log(ee, true);                  return ccs_try_alt_exec(ee);
                 goto ok;  
         }  
1212          retval = ccs_find_next_domain(ee);          retval = ccs_find_next_domain(ee);
1213          if (retval != -EPERM)          if (retval == -EPERM) {
1214                  goto ok;                  if (ccs_find_execute_handler(ee,
1215          if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {                                               CCS_TYPE_DENIED_EXECUTE_HANDLER))
1216                  retval = ccs_try_alt_exec(ee);                          return ccs_try_alt_exec(ee);
                 if (!retval)  
                         ccs_audit_execute_handler_log(ee, false);  
1217          }          }
1218   ok:          if (!retval)
1219          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);  
1220          return retval;          return retval;
1221  }  }
1222    
# Line 1283  int ccs_start_execve(struct linux_binprm Line 1224  int ccs_start_execve(struct linux_binprm
1224   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1225   *   *
1226   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1227     * @ee:     Pointer to "struct ccs_execve".
1228   *   *
1229   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1230   */   */
1231  void ccs_finish_execve(int retval)  static void ccs_finish_execve(int retval, struct ccs_execve *ee)
1232  {  {
1233          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;  
1234          if (!ee)          if (!ee)
1235                  return;                  return;
1236          if (retval < 0)          if (retval < 0) {
1237                  goto out;                  task->ccs_domain_info = ee->previous_domain;
1238          /* Proceed to next domain if execution suceeded. */                  /*
1239          task->ccs_domain_info = ee->r.domain;                   * Make task->ccs_domain_info visible to GC before changing
1240          /* Mark the current process as execute handler. */                   * task->ccs_flags .
1241          if (ee->handler)                   */
1242                  task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;                  smp_mb();
1243          /* Mark the current process as normal process. */          } else {
1244          else                  /* Mark the current process as execute handler. */
1245                  task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;                  if (ee->handler)
1246   out:                          task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1247          ccs_free_execve_entry(ee);                  /* Mark the current process as normal process. */
1248                    else
1249                            task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1250            }
1251            /* Tell GC that I finished execve(). */
1252            task->ccs_flags &= ~CCS_TASK_IS_IN_EXECVE;
1253            ccs_read_unlock(ee->reader_idx);
1254            kfree(ee->handler_path);
1255            kfree(ee->tmp);
1256            kfree(ee->dump.data);
1257            kfree(ee);
1258    }
1259    
1260    /**
1261     * ccs_may_transit - Check permission and do domain transition without execve().
1262     *
1263     * @domainname: Domainname to transit to.
1264     * @pathname: Pathname to check.
1265     *
1266     * Returns 0 on success, negative value otherwise.
1267     *
1268     * Caller holds ccs_read_lock().
1269     */
1270    int ccs_may_transit(const char *domainname, const char *pathname)
1271    {
1272            struct ccs_path_info name;
1273            struct ccs_request_info r;
1274            struct ccs_domain_info *domain;
1275            int error;
1276            bool domain_created = false;
1277            name.name = pathname;
1278            ccs_fill_path_info(&name);
1279            /* Check allow_transit permission. */
1280            ccs_init_request_info(&r, CCS_MAC_FILE_TRANSIT);
1281            error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1282            if (error)
1283                    return error;
1284            /* Check destination domain. */
1285            domain = ccs_find_domain(domainname);
1286            if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1287                strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1288                    domain = ccs_assign_domain(domainname, r.profile);
1289                    if (domain)
1290                            domain_created = true;
1291            }
1292            if (domain) {
1293                    error = 0;
1294                    current->ccs_domain_info = domain;
1295                    if (domain_created)
1296                            ccs_audit_domain_creation_log();
1297            } else {
1298                    error = -ENOENT;
1299            }
1300            return error;
1301    }
1302    
1303    static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1304                                           struct pt_regs *regs)
1305    {
1306            struct ccs_execve *ee;
1307            int retval;
1308            if (!ccs_policy_loaded)
1309                    ccsecurity_exports.load_policy(bprm->filename);
1310            retval = ccs_start_execve(bprm, &ee);
1311            if (!retval)
1312                    retval = search_binary_handler(bprm, regs);
1313            ccs_finish_execve(retval, ee);
1314            return retval;
1315    }
1316    
1317    void __init ccs_domain_init(void)
1318    {
1319            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1320  }  }

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

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