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

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 3064 by kumaneko, Fri Sep 25 08:55:35 2009 UTC branches/ccs-patch/security/ccsecurity/domain.c revision 3752 by kumaneko, Fri Jun 11 05:46:17 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   2009/09/06   * Version: 1.7.2+   2010/06/04
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 24  Line 24 
24    
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",          r->granted = true;
54                                     is_default ? CCS_KEYWORD_EXECUTE_HANDLER :          return ccs_write_log(r, "%s %s\n", ee->handler_type ==
55                                     CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);                               CCS_TYPE_DENIED_EXECUTE_HANDLER ?
56                                 CCS_KEYWORD_DENIED_EXECUTE_HANDLER :
57                                 CCS_KEYWORD_EXECUTE_HANDLER, handler);
58  }  }
59    
60  /**  /**
61   * ccs_audit_domain_creation_log - Audit domain creation log.   * ccs_audit_domain_creation_log - Audit domain creation log.
62   *   *
  * @domain:  Pointer to "struct ccs_domain_info".  
  *  
63   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
64   */   */
65  static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)  static int ccs_audit_domain_creation_log(void)
66  {  {
         int error;  
67          struct ccs_request_info r;          struct ccs_request_info r;
68          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);          ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE);
69          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);          r.granted = false;
70          return error;          return ccs_write_log(&r, "use_profile %u\n", r.profile);
71  }  }
72    
73  /* The list for "struct ccs_domain_initializer_entry". */  int ccs_update_policy(struct ccs_acl_head *new_entry, const int size,
74  LIST_HEAD(ccs_domain_initializer_list);                        bool is_delete, const int idx, bool (*check_duplicate)
75                          (const struct ccs_acl_head *,
76  /**                         const struct ccs_acl_head *))
  * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.  
  *  
  * @domainname: The name of domain. May be NULL.  
  * @program:    The name of program.  
  * @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.  
  */  
 static int ccs_update_domain_initializer_entry(const char *domainname,  
                                                const char *program,  
                                                const bool is_not,  
                                                const bool is_delete)  
77  {  {
         struct ccs_domain_initializer_entry *entry = NULL;  
         struct ccs_domain_initializer_entry *ptr;  
         struct ccs_domain_initializer_entry e = { .is_not = is_not };  
78          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
79          if (!ccs_is_correct_path(program, 1, -1, -1))          struct ccs_acl_head *entry;
80                  return -EINVAL; /* No patterns allowed. */          if (mutex_lock_interruptible(&ccs_policy_lock))
81          if (domainname) {                  return -ENOMEM;
82                  if (!ccs_is_domain_def(domainname) &&          list_for_each_entry_rcu(entry, &ccs_policy_list[idx], list) {
83                      ccs_is_correct_path(domainname, 1, -1, -1))                  if (!check_duplicate(entry, new_entry))
                         e.is_last_name = true;  
                 else if (!ccs_is_correct_domain(domainname))  
                         return -EINVAL;  
                 e.domainname = ccs_get_name(domainname);  
                 if (!e.domainname)  
                         goto out;  
         }  
         e.program = ccs_get_name(program);  
         if (!e.program)  
                 goto out;  
         if (!is_delete)  
                 entry = kmalloc(sizeof(e), GFP_KERNEL);  
         mutex_lock(&ccs_policy_lock);  
         list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {  
                 if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),  
                                sizeof(e)))  
84                          continue;                          continue;
85                  ptr->is_deleted = is_delete;                  entry->is_deleted = is_delete;
86                  error = 0;                  error = 0;
87                  break;                  break;
88          }          }
89          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {          if (error && !is_delete) {
90                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);                  entry = ccs_commit_ok(new_entry, size);
91                  entry = NULL;                  if (entry) {
92                  error = 0;                          list_add_tail_rcu(&entry->list, &ccs_policy_list[idx]);
93                            error = 0;
94                    }
95          }          }
96          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
  out:  
         ccs_put_name(e.domainname);  
         ccs_put_name(e.program);  
         kfree(entry);  
97          return error;          return error;
98  }  }
99    
100  /**  int ccs_update_group(struct ccs_acl_head *new_entry, const int size,
101   * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.                       bool is_delete, struct ccs_group *group,
102   *                       bool (*check_duplicate) (const struct ccs_acl_head *,
103   * @head: Pointer to "struct ccs_io_buffer".                                                const struct ccs_acl_head *))
  *  
  * Returns true on success, false otherwise.  
  *  
  * Caller holds ccs_read_lock().  
  */  
 bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)  
104  {  {
105          struct list_head *pos;          int error = is_delete ? -ENOENT : -ENOMEM;
106          bool done = true;          struct ccs_acl_head *entry;
107          list_for_each_cookie(pos, head->read_var2,          if (mutex_lock_interruptible(&ccs_policy_lock))
108                               &ccs_domain_initializer_list) {                  return -ENOMEM;
109                  const char *no;          list_for_each_entry_rcu(entry, &group->member_list, list) {
110                  const char *from = "";                  if (!check_duplicate(entry, new_entry))
                 const char *domain = "";  
                 struct ccs_domain_initializer_entry *ptr;  
                 ptr = list_entry(pos, struct ccs_domain_initializer_entry,  
                                  list);  
                 if (ptr->is_deleted)  
111                          continue;                          continue;
112                  no = ptr->is_not ? "no_" : "";                  entry->is_deleted = is_delete;
113                  if (ptr->domainname) {                  error = 0;
114                          from = " from ";                  break;
115                          domain = ptr->domainname->name;          }
116            if (!is_delete && error) {
117                    entry = ccs_commit_ok(new_entry, size);
118                    if (entry) {
119                            list_add_tail_rcu(&entry->list, &group->member_list);
120                            error = 0;
121                  }                  }
                 done = ccs_io_printf(head, "%s" CCS_KEYWORD_INITIALIZE_DOMAIN  
                                      "%s%s%s\n", no, ptr->program->name, from,  
                                      domain);  
                 if (!done)  
                         break;  
122          }          }
123          return done;          mutex_unlock(&ccs_policy_lock);
124            return error;
125  }  }
126    
127  /**  static void ccs_delete_type(struct ccs_domain_info *domain, u8 type)
  * 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)  
128  {  {
129          char *cp = strstr(data, " from ");          struct ccs_acl_info *ptr;
130          if (cp) {          list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
131                  *cp = '\0';                  if (ptr->type == type)
132                  return ccs_update_domain_initializer_entry(cp + 6, data,                          ptr->is_deleted = true;
                                                            is_not, is_delete);  
133          }          }
         return ccs_update_domain_initializer_entry(NULL, data, is_not,  
                                                    is_delete);  
134  }  }
135    
136  /**  int ccs_update_domain(struct ccs_acl_info *new_entry, const int size,
137   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.                        bool is_delete, struct ccs_domain_info *domain,
138   *                        bool (*check_duplicate) (const struct ccs_acl_info *,
139   * @domainname: The name of domain.                                                 const struct ccs_acl_info *),
140   * @program:    The name of program.                        bool (*merge_duplicate) (struct ccs_acl_info *,
141   * @last_name:  The last component of @domainname.                                                 struct ccs_acl_info *,
142   *                                                 const bool))
143   * Returns true if executing @program reinitializes domain transition,  {
144   * false otherwise.          int error = is_delete ? -ENOENT : -ENOMEM;
145   *          struct ccs_acl_info *entry;
146   * Caller holds ccs_read_lock().          /*
147   */           * Only one "execute_handler" and "denied_execute_handler" can exist
148  static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,           * in a domain.
149                                        const struct ccs_path_info *program,           */
150                                        const struct ccs_path_info *last_name)          const u8 type = new_entry->type;
151  {          const bool exclusive = !is_delete &&
152          struct ccs_domain_initializer_entry *ptr;                  (type == CCS_TYPE_EXECUTE_HANDLER ||
153          bool flag = false;                   type == CCS_TYPE_DENIED_EXECUTE_HANDLER);
154          list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {          if (mutex_lock_interruptible(&ccs_policy_lock))
155                  if (ptr->is_deleted)                  return error;
156            list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
157                    if (!check_duplicate(entry, new_entry))
158                          continue;                          continue;
159                  if (ptr->domainname) {                  if (exclusive)
160                          if (!ptr->is_last_name) {                          ccs_delete_type(domain, type);
161                                  if (ptr->domainname != domainname)                  if (merge_duplicate)
162                                          continue;                          entry->is_deleted = merge_duplicate(entry, new_entry,
163                          } else {                                                              is_delete);
164                                  if (ccs_pathcmp(ptr->domainname, last_name))                  else
165                                          continue;                          entry->is_deleted = is_delete;
166                          }                  error = 0;
167                    break;
168            }
169            if (error && !is_delete) {
170                    entry = ccs_commit_ok(new_entry, size);
171                    if (entry) {
172                            if (exclusive)
173                                    ccs_delete_type(domain, type);
174                            ccs_add_domain_acl(domain, entry);
175                            error = 0;
176                  }                  }
177                  if (ccs_pathcmp(ptr->program, program))          }
178            mutex_unlock(&ccs_policy_lock);
179            return error;
180    }
181    
182    void ccs_check_acl(struct ccs_request_info *r,
183                       bool (*check_entry) (const struct ccs_request_info *,
184                                            const struct ccs_acl_info *))
185    {
186            const struct ccs_domain_info *domain = ccs_current_domain();
187            struct ccs_acl_info *ptr;
188     retry:
189            list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
190                    if (ptr->is_deleted || ptr->type != r->param_type)
191                          continue;                          continue;
192                  if (ptr->is_not) {                  if (check_entry(r, ptr) && ccs_condition(r, ptr->cond)) {
193                          flag = false;                          r->cond = ptr->cond;
194                          break;                          r->granted = true;
195                            return;
196                  }                  }
                 flag = true;  
197          }          }
198          return flag;          if (domain != &ccs_global_domain &&
199                !domain->flags[CCS_DIF_IGNORE_GLOBAL] &&
200                (r->param_type != CCS_TYPE_PATH_ACL ||
201                 r->param.path.operation != CCS_TYPE_READ ||
202                 !domain->flags[CCS_DIF_IGNORE_GLOBAL_ALLOW_READ]) &&
203                (r->param_type != CCS_TYPE_ENV_ACL ||
204                 !domain->flags[CCS_DIF_IGNORE_GLOBAL_ALLOW_ENV])) {
205                    domain = &ccs_global_domain;
206                    goto retry;
207            }
208            r->granted = false;
209  }  }
210    
211  /* The list for "struct ccs_domain_keeper_entry". */  static bool ccs_same_transition_control_entry(const struct ccs_acl_head *a,
212  LIST_HEAD(ccs_domain_keeper_list);                                                const struct ccs_acl_head *b)
213    {
214            const struct ccs_transition_control *p1 = container_of(a, typeof(*p1),
215                                                                   head);
216            const struct ccs_transition_control *p2 = container_of(b, typeof(*p2),
217                                                                   head);
218            return p1->type == p2->type && p1->is_last_name == p2->is_last_name
219                    && p1->domainname == p2->domainname
220                    && p1->program == p2->program;
221    }
222    
223  /**  /**
224   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.   * ccs_update_transition_control_entry - Update "struct ccs_transition_control" list.
225   *   *
226   * @domainname: The name of domain.   * @domainname: The name of domain. Maybe NULL.
227   * @program:    The name of program. May be NULL.   * @program:    The name of program. Maybe NULL.
228   * @is_not:     True if it is "no_keep_domain" entry.   * @type:       Type of transition.
229   * @is_delete:  True if it is a delete request.   * @is_delete:  True if it is a delete request.
230   *   *
231   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
232   */   */
233  static int ccs_update_domain_keeper_entry(const char *domainname,  static int ccs_update_transition_control_entry(const char *domainname,
234                                            const char *program,                                                 const char *program,
235                                            const bool is_not,                                                 const u8 type,
236                                            const bool is_delete)                                                 const bool is_delete)
237  {  {
238          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 };  
239          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
240          if (!ccs_is_domain_def(domainname) &&          if (program && strcmp(program, "any")) {
241              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))  
242                          return -EINVAL;                          return -EINVAL;
243                  e.program = ccs_get_name(program);                  e.program = ccs_get_name(program);
244                  if (!e.program)                  if (!e.program)
245                          goto out;                          goto out;
246          }          }
247          e.domainname = ccs_get_name(domainname);          if (domainname && strcmp(domainname, "any")) {
248          if (!e.domainname)                  if (!ccs_correct_domain(domainname)) {
249                  goto out;                          if (!ccs_correct_path(domainname))
250          if (!is_delete)                                  goto out;
251                  entry = kmalloc(sizeof(e), GFP_KERNEL);                          e.is_last_name = true;
252          mutex_lock(&ccs_policy_lock);                  }
253          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {                  e.domainname = ccs_get_name(domainname);
254                  if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),                  if (!e.domainname)
255                                 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;  
256          }          }
257          mutex_unlock(&ccs_policy_lock);          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
258                                      CCS_ID_TRANSITION_CONTROL,
259                                      ccs_same_transition_control_entry);
260   out:   out:
261          ccs_put_name(e.domainname);          ccs_put_name(e.domainname);
262          ccs_put_name(e.program);          ccs_put_name(e.program);
         kfree(entry);  
263          return error;          return error;
264  }  }
265    
266  /**  /**
267   * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.   * ccs_write_transition_control - Write "struct ccs_transition_control" list.
268   *   *
269   * @data:      String to parse.   * @data:      String to parse.
  * @is_not:    True if it is "no_keep_domain" entry.  
270   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
271     * @type:      Type of this entry.
272   *   *
273     * Returns 0 on success, negative value otherwise.
274   */   */
275  int ccs_write_domain_keeper_policy(char *data, const bool is_not,  int ccs_write_transition_control(char *data, const bool is_delete,
276                                     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)  
277  {  {
278          struct list_head *pos;          char *domainname = strstr(data, " from ");
279          bool done = true;          if (domainname) {
280          list_for_each_cookie(pos, head->read_var2,                  *domainname = '\0';
281                               &ccs_domain_keeper_list) {                  domainname += 6;
282                  struct ccs_domain_keeper_entry *ptr;          } else if (type == CCS_TRANSITION_CONTROL_NO_KEEP ||
283                  const char *no;                     type == CCS_TRANSITION_CONTROL_KEEP) {
284                  const char *from = "";                  domainname = data;
285                  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;  
286          }          }
287          return done;          return ccs_update_transition_control_entry(domainname, data, type,
288                                                       is_delete);
289  }  }
290    
291  /**  /**
292   * ccs_is_domain_keeper - Check whether the given program causes domain transition suppression.   * ccs_transition_type - Get domain transition type.
293   *   *
294   * @domainname: The name of domain.   * @domainname: The name of domain.
295   * @program:    The name of program.   * @program:    The name of program.
  * @last_name:  The last component of @domainname.  
296   *   *
297   * Returns true if executing @program supresses domain transition,   * Returns CCS_TRANSITION_CONTROL_INITIALIZE if executing @program
298   * false otherwise.   * reinitializes domain transition, CCS_TRANSITION_CONTROL_KEEP if executing
299     * @program suppresses domain transition, others otherwise.
300   *   *
301   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
302   */   */
303  static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,  static u8 ccs_transition_type(const struct ccs_path_info *domainname,
304                                   const struct ccs_path_info *program,                                const struct ccs_path_info *program)
305                                   const struct ccs_path_info *last_name)  {
306  {          const struct ccs_transition_control *ptr;
307          struct ccs_domain_keeper_entry *ptr;          const char *last_name = ccs_last_word(domainname->name);
308          bool flag = false;          u8 type;
309          list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {          for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) {
310                  if (ptr->is_deleted)   next:
311                          continue;                  list_for_each_entry_rcu(ptr, &ccs_policy_list
312                  if (!ptr->is_last_name) {                                          [CCS_ID_TRANSITION_CONTROL],
313                          if (ptr->domainname != domainname)                                          head.list) {
314                            if (ptr->head.is_deleted || ptr->type != type)
315                                  continue;                                  continue;
316                  } else {                          if (ptr->domainname) {
317                          if (ccs_pathcmp(ptr->domainname, last_name))                                  if (!ptr->is_last_name) {
318                                            if (ptr->domainname != domainname)
319                                                    continue;
320                                    } else {
321                                            /*
322                                             * Use direct strcmp() since this is
323                                             * unlikely used.
324                                             */
325                                            if (strcmp(ptr->domainname->name,
326                                                       last_name))
327                                                    continue;
328                                    }
329                            }
330                            if (ptr->program && ccs_pathcmp(ptr->program, program))
331                                  continue;                                  continue;
332                            if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) {
333                                    /*
334                                     * Do not check for initialize_domain if
335                                     * no_initialize_domain matched.
336                                     */
337                                    type = CCS_TRANSITION_CONTROL_NO_KEEP;
338                                    goto next;
339                            }
340                            goto done;
341                  }                  }
                 if (ptr->program && ccs_pathcmp(ptr->program, program))  
                         continue;  
                 if (ptr->is_not) {  
                         flag = false;  
                         break;  
                 }  
                 flag = true;  
342          }          }
343          return flag;   done:
344            return type;
345  }  }
346    
347  /* The list for "struct ccs_aggregator_entry". */  static bool ccs_same_aggregator_entry(const struct ccs_acl_head *a,
348  LIST_HEAD(ccs_aggregator_list);                                        const struct ccs_acl_head *b)
349    {
350            const struct ccs_aggregator *p1 = container_of(a, typeof(*p1), head);
351            const struct ccs_aggregator *p2 = container_of(b, typeof(*p2), head);
352            return p1->original_name == p2->original_name &&
353                    p1->aggregated_name == p2->aggregated_name;
354    }
355    
356  /**  /**
357   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.   * ccs_update_aggregator_entry - Update "struct ccs_aggregator" list.
358   *   *
359   * @original_name:   The original program's name.   * @original_name:   The original program's name.
360   * @aggregated_name: The aggregated program's name.   * @aggregated_name: The aggregated program's name.
# Line 398  static int ccs_update_aggregator_entry(c Line 366  static int ccs_update_aggregator_entry(c
366                                         const char *aggregated_name,                                         const char *aggregated_name,
367                                         const bool is_delete)                                         const bool is_delete)
368  {  {
369          struct ccs_aggregator_entry *entry = NULL;          struct ccs_aggregator e = { };
         struct ccs_aggregator_entry *ptr;  
         struct ccs_aggregator_entry e = { };  
370          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
371          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||          if (!ccs_correct_path(original_name) ||
372              !ccs_is_correct_path(aggregated_name, 1, -1, -1))              !ccs_correct_path(aggregated_name))
373                  return -EINVAL;                  return -EINVAL;
374          e.original_name = ccs_get_name(original_name);          e.original_name = ccs_get_name(original_name);
375          e.aggregated_name = ccs_get_name(aggregated_name);          e.aggregated_name = ccs_get_name(aggregated_name);
376          if (!e.original_name || !e.aggregated_name)          if (!e.original_name || !e.aggregated_name ||
377                e.aggregated_name->is_patterned) /* No patterns allowed. */
378                  goto out;                  goto out;
379          if (!is_delete)          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
380                  entry = kmalloc(sizeof(e), GFP_KERNEL);                                    CCS_ID_AGGREGATOR,
381          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);  
382   out:   out:
383          ccs_put_name(e.original_name);          ccs_put_name(e.original_name);
384          ccs_put_name(e.aggregated_name);          ccs_put_name(e.aggregated_name);
         kfree(entry);  
385          return error;          return error;
386  }  }
387    
388  /**  /**
389   * 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.  
390   *   *
391   * @data:      String to parse.   * @data:      String to parse.
392   * @is_delete: True if it is a delete request.   * @is_delete: True if it is a delete request.
393   *   *
394   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
395   */   */
396  int ccs_write_aggregator_policy(char *data, const bool is_delete)  int ccs_write_aggregator(char *data, const bool is_delete)
397  {  {
398          char *w[2];          char *w[2];
399          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
# Line 491  int ccs_delete_domain(char *domainname) Line 416  int ccs_delete_domain(char *domainname)
416          struct ccs_path_info name;          struct ccs_path_info name;
417          name.name = domainname;          name.name = domainname;
418          ccs_fill_path_info(&name);          ccs_fill_path_info(&name);
419          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
420                    return 0;
421          /* Is there an active domain? */          /* Is there an active domain? */
422          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
423                  /* Never delete ccs_kernel_domain */                  /* Never delete ccs_kernel_domain */
# Line 508  int ccs_delete_domain(char *domainname) Line 434  int ccs_delete_domain(char *domainname)
434  }  }
435    
436  /**  /**
437   * ccs_find_or_assign_new_domain - Create a domain.   * ccs_assign_domain - Create a domain.
438   *   *
439   * @domainname: The name of domain.   * @domainname: The name of domain.
440   * @profile:    Profile number to assign if the domain was newly created.   * @profile:    Profile number to assign if the domain was newly created.
441   *   *
442   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
443   */   */
444  struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,  struct ccs_domain_info *ccs_assign_domain(const char *domainname,
445                                                        const u8 profile)                                            const u8 profile)
446  {  {
447          struct ccs_domain_info *entry;          struct ccs_domain_info e = { };
448          struct ccs_domain_info *domain;          struct ccs_domain_info *entry = NULL;
         const struct ccs_path_info *saved_domainname;  
449          bool found = false;          bool found = false;
450    
451          if (!ccs_is_correct_domain(domainname))          if (!ccs_correct_domain(domainname))
452                  return NULL;                  return NULL;
453          saved_domainname = ccs_get_name(domainname);          e.profile = profile;
454          if (!saved_domainname)          e.domainname = ccs_get_name(domainname);
455            if (!e.domainname)
456                  return NULL;                  return NULL;
457          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          if (mutex_lock_interruptible(&ccs_policy_lock))
458          mutex_lock(&ccs_policy_lock);                  goto out;
459          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          list_for_each_entry_rcu(entry, &ccs_domain_list, list) {
460                  if (domain->is_deleted ||                  if (entry->is_deleted ||
461                      ccs_pathcmp(saved_domainname, domain->domainname))                      ccs_pathcmp(e.domainname, entry->domainname))
462                          continue;                          continue;
463                  found = true;                  found = true;
464                  break;                  break;
465          }          }
466          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {          if (!found) {
467                  INIT_LIST_HEAD(&entry->acl_info_list);                  entry = ccs_commit_ok(&e, sizeof(e));
468                  entry->domainname = saved_domainname;                  if (entry) {
469                  saved_domainname = NULL;                          INIT_LIST_HEAD(&entry->acl_info_list);
470                  entry->profile = profile;                          list_add_tail_rcu(&entry->list, &ccs_domain_list);
471                  list_add_tail_rcu(&entry->list, &ccs_domain_list);                          found = true;
472                  domain = entry;                  }
                 entry = NULL;  
                 found = true;  
473          }          }
474          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
475          ccs_put_name(saved_domainname);   out:
476          kfree(entry);          ccs_put_name(e.domainname);
477          return found ? domain : NULL;          return found ? entry : NULL;
478  }  }
479    
480  /**  /**
481   * ccs_find_next_domain - Find a domain.   * ccs_find_next_domain - Find a domain.
482   *   *
483   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
484   *   *
485   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
486   *   *
487   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
488   */   */
489  static int ccs_find_next_domain(struct ccs_execve_entry *ee)  static int ccs_find_next_domain(struct ccs_execve *ee)
490  {  {
491          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
492          const struct ccs_path_info *handler = ee->handler;          const struct ccs_path_info *handler = ee->handler;
493          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
494          const char *old_domain_name = r->domain->domainname->name;          struct ccs_domain_info * const old_domain = ccs_current_domain();
495          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
496          const u32 ccs_flags = current->ccs_flags;          struct task_struct *task = current;
497            const u32 ccs_flags = task->ccs_flags;
498          struct ccs_path_info rn = { }; /* real name */          struct ccs_path_info rn = { }; /* real name */
         struct ccs_path_info ln; /* last name */  
499          int retval;          int retval;
500          bool need_kfree = false;          bool need_kfree = false;
501          ln.name = ccs_last_word(old_domain_name);          bool domain_created = false;
         ccs_fill_path_info(&ln);  
502   retry:   retry:
503          current->ccs_flags = ccs_flags;          current->ccs_flags = ccs_flags;
504          r->cond = NULL;          r->cond = NULL;
# Line 602  static int ccs_find_next_domain(struct c Line 525  static int ccs_find_next_domain(struct c
525                          goto out;                          goto out;
526                  }                  }
527          } else {          } else {
528                  struct ccs_aggregator_entry *ptr;                  struct ccs_aggregator *ptr;
529                  /* Check 'aggregator' directive. */                  /* Check 'aggregator' directive. */
530                  list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {                  list_for_each_entry_rcu(ptr,
531                          if (ptr->is_deleted ||                                          &ccs_policy_list[CCS_ID_AGGREGATOR],
532                                            head.list) {
533                            if (ptr->head.is_deleted ||
534                              !ccs_path_matches_pattern(&rn, ptr->original_name))                              !ccs_path_matches_pattern(&rn, ptr->original_name))
535                                  continue;                                  continue;
536                          kfree(rn.name);                          kfree(rn.name);
# Line 616  static int ccs_find_next_domain(struct c Line 541  static int ccs_find_next_domain(struct c
541                  }                  }
542    
543                  /* Check execute permission. */                  /* Check execute permission. */
544                  retval = ccs_exec_perm(r, &rn);                  retval = ccs_path_permission(r, CCS_TYPE_EXECUTE, &rn);
545                  if (retval == 1)                  if (retval == CCS_RETRY_REQUEST)
546                          goto retry;                          goto retry;
547                  if (retval < 0)                  if (retval < 0)
548                          goto out;                          goto out;
549          }          }
550    
551          /* Calculate domain to transit to. */          /* Calculate domain to transit to. */
552          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {          switch (ccs_transition_type(old_domain->domainname, &rn)) {
553            case CCS_TRANSITION_CONTROL_INITIALIZE:
554                  /* Transit to the child of ccs_kernel_domain domain. */                  /* Transit to the child of ccs_kernel_domain domain. */
555                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, CCS_ROOT_NAME " " "%s",
556                           rn.name);                           rn.name);
557          } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {                  break;
558                  /*          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)) {  
559                  /* Keep current domain. */                  /* Keep current domain. */
560                  domain = r->domain;                  domain = old_domain;
561          } else {                  break;
562                  /* Normal domain transition. */          default:
563                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",                  if (old_domain == &ccs_kernel_domain && !ccs_policy_loaded) {
564                           old_domain_name, rn.name);                          /*
565                             * Needn't to transit from kernel domain before
566                             * starting /sbin/init. But transit from kernel domain
567                             * if executing initializers because they might start
568                             * before /sbin/init.
569                             */
570                            domain = old_domain;
571                    } else {
572                            /* Normal domain transition. */
573                            snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
574                                     old_domain->domainname->name, rn.name);
575                    }
576                    break;
577          }          }
578          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
579                  goto done;                  goto done;
# Line 651  static int ccs_find_next_domain(struct c Line 583  static int ccs_find_next_domain(struct c
583          if (r->mode == CCS_CONFIG_ENFORCING) {          if (r->mode == CCS_CONFIG_ENFORCING) {
584                  int error = ccs_supervisor(r, "# wants to create domain\n"                  int error = ccs_supervisor(r, "# wants to create domain\n"
585                                             "%s\n", ee->tmp);                                             "%s\n", ee->tmp);
586                  if (error == 1)                  if (error == CCS_RETRY_REQUEST)
587                          goto retry;                          goto retry;
588                  if (error < 0)                  if (error < 0)
589                          goto done;                          goto done;
590          }          }
591          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);          domain = ccs_assign_domain(ee->tmp, r->profile);
592          if (domain)          if (domain)
593                  ccs_audit_domain_creation_log(r->domain);                  domain_created = true;
594   done:   done:
595          if (!domain) {          if (!domain) {
596                  printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",                  retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0;
597                         ee->tmp);                  if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) {
598                  if (r->mode == CCS_CONFIG_ENFORCING)                          old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true;
599                          retval = -EPERM;                          r->granted = false;
600                  else {                          ccs_write_log(r, CCS_KEYWORD_TRANSITION_FAILED "\n");
601                          retval = 0;                          printk(KERN_WARNING
602                          r->domain->domain_transition_failed = true;                                 "ERROR: Domain '%s' not defined.\n", ee->tmp);
603                  }                  }
604          } else {          } else {
605                  retval = 0;                  retval = 0;
606          }          }
607   out:          if (!retval && handler)
608                    ccs_audit_execute_handler_log(ee);
609            /*
610             * Tell GC that I started execve().
611             * Also, tell open_exec() to check read permission.
612             */
613            task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;
614            /*
615             * Make task->ccs_flags visible to GC before changing
616             * task->ccs_domain_info .
617             */
618            smp_mb();
619            /*
620             * Proceed to the next domain in order to allow reaching via PID.
621             * It will be reverted if execve() failed. Reverting is not good.
622             * But it is better than being unable to reach via PID in interactive
623             * enforcing mode.
624             */
625          if (domain)          if (domain)
626                  r->domain = domain;                  task->ccs_domain_info = domain;
627            if (domain_created)
628                    ccs_audit_domain_creation_log();
629     out:
630          if (need_kfree)          if (need_kfree)
631                  kfree(rn.name);                  kfree(rn.name);
632          return retval;          return retval;
# Line 683  static int ccs_find_next_domain(struct c Line 635  static int ccs_find_next_domain(struct c
635  /**  /**
636   * ccs_environ - Check permission for environment variable names.   * ccs_environ - Check permission for environment variable names.
637   *   *
638   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
639   *   *
640   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
641   */   */
642  static int ccs_environ(struct ccs_execve_entry *ee)  static int ccs_environ(struct ccs_execve *ee)
643  {  {
644          struct ccs_request_info *r = &ee->r;          struct ccs_request_info *r = &ee->r;
645          struct linux_binprm *bprm = ee->bprm;          struct linux_binprm *bprm = ee->bprm;
646          char *arg_ptr = ee->tmp;          /* env_page->data is allocated by ccs_dump_page(). */
647            struct ccs_page_dump env_page = { };
648            char *arg_ptr; /* Size is CCS_EXEC_TMPSIZE bytes */
649          int arg_len = 0;          int arg_len = 0;
650          unsigned long pos = bprm->p;          unsigned long pos = bprm->p;
651          int offset = pos % PAGE_SIZE;          int offset = pos % PAGE_SIZE;
# Line 699  static int ccs_environ(struct ccs_execve Line 653  static int ccs_environ(struct ccs_execve
653          int envp_count = bprm->envc;          int envp_count = bprm->envc;
654          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
655          int error = -ENOMEM;          int error = -ENOMEM;
656            ee->r.type = CCS_MAC_ENVIRON;
657            ee->r.mode = ccs_get_mode(ccs_current_domain()->profile,
658                                      CCS_MAC_ENVIRON);
659          if (!r->mode || !envp_count)          if (!r->mode || !envp_count)
660                  return 0;                  return 0;
661            arg_ptr = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
662            if (!arg_ptr)
663                    goto out;
664          while (error == -ENOMEM) {          while (error == -ENOMEM) {
665                  if (!ccs_dump_page(bprm, pos, &ee->dump))                  if (!ccs_dump_page(bprm, pos, &env_page))
666                          goto out;                          goto out;
667                  pos += PAGE_SIZE - offset;                  pos += PAGE_SIZE - offset;
668                  /* Read. */                  /* Read. */
669                  while (argv_count && offset < PAGE_SIZE) {                  while (argv_count && offset < PAGE_SIZE) {
670                          const char *kaddr = ee->dump.data;                          if (!env_page.data[offset++])
                         if (!kaddr[offset++])  
671                                  argv_count--;                                  argv_count--;
672                  }                  }
673                  if (argv_count) {                  if (argv_count) {
# Line 716  static int ccs_environ(struct ccs_execve Line 675  static int ccs_environ(struct ccs_execve
675                          continue;                          continue;
676                  }                  }
677                  while (offset < PAGE_SIZE) {                  while (offset < PAGE_SIZE) {
678                          const char *kaddr = ee->dump.data;                          const unsigned char c = env_page.data[offset++];
                         const unsigned char c = kaddr[offset++];  
679                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
680                                  if (c == '=') {                                  if (c == '=') {
681                                          arg_ptr[arg_len++] = '\0';                                          arg_ptr[arg_len++] = '\0';
# Line 753  static int ccs_environ(struct ccs_execve Line 711  static int ccs_environ(struct ccs_execve
711   out:   out:
712          if (r->mode != 3)          if (r->mode != 3)
713                  error = 0;                  error = 0;
714            kfree(env_page.data);
715            kfree(arg_ptr);
716          return error;          return error;
717  }  }
718    
# Line 803  static void ccs_unescape(unsigned char * Line 763  static void ccs_unescape(unsigned char *
763   *   *
764   * Returns number of directories to strip.   * Returns number of directories to strip.
765   */   */
766  static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)  static int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
767  {  {
768          int depth = 0;          int depth = 0;
769          ccs_realpath_lock();          ccs_realpath_lock();
# Line 860  static int ccs_get_root_depth(void) Line 820  static int ccs_get_root_depth(void)
820  /**  /**
821   * ccs_try_alt_exec - Try to start execute handler.   * ccs_try_alt_exec - Try to start execute handler.
822   *   *
823   * @ee: Pointer to "struct ccs_execve_entry".   * @ee: Pointer to "struct ccs_execve".
824   *   *
825   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
826   */   */
827  static int ccs_try_alt_exec(struct ccs_execve_entry *ee)  static int ccs_try_alt_exec(struct ccs_execve *ee)
828  {  {
829          /*          /*
830           * Contents of modified bprm.           * Contents of modified bprm.
# Line 960  static int ccs_try_alt_exec(struct ccs_e Line 920  static int ccs_try_alt_exec(struct ccs_e
920                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
921                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
922                           "state[1]=%u state[2]=%u",                           "state[1]=%u state[2]=%u",
923                           (pid_t) sys_getpid(), current_uid(), current_gid(),                           (pid_t) ccsecurity_exports.sys_getpid(),
924                           current_euid(), current_egid(), current_suid(),                           current_uid(), current_gid(), current_euid(),
925                           current_sgid(), current_fsuid(), current_fsgid(),                           current_egid(), current_suid(), current_sgid(),
926                             current_fsuid(), current_fsgid(),
927                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),                           (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
928                           (u8) (ccs_flags >> 8));                           (u8) (ccs_flags >> 8));
929                  retval = copy_strings_kernel(1, &cp, bprm);                  retval = copy_strings_kernel(1, &cp, bprm);
# Line 1002  static int ccs_try_alt_exec(struct ccs_e Line 963  static int ccs_try_alt_exec(struct ccs_e
963          {          {
964                  int depth = ccs_get_root_depth();                  int depth = ccs_get_root_depth();
965                  int len = ee->handler->total_len + 1;                  int len = ee->handler->total_len + 1;
966                  char *cp = kmalloc(len, GFP_KERNEL);                  char *cp = kmalloc(len, CCS_GFP_FLAGS);
967                  if (!cp) {                  if (!cp) {
968                          retval = -ENOMEM;                          retval = -ENOMEM;
969                          goto out;                          goto out;
# Line 1033  static int ccs_try_alt_exec(struct ccs_e Line 994  static int ccs_try_alt_exec(struct ccs_e
994  #endif  #endif
995  #endif  #endif
996    
997          /* OK, now restart the process with execute handler program's dentry. */          /*
998             * OK, now restart the process with execute handler program's dentry.
999             */
1000          filp = open_exec(ee->handler_path);          filp = open_exec(ee->handler_path);
1001          if (IS_ERR(filp)) {          if (IS_ERR(filp)) {
1002                  retval = PTR_ERR(filp);                  retval = PTR_ERR(filp);
# Line 1059  static int ccs_try_alt_exec(struct ccs_e Line 1022  static int ccs_try_alt_exec(struct ccs_e
1022  /**  /**
1023   * ccs_find_execute_handler - Find an execute handler.   * ccs_find_execute_handler - Find an execute handler.
1024   *   *
1025   * @ee:   Pointer to "struct ccs_execve_entry".   * @ee:   Pointer to "struct ccs_execve".
1026   * @type: Type of execute handler.   * @type: Type of execute handler.
1027   *   *
1028   * Returns true if found, false otherwise.   * Returns true if found, false otherwise.
1029   *   *
1030   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1031   */   */
1032  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)  
1033  {  {
1034          struct task_struct *task = current;          struct ccs_request_info *r = &ee->r;
1035          const struct ccs_domain_info *domain = ccs_current_domain();          const struct ccs_domain_info *domain = ccs_current_domain();
1036          struct ccs_acl_info *ptr;          struct ccs_acl_info *ptr;
         bool found = false;  
1037          /*          /*
1038           * Don't use execute handler if the current process is           * To avoid infinite execute handler loop, don't use execute handler
1039           * marked as execute handler to avoid infinite execute handler loop.           * if the current process is marked as execute handler .
1040           */           */
1041          if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)          if (current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1042                  return false;                  return false;
1043          list_for_each_entry(ptr, &domain->acl_info_list, list) {   retry:
1044                  struct ccs_execute_handler_record *acl;          list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1045                  if (ptr->type != type)                  struct ccs_execute_handler *acl;
1046                    if (ptr->type != type || !ccs_condition(r, ptr->cond))
1047                          continue;                          continue;
1048                  acl = container_of(ptr, struct ccs_execute_handler_record,                  acl = container_of(ptr, struct ccs_execute_handler, head);
                                    head);  
1049                  ee->handler = acl->handler;                  ee->handler = acl->handler;
1050                  found = true;                  ee->handler_type = type;
1051                  break;                  r->cond = ptr->cond;
1052                    return true;
1053            }
1054            if (domain != &ccs_global_domain &&
1055                !domain->flags[CCS_DIF_IGNORE_GLOBAL]) {
1056                    domain = &ccs_global_domain;
1057                    goto retry;
1058          }          }
1059          return found;          return false;
1060  }  }
1061    
1062    #ifdef CONFIG_MMU
1063    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1064    #define CCS_BPRM_MMU
1065    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR >= 3
1066    #define CCS_BPRM_MMU
1067    #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2
1068    #define CCS_BPRM_MMU
1069    #endif
1070    #endif
1071    
1072  /**  /**
1073   * ccs_dump_page - Dump a page to buffer.   * ccs_dump_page - Dump a page to buffer.
1074   *   *
# Line 1107  bool ccs_dump_page(struct linux_binprm * Line 1084  bool ccs_dump_page(struct linux_binprm *
1084          struct page *page;          struct page *page;
1085          /* dump->data is released by ccs_finish_execve(). */          /* dump->data is released by ccs_finish_execve(). */
1086          if (!dump->data) {          if (!dump->data) {
1087                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);                  dump->data = kzalloc(PAGE_SIZE, CCS_GFP_FLAGS);
1088                  if (!dump->data)                  if (!dump->data)
1089                          return false;                          return false;
1090          }          }
1091          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1092  #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)  
         if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)  
                 return false;  
 #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)  
1093          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)
1094                  return false;                  return false;
1095  #else  #else
# Line 1133  bool ccs_dump_page(struct linux_binprm * Line 1104  bool ccs_dump_page(struct linux_binprm *
1104                   */                   */
1105                  char *kaddr = kmap_atomic(page, KM_USER0);                  char *kaddr = kmap_atomic(page, KM_USER0);
1106                  dump->page = page;                  dump->page = page;
1107                  memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);                  memcpy(dump->data + offset, kaddr + offset,
1108                           PAGE_SIZE - offset);
1109                  kunmap_atomic(kaddr, KM_USER0);                  kunmap_atomic(kaddr, KM_USER0);
1110          }          }
1111          /* Same with put_arg_page(page) in fs/exec.c */          /* Same with put_arg_page(page) in fs/exec.c */
1112  #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)  
         put_page(page);  
 #elif defined(AX_MAJOR) && AX_MAJOR == 3 && defined(AX_MINOR) && AX_MINOR >= 2 && defined(CONFIG_MMU)  
1113          put_page(page);          put_page(page);
1114  #endif  #endif
1115          return true;          return true;
# Line 1151  bool ccs_dump_page(struct linux_binprm * Line 1119  bool ccs_dump_page(struct linux_binprm *
1119   * ccs_start_execve - Prepare for execve() operation.   * ccs_start_execve - Prepare for execve() operation.
1120   *   *
1121   * @bprm: Pointer to "struct linux_binprm".   * @bprm: Pointer to "struct linux_binprm".
1122   * @eep:  Pointer to "struct ccs_execve_entry *".   * @eep:  Pointer to "struct ccs_execve *".
1123   *   *
1124   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1125   */   */
1126  int ccs_start_execve(struct linux_binprm *bprm, struct ccs_execve_entry **eep)  static int ccs_start_execve(struct linux_binprm *bprm,
1127                                struct ccs_execve **eep)
1128  {  {
1129          int retval;          int retval;
1130          struct task_struct *task = current;          struct task_struct *task = current;
1131          struct ccs_execve_entry *ee;          struct ccs_execve *ee;
1132          *eep = NULL;          *eep = NULL;
1133          if (!ccs_policy_loaded)          ee = kzalloc(sizeof(*ee), CCS_GFP_FLAGS);
                 ccs_load_policy(bprm->filename);  
         ee = kzalloc(sizeof(*ee), GFP_KERNEL);  
1134          if (!ee)          if (!ee)
1135                  return -ENOMEM;                  return -ENOMEM;
1136          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);          ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, CCS_GFP_FLAGS);
1137          if (!ee->tmp) {          if (!ee->tmp) {
1138                  kfree(ee);                  kfree(ee);
1139                  return -ENOMEM;                  return -ENOMEM;
# Line 1175  int ccs_start_execve(struct linux_binprm Line 1142  int ccs_start_execve(struct linux_binprm
1142          /* ee->dump->data is allocated by ccs_dump_page(). */          /* ee->dump->data is allocated by ccs_dump_page(). */
1143          ee->previous_domain = task->ccs_domain_info;          ee->previous_domain = task->ccs_domain_info;
1144          /* Clear manager flag. */          /* Clear manager flag. */
1145          task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;          task->ccs_flags &= ~CCS_TASK_IS_MANAGER;
         /* Tell GC that I started execve(). */  
         task->ccs_flags |= CCS_TASK_IS_IN_EXECVE;  
         /*  
          * Make task->ccs_flags visible to GC before changing  
          * task->ccs_domain_info .  
          */  
         smp_mb();  
1146          *eep = ee;          *eep = ee;
1147          ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);          ccs_init_request_info(&ee->r, CCS_MAC_FILE_EXECUTE);
1148          ee->r.ee = ee;          ee->r.ee = ee;
1149          ee->bprm = bprm;          ee->bprm = bprm;
1150          ee->r.obj = &ee->obj;          ee->r.obj = &ee->obj;
1151          ee->obj.path1.dentry = bprm->file->f_dentry;          ee->obj.path1.dentry = bprm->file->f_dentry;
1152          ee->obj.path1.mnt = bprm->file->f_vfsmnt;          ee->obj.path1.mnt = bprm->file->f_vfsmnt;
         if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {  
                 retval = ccs_try_alt_exec(ee);  
                 if (!retval)  
                         ccs_audit_execute_handler_log(ee, true);  
                 goto ok;  
         }  
         retval = ccs_find_next_domain(ee);  
         if (retval != -EPERM)  
                 goto ok;  
         if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {  
                 retval = ccs_try_alt_exec(ee);  
                 if (!retval)  
                         ccs_audit_execute_handler_log(ee, false);  
         }  
  ok:  
         if (retval < 0)  
                 goto out;  
1153          /*          /*
1154           * Proceed to the next domain in order to allow reaching via PID.           * No need to call ccs_environ() for execute handler because envp[] is
1155           * It will be reverted if execve() failed. Reverting is not good.           * moved to argv[].
          * But it is better than being unable to reach via PID in interactive  
          * enforcing mode.  
1156           */           */
1157          task->ccs_domain_info = ee->r.domain;          if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER))
1158          ee->r.mode = ccs_get_mode(ee->r.domain->profile, CCS_MAC_ENVIRON);                  return ccs_try_alt_exec(ee);
1159          retval = ccs_environ(ee);          retval = ccs_find_next_domain(ee);
1160          if (retval < 0)          if (retval == -EPERM) {
1161                  goto out;                  if (ccs_find_execute_handler(ee,
1162          retval = 0;                                               CCS_TYPE_DENIED_EXECUTE_HANDLER))
1163   out:                          return ccs_try_alt_exec(ee);
1164            }
1165            if (!retval)
1166                    retval = ccs_environ(ee);
1167          return retval;          return retval;
1168  }  }
1169    
# Line 1227  int ccs_start_execve(struct linux_binprm Line 1171  int ccs_start_execve(struct linux_binprm
1171   * ccs_finish_execve - Clean up execve() operation.   * ccs_finish_execve - Clean up execve() operation.
1172   *   *
1173   * @retval: Return code of an execve() operation.   * @retval: Return code of an execve() operation.
1174   * @ee:     Pointer to "struct ccs_execve_entry".   * @ee:     Pointer to "struct ccs_execve".
1175   *   *
1176   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1177   */   */
1178  void ccs_finish_execve(int retval, struct ccs_execve_entry *ee)  static void ccs_finish_execve(int retval, struct ccs_execve *ee)
1179  {  {
1180          struct task_struct *task = current;          struct task_struct *task = current;
1181          if (!ee)          if (!ee)
# Line 1259  void ccs_finish_execve(int retval, struc Line 1203  void ccs_finish_execve(int retval, struc
1203          kfree(ee->dump.data);          kfree(ee->dump.data);
1204          kfree(ee);          kfree(ee);
1205  }  }
1206    
1207    /**
1208     * ccs_may_transit - Check permission and do domain transition without execve().
1209     *
1210     * @domainname: Domainname to transit to.
1211     * @pathname: Pathname to check.
1212     *
1213     * Returns 0 on success, negative value otherwise.
1214     *
1215     * Caller holds ccs_read_lock().
1216     */
1217    int ccs_may_transit(const char *domainname, const char *pathname)
1218    {
1219            struct ccs_path_info name;
1220            struct ccs_request_info r;
1221            struct ccs_domain_info *domain;
1222            int error;
1223            bool domain_created = false;
1224            name.name = pathname;
1225            ccs_fill_path_info(&name);
1226            /* Check allow_transit permission. */
1227            ccs_init_request_info(&r, CCS_MAC_FILE_TRANSIT);
1228            error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name);
1229            if (error)
1230                    return error;
1231            /* Check destination domain. */
1232            domain = ccs_find_domain(domainname);
1233            if (!domain && r.mode != CCS_CONFIG_ENFORCING &&
1234                strlen(domainname) < CCS_EXEC_TMPSIZE - 10) {
1235                    domain = ccs_assign_domain(domainname, r.profile);
1236                    if (domain)
1237                            domain_created = true;
1238            }
1239            if (domain) {
1240                    error = 0;
1241                    current->ccs_domain_info = domain;
1242                    if (domain_created)
1243                            ccs_audit_domain_creation_log();
1244            } else {
1245                    error = -ENOENT;
1246            }
1247            return error;
1248    }
1249    
1250    static int __ccs_search_binary_handler(struct linux_binprm *bprm,
1251                                           struct pt_regs *regs)
1252    {
1253            struct ccs_execve *ee;
1254            int retval;
1255            if (!ccs_policy_loaded)
1256                    ccsecurity_exports.load_policy(bprm->filename);
1257            retval = ccs_start_execve(bprm, &ee);
1258            if (!retval)
1259                    retval = search_binary_handler(bprm, regs);
1260            ccs_finish_execve(retval, ee);
1261            return retval;
1262    }
1263    
1264    void __init ccs_domain_init(void)
1265    {
1266            ccsecurity_ops.search_binary_handler = __ccs_search_binary_handler;
1267    }

Legend:
Removed from v.3064  
changed lines
  Added in v.3752

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