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

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

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

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