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

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.5.x/ccs-patch/fs/tomoyo_domain.c revision 502 by kumaneko, Tue Sep 25 13:33:45 2007 UTC trunk/1.7.x/ccs-patch/security/ccsecurity/domain.c revision 2975 by kumaneko, Tue Sep 1 05:34:46 2009 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/tomoyo_domain.c   * security/ccsecurity/domain.c
3   *   *
4   * Implementation of the Domain-Based Mandatory Access Control.   * Copyright (C) 2005-2009  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2007  NTT DATA CORPORATION   * Version: 1.7.0-rc   2009/09/01
  *  
  * Version: 1.5.0   2007/09/20  
7   *   *
8   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
10   *   *
11   */   */
 /***** TOMOYO Linux start. *****/  
12    
13  #include <linux/ccs_common.h>  #include <linux/slab.h>
 #include <linux/tomoyo.h>  
 #include <linux/realpath.h>  
14  #include <linux/highmem.h>  #include <linux/highmem.h>
15  #include <linux/binfmts.h>  #include <linux/version.h>
16    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17    #include <linux/namei.h>
18    #include <linux/mount.h>
19    #endif
20    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
21    #include <linux/fs_struct.h>
22    #endif
23    #include "internal.h"
24    
25    /* For compatibility with older kernels. */
26  #ifndef for_each_process  #ifndef for_each_process
27  #define for_each_process for_each_task  #define for_each_process for_each_task
28  #endif  #endif
29    
30  /*************************  VARIABLES  *************************/  /* Variables definitions.*/
31    
32  /* The initial domain. */  /* The initial domain. */
33  struct domain_info KERNEL_DOMAIN = { NULL, NULL, NULL, 0, 0, 0 };  struct ccs_domain_info ccs_kernel_domain;
   
 /* /sbin/init started? */  
 extern int sbin_init_started;  
   
 #ifdef CONFIG_TOMOYO  
   
 /* Lock for appending domain's ACL. */  
 DECLARE_MUTEX(domain_acl_lock);  
   
 /*************************  UTILITY FUNCTIONS  *************************/  
   
 /***** The structure for program files to force domain reconstruction. *****/  
   
 struct domain_initializer_entry {  
         struct domain_initializer_entry *next;  
         const struct path_info *domainname;    /* This may be NULL */  
         const struct path_info *program;  
         u8 is_deleted;  
         u8 is_not;  
         u8 is_last_name;  
 };  
   
 /***** The structure for domains to not to transit domains. *****/  
   
 struct domain_keeper_entry {  
         struct domain_keeper_entry *next;  
         const struct path_info *domainname;  
         const struct path_info *program;       /* This may be NULL */  
         u8 is_deleted;  
         u8 is_not;  
         u8 is_last_name;  
 };  
34    
35  /***** The structure for program files that should be aggregated. *****/  /* The list for "struct ccs_domain_info". */
36    LIST_HEAD(ccs_domain_list);
37    
38  struct aggregator_entry {  /**
39          struct aggregator_entry *next;   * ccs_audit_execute_handler_log - Audit execute_handler log.
40          const struct path_info *original_name;   *
41          const struct path_info *aggregated_name;   * @ee:         Pointer to "struct ccs_execve_entry".
42          int is_deleted;   * @is_default: True if it is "execute_handler" log.
43  };   *
44     * Returns 0 on success, negative value otherwise.
45  /***** The structure for program files that should be aliased. *****/   */
46    static int ccs_audit_execute_handler_log(struct ccs_execve_entry *ee,
47  struct alias_entry {                                           const bool is_default)
         struct alias_entry *next;  
         const struct path_info *original_name;  
         const struct path_info *aliased_name;  
         int is_deleted;  
 };  
   
 /*************************  VARIABLES  *************************/  
   
 /* Domain creation lock. */  
 static DECLARE_MUTEX(new_domain_assign_lock);  
   
 /*************************  UTILITY FUNCTIONS  *************************/  
   
 const char *GetLastName(const struct domain_info *domain)  
 {  
         const char *cp0 = domain->domainname->name, *cp1;  
         if ((cp1 = strrchr(cp0, ' ')) != NULL) return cp1 + 1;  
         return cp0;  
 }  
   
 int AddDomainACL(struct acl_info *ptr, struct domain_info *domain, struct acl_info *new_ptr)  
48  {  {
49          mb(); /* Instead of using spinlock. */          struct ccs_request_info *r = &ee->r;
50          if (!ptr) domain->first_acl_ptr = (struct acl_info *) new_ptr;          const char *handler = ee->handler->name;
51          else ptr->next = (struct acl_info *) new_ptr;          r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE);
52          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);          return ccs_write_audit_log(true, r, "%s %s\n",
53          return 0;                                     is_default ? CCS_KEYWORD_EXECUTE_HANDLER :
54                                       CCS_KEYWORD_DENIED_EXECUTE_HANDLER, handler);
55  }  }
56    
57  int DelDomainACL(struct acl_info *ptr)  /**
58     * ccs_audit_domain_creation_log - Audit domain creation log.
59     *
60     * @domain:  Pointer to "struct ccs_domain_info".
61     *
62     * Returns 0 on success, negative value otherwise.
63     */
64    static int ccs_audit_domain_creation_log(struct ccs_domain_info *domain)
65  {  {
66          ptr->is_deleted = 1;          int error;
67          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);          struct ccs_request_info r;
68          return 0;          ccs_init_request_info(&r, domain, CCS_MAC_FILE_EXECUTE);
69  }          error = ccs_write_audit_log(false, &r, "use_profile %u\n", r.profile);
70            return error;
 int TooManyDomainACL(struct domain_info * const domain) {  
         unsigned int count = 0;  
         struct acl_info *ptr;  
         for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) {  
                 if (!ptr->is_deleted) count++;  
         }  
         /* If there are so many entries, don't append if learning mode. */  
         if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 0;  
         if (!domain->quota_warned) {  
                 printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);  
                 domain->quota_warned = 1;  
         }  
         return 1;  
71  }  }
72    
73    /* The list for "struct ccs_domain_initializer_entry". */
74    LIST_HEAD(ccs_domain_initializer_list);
75    
76  /*************************  DOMAIN INITIALIZER HANDLER  *************************/  /**
77     * ccs_update_domain_initializer_entry - Update "struct ccs_domain_initializer_entry" list.
78  static struct domain_initializer_entry *domain_initializer_list = NULL;   *
79     * @domainname: The name of domain. May be NULL.
80  static int AddDomainInitializerEntry(const char *domainname, const char *program, const int is_not, const int is_delete)   * @program:    The name of program.
81  {   * @is_not:     True if it is "no_initialize_domain" entry.
82          struct domain_initializer_entry *new_entry, *ptr;   * @is_delete:  True if it is a delete request.
83          static DECLARE_MUTEX(lock);   *
84          const struct path_info *saved_program, *saved_domainname = NULL;   * Returns 0 on success, negative value otherwise.
85          int error = -ENOMEM;   */
86          int is_last_name = 0;  static int ccs_update_domain_initializer_entry(const char *domainname,
87          if (!IsCorrectPath(program, 1, -1, -1, __FUNCTION__)) return -EINVAL; /* No patterns allowed. */                                                 const char *program,
88                                                   const bool is_not,
89                                                   const bool is_delete)
90    {
91            struct ccs_domain_initializer_entry *entry = NULL;
92            struct ccs_domain_initializer_entry *ptr;
93            struct ccs_domain_initializer_entry e = { .is_not = is_not };
94            int error = is_delete ? -ENOENT : -ENOMEM;
95            if (!ccs_is_correct_path(program, 1, -1, -1))
96                    return -EINVAL; /* No patterns allowed. */
97          if (domainname) {          if (domainname) {
98                  if (!IsDomainDef(domainname) && IsCorrectPath(domainname, 1, -1, -1, __FUNCTION__)) {                  if (!ccs_is_domain_def(domainname) &&
99                          is_last_name = 1;                      ccs_is_correct_path(domainname, 1, -1, -1))
100                  } else if (!IsCorrectDomain(domainname, __FUNCTION__)) {                          e.is_last_name = true;
101                    else if (!ccs_is_correct_domain(domainname))
102                          return -EINVAL;                          return -EINVAL;
103                  }                  e.domainname = ccs_get_name(domainname);
104                  if ((saved_domainname = SaveName(domainname)) == NULL) return -ENOMEM;                  if (!e.domainname)
         }  
         if ((saved_program = SaveName(program)) == NULL) return -ENOMEM;  
         down(&lock);  
         for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {  
                 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {  
                         ptr->is_deleted = is_delete;  
                         error = 0;  
105                          goto out;                          goto out;
                 }  
106          }          }
107          if (is_delete) {          e.program = ccs_get_name(program);
108                  error = -ENOENT;          if (!e.program)
109                  goto out;                  goto out;
110            if (!is_delete)
111                    entry = kmalloc(sizeof(e), GFP_KERNEL);
112            mutex_lock(&ccs_policy_lock);
113            list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
114                    if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
115                                   sizeof(e)))
116                            continue;
117                    ptr->is_deleted = is_delete;
118                    error = 0;
119                    break;
120          }          }
121          if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
122          new_entry->domainname = saved_domainname;                  list_add_tail_rcu(&entry->list, &ccs_domain_initializer_list);
123          new_entry->program = saved_program;                  entry = NULL;
124          new_entry->is_not = is_not;                  error = 0;
         new_entry->is_last_name = is_last_name;  
         mb(); /* Instead of using spinlock. */  
         if ((ptr = domain_initializer_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 domain_initializer_list = new_entry;  
125          }          }
126          error = 0;          mutex_unlock(&ccs_policy_lock);
127   out:   out:
128          up(&lock);          ccs_put_name(e.domainname);
129            ccs_put_name(e.program);
130            kfree(entry);
131          return error;          return error;
132  }  }
133    
134  int ReadDomainInitializerPolicy(struct io_buffer *head)  /**
135     * ccs_read_domain_initializer_policy - Read "struct ccs_domain_initializer_entry" list.
136     *
137     * @head: Pointer to "struct ccs_io_buffer".
138     *
139     * Returns true on success, false otherwise.
140     *
141     * Caller holds ccs_read_lock().
142     */
143    bool ccs_read_domain_initializer_policy(struct ccs_io_buffer *head)
144  {  {
145          struct domain_initializer_entry *ptr = head->read_var2;          struct list_head *pos;
146          if (!ptr) ptr = domain_initializer_list;          bool done = true;
147          while (ptr) {          list_for_each_cookie(pos, head->read_var2,
148                  head->read_var2 = ptr;                               &ccs_domain_initializer_list) {
149                  if (!ptr->is_deleted) {                  const char *no;
150                          if (ptr->domainname) {                  const char *from = "";
151                                  if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;                  const char *domain = "";
152                          } else {                  struct ccs_domain_initializer_entry *ptr;
153                                  if (io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->program->name)) break;                  ptr = list_entry(pos, struct ccs_domain_initializer_entry,
154                          }                                   list);
155                    if (ptr->is_deleted)
156                            continue;
157                    no = ptr->is_not ? "no_" : "";
158                    if (ptr->domainname) {
159                            from = " from ";
160                            domain = ptr->domainname->name;
161                  }                  }
162                  ptr = ptr->next;                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_INITIALIZE_DOMAIN
163                                         "%s%s%s\n", no, ptr->program->name, from,
164                                         domain);
165                    if (!done)
166                            break;
167          }          }
168          return ptr ? -ENOMEM : 0;          return done;
169  }  }
170    
171  int AddDomainInitializerPolicy(char *data, const int is_not, const int is_delete)  /**
172     * ccs_write_domain_initializer_policy - Write "struct ccs_domain_initializer_entry" list.
173     *
174     * @data:      String to parse.
175     * @is_not:    True if it is "no_initialize_domain" entry.
176     * @is_delete: True if it is a delete request.
177     *
178     * Returns 0 on success, negative value otherwise.
179     */
180    int ccs_write_domain_initializer_policy(char *data, const bool is_not,
181                                            const bool is_delete)
182  {  {
183          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
184          if (cp) {          if (cp) {
185                  *cp = '\0';                  *cp = '\0';
186                  return AddDomainInitializerEntry(cp + 6, data, is_not, is_delete);                  return ccs_update_domain_initializer_entry(cp + 6, data,
187          } else {                                                             is_not, is_delete);
                 return AddDomainInitializerEntry(NULL, data, is_not, is_delete);  
188          }          }
189            return ccs_update_domain_initializer_entry(NULL, data, is_not,
190                                                       is_delete);
191  }  }
192    
193  static int IsDomainInitializer(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)  /**
194  {   * ccs_is_domain_initializer - Check whether the given program causes domainname reinitialization.
195          struct domain_initializer_entry *ptr;   *
196          int flag = 0;   * @domainname: The name of domain.
197          for (ptr = domain_initializer_list; ptr; ptr = ptr->next) {   * @program:    The name of program.
198                  if (ptr->is_deleted ) continue;   * @last_name:  The last component of @domainname.
199     *
200     * Returns true if executing @program reinitializes domain transition,
201     * false otherwise.
202     *
203     * Caller holds ccs_read_lock().
204     */
205    static bool ccs_is_domain_initializer(const struct ccs_path_info *domainname,
206                                          const struct ccs_path_info *program,
207                                          const struct ccs_path_info *last_name)
208    {
209            struct ccs_domain_initializer_entry *ptr;
210            bool flag = false;
211            list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list, list) {
212                    if (ptr->is_deleted)
213                            continue;
214                  if (ptr->domainname) {                  if (ptr->domainname) {
215                          if (!ptr->is_last_name) {                          if (!ptr->is_last_name) {
216                                  if (ptr->domainname != domainname) continue;                                  if (ptr->domainname != domainname)
217                                            continue;
218                          } else {                          } else {
219                                  if (pathcmp(ptr->domainname, last_name)) continue;                                  if (ccs_pathcmp(ptr->domainname, last_name))
220                                            continue;
221                          }                          }
222                  }                  }
223                  if (pathcmp(ptr->program, program)) continue;                  if (ccs_pathcmp(ptr->program, program))
224                  if (ptr->is_not) return 0;                          continue;
225                  flag = 1;                  if (ptr->is_not) {
226                            flag = false;
227                            break;
228                    }
229                    flag = true;
230          }          }
231          return flag;          return flag;
232  }  }
233    
234  /*************************  DOMAIN KEEPER HANDLER  *************************/  /* The list for "struct ccs_domain_keeper_entry". */
235    LIST_HEAD(ccs_domain_keeper_list);
 static struct domain_keeper_entry *domain_keeper_list = NULL;  
236    
237  static int AddDomainKeeperEntry(const char *domainname, const char *program, const int is_not, const int is_delete)  /**
238  {   * ccs_update_domain_keeper_entry - Update "struct ccs_domain_keeper_entry" list.
239          struct domain_keeper_entry *new_entry, *ptr;   *
240          const struct path_info *saved_domainname, *saved_program = NULL;   * @domainname: The name of domain.
241          static DECLARE_MUTEX(lock);   * @program:    The name of program. May be NULL.
242          int error = -ENOMEM;   * @is_not:     True if it is "no_keep_domain" entry.
243          int is_last_name = 0;   * @is_delete:  True if it is a delete request.
244          if (!IsDomainDef(domainname) && IsCorrectPath(domainname, 1, -1, -1, __FUNCTION__)) {   *
245                  is_last_name = 1;   * Returns 0 on success, negative value otherwise.
246          } else if (!IsCorrectDomain(domainname, __FUNCTION__)) {   */
247    static int ccs_update_domain_keeper_entry(const char *domainname,
248                                              const char *program,
249                                              const bool is_not,
250                                              const bool is_delete)
251    {
252            struct ccs_domain_keeper_entry *entry = NULL;
253            struct ccs_domain_keeper_entry *ptr;
254            struct ccs_domain_keeper_entry e = { .is_not = is_not };
255            int error = is_delete ? -ENOENT : -ENOMEM;
256            if (!ccs_is_domain_def(domainname) &&
257                ccs_is_correct_path(domainname, 1, -1, -1))
258                    e.is_last_name = true;
259            else if (!ccs_is_correct_domain(domainname))
260                  return -EINVAL;                  return -EINVAL;
         }  
261          if (program) {          if (program) {
262                  if (!IsCorrectPath(program, 1, -1, -1, __FUNCTION__)) return -EINVAL;                  if (!ccs_is_correct_path(program, 1, -1, -1))
263                  if ((saved_program = SaveName(program)) == NULL) return -ENOMEM;                          return -EINVAL;
264          }                  e.program = ccs_get_name(program);
265          if ((saved_domainname = SaveName(domainname)) == NULL) return -ENOMEM;                  if (!e.program)
         down(&lock);  
         for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {  
                 if (ptr->is_not == is_not && ptr->domainname == saved_domainname && ptr->program == saved_program) {  
                         ptr->is_deleted = is_delete;  
                         error = 0;  
266                          goto out;                          goto out;
                 }  
267          }          }
268          if (is_delete) {          e.domainname = ccs_get_name(domainname);
269                  error = -ENOENT;          if (!e.domainname)
270                  goto out;                  goto out;
271            if (!is_delete)
272                    entry = kmalloc(sizeof(e), GFP_KERNEL);
273            mutex_lock(&ccs_policy_lock);
274            list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
275                    if (ccs_memcmp(ptr, &e, offsetof(typeof(e), is_not),
276                                   sizeof(e)))
277                            continue;
278                    ptr->is_deleted = is_delete;
279                    error = 0;
280                    break;
281          }          }
282          if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
283          new_entry->domainname = saved_domainname;                  list_add_tail_rcu(&entry->list, &ccs_domain_keeper_list);
284          new_entry->program = saved_program;                  entry = NULL;
285          new_entry->is_not = is_not;                  error = 0;
         new_entry->is_last_name = is_last_name;  
         mb(); /* Instead of using spinlock. */  
         if ((ptr = domain_keeper_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 domain_keeper_list = new_entry;  
286          }          }
287          error = 0;          mutex_unlock(&ccs_policy_lock);
288   out:   out:
289          up(&lock);          ccs_put_name(e.domainname);
290            ccs_put_name(e.program);
291            kfree(entry);
292          return error;          return error;
293  }  }
294    
295  int AddDomainKeeperPolicy(char *data, const int is_not, const int is_delete)  /**
296     * ccs_write_domain_keeper_policy - Write "struct ccs_domain_keeper_entry" list.
297     *
298     * @data:      String to parse.
299     * @is_not:    True if it is "no_keep_domain" entry.
300     * @is_delete: True if it is a delete request.
301     *
302     */
303    int ccs_write_domain_keeper_policy(char *data, const bool is_not,
304                                       const bool is_delete)
305  {  {
306          char *cp = strstr(data, " from ");          char *cp = strstr(data, " from ");
307          if (cp) {          if (cp) {
308                  *cp = '\0';                  *cp = '\0';
309                  return AddDomainKeeperEntry(cp + 6, data, is_not, is_delete);                  return ccs_update_domain_keeper_entry(cp + 6, data,
310          } else {                                                        is_not, is_delete);
                 return AddDomainKeeperEntry(data, NULL, is_not, is_delete);  
311          }          }
312            return ccs_update_domain_keeper_entry(data, NULL, is_not, is_delete);
313  }  }
314    
315  int ReadDomainKeeperPolicy(struct io_buffer *head)  /**
316     * ccs_read_domain_keeper_policy - Read "struct ccs_domain_keeper_entry" list.
317     *
318     * @head: Pointer to "struct ccs_io_buffer".
319     *
320     * Returns true on success, false otherwise.
321     *
322     * Caller holds ccs_read_lock().
323     */
324    bool ccs_read_domain_keeper_policy(struct ccs_io_buffer *head)
325  {  {
326          struct domain_keeper_entry *ptr = head->read_var2;          struct list_head *pos;
327          if (!ptr) ptr = domain_keeper_list;          bool done = true;
328          while (ptr) {          list_for_each_cookie(pos, head->read_var2,
329                  head->read_var2 = ptr;                               &ccs_domain_keeper_list) {
330                  if (!ptr->is_deleted) {                  struct ccs_domain_keeper_entry *ptr;
331                          if (ptr->program) {                  const char *no;
332                                  if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s from %s\n", ptr->is_not ? "no_" : "", ptr->program->name, ptr->domainname->name)) break;                  const char *from = "";
333                          } else {                  const char *program = "";
334                                  if (io_printf(head, "%s" KEYWORD_KEEP_DOMAIN "%s\n", ptr->is_not ? "no_" : "", ptr->domainname->name)) break;                  ptr = list_entry(pos, struct ccs_domain_keeper_entry, list);
335                          }                  if (ptr->is_deleted)
336                            continue;
337                    no = ptr->is_not ? "no_" : "";
338                    if (ptr->program) {
339                            from = " from ";
340                            program = ptr->program->name;
341                  }                  }
342                  ptr = ptr->next;                  done = ccs_io_printf(head, "%s" CCS_KEYWORD_KEEP_DOMAIN
343                                         "%s%s%s\n", no, program, from,
344                                         ptr->domainname->name);
345                    if (!done)
346                            break;
347          }          }
348          return ptr ? -ENOMEM : 0;          return done;
349  }  }
350    
351  static int IsDomainKeeper(const struct path_info *domainname, const struct path_info *program, const struct path_info *last_name)  /**
352  {   * ccs_is_domain_keeper - Check whether the given program causes domain transition suppression.
353          struct domain_keeper_entry *ptr;   *
354          int flag = 0;   * @domainname: The name of domain.
355          for (ptr = domain_keeper_list; ptr; ptr = ptr->next) {   * @program:    The name of program.
356                  if (ptr->is_deleted) continue;   * @last_name:  The last component of @domainname.
357     *
358     * Returns true if executing @program supresses domain transition,
359     * false otherwise.
360     *
361     * Caller holds ccs_read_lock().
362     */
363    static bool ccs_is_domain_keeper(const struct ccs_path_info *domainname,
364                                     const struct ccs_path_info *program,
365                                     const struct ccs_path_info *last_name)
366    {
367            struct ccs_domain_keeper_entry *ptr;
368            bool flag = false;
369            list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
370                    if (ptr->is_deleted)
371                            continue;
372                  if (!ptr->is_last_name) {                  if (!ptr->is_last_name) {
373                          if (ptr->domainname != domainname) continue;                          if (ptr->domainname != domainname)
374                                    continue;
375                  } else {                  } else {
376                          if (pathcmp(ptr->domainname, last_name)) continue;                          if (ccs_pathcmp(ptr->domainname, last_name))
377                                    continue;
378                  }                  }
379                  if (ptr->program && pathcmp(ptr->program, program)) continue;                  if (ptr->program && ccs_pathcmp(ptr->program, program))
380                  if (ptr->is_not) return 0;                          continue;
381                  flag = 1;                  if (ptr->is_not) {
382                            flag = false;
383                            break;
384                    }
385                    flag = true;
386          }          }
387          return flag;          return flag;
388  }  }
389    
390  /*************************  SYMBOLIC LINKED PROGRAM HANDLER  *************************/  /* The list for "struct ccs_aggregator_entry". */
391    LIST_HEAD(ccs_aggregator_list);
 static struct alias_entry *alias_list = NULL;  
392    
393  static int AddAliasEntry(const char *original_name, const char *aliased_name, const int is_delete)  /**
394  {   * ccs_update_aggregator_entry - Update "struct ccs_aggregator_entry" list.
395          struct alias_entry *new_entry, *ptr;   *
396          static DECLARE_MUTEX(lock);   * @original_name:   The original program's name.
397          const struct path_info *saved_original_name, *saved_aliased_name;   * @aggregated_name: The aggregated program's name.
398          int error = -ENOMEM;   * @is_delete:       True if it is a delete request.
399          if (!IsCorrectPath(original_name, 1, -1, -1, __FUNCTION__) || !IsCorrectPath(aliased_name, 1, -1, -1, __FUNCTION__)) return -EINVAL; /* No patterns allowed. */   *
400          if ((saved_original_name = SaveName(original_name)) == NULL || (saved_aliased_name = SaveName(aliased_name)) == NULL) return -ENOMEM;   * Returns 0 on success, negative value otherwise.
401          down(&lock);   */
402          for (ptr = alias_list; ptr; ptr = ptr->next) {  static int ccs_update_aggregator_entry(const char *original_name,
403                  if (ptr->original_name == saved_original_name && ptr->aliased_name == saved_aliased_name) {                                         const char *aggregated_name,
404                          ptr->is_deleted = is_delete;                                         const bool is_delete)
405                          error = 0;  {
406                          goto out;          struct ccs_aggregator_entry *entry = NULL;
407                  }          struct ccs_aggregator_entry *ptr;
408          }          struct ccs_aggregator_entry e = { };
409          if (is_delete) {          int error = is_delete ? -ENOENT : -ENOMEM;
410                  error = -ENOENT;          if (!ccs_is_correct_path(original_name, 1, 0, -1) ||
411                !ccs_is_correct_path(aggregated_name, 1, -1, -1))
412                    return -EINVAL;
413            e.original_name = ccs_get_name(original_name);
414            e.aggregated_name = ccs_get_name(aggregated_name);
415            if (!e.original_name || !e.aggregated_name)
416                  goto out;                  goto out;
417            if (!is_delete)
418                    entry = kmalloc(sizeof(e), GFP_KERNEL);
419            mutex_lock(&ccs_policy_lock);
420            list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
421                    if (ccs_memcmp(ptr, &e, offsetof(typeof(e), original_name),
422                                   sizeof(e)))
423                            continue;
424                    ptr->is_deleted = is_delete;
425                    error = 0;
426                    break;
427          }          }
428          if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;          if (!is_delete && error && ccs_commit_ok(entry, &e, sizeof(e))) {
429          new_entry->original_name = saved_original_name;                  list_add_tail_rcu(&entry->list, &ccs_aggregator_list);
430          new_entry->aliased_name = saved_aliased_name;                  entry = NULL;
431          mb(); /* Instead of using spinlock. */                  error = 0;
         if ((ptr = alias_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 alias_list = new_entry;  
432          }          }
433          error = 0;          mutex_unlock(&ccs_policy_lock);
434   out:   out:
435          up(&lock);          ccs_put_name(e.original_name);
436            ccs_put_name(e.aggregated_name);
437            kfree(entry);
438          return error;          return error;
439  }  }
440    
441  int ReadAliasPolicy(struct io_buffer *head)  /**
442     * ccs_read_aggregator_policy - Read "struct ccs_aggregator_entry" list.
443     *
444     * @head: Pointer to "struct ccs_io_buffer".
445     *
446     * Returns true on success, false otherwise.
447     *
448     * Caller holds ccs_read_lock().
449     */
450    bool ccs_read_aggregator_policy(struct ccs_io_buffer *head)
451  {  {
452          struct alias_entry *ptr = head->read_var2;          struct list_head *pos;
453          if (!ptr) ptr = alias_list;          bool done = true;
454          while (ptr) {          list_for_each_cookie(pos, head->read_var2, &ccs_aggregator_list) {
455                  head->read_var2 = ptr;                  struct ccs_aggregator_entry *ptr;
456                  if (!ptr->is_deleted && io_printf(head, KEYWORD_ALIAS "%s %s\n", ptr->original_name->name, ptr->aliased_name->name)) break;                  ptr = list_entry(pos, struct ccs_aggregator_entry, list);
457                  ptr = ptr->next;                  if (ptr->is_deleted)
458                            continue;
459                    done = ccs_io_printf(head, CCS_KEYWORD_AGGREGATOR "%s %s\n",
460                                         ptr->original_name->name,
461                                         ptr->aggregated_name->name);
462                    if (!done)
463                            break;
464          }          }
465          return ptr ? -ENOMEM : 0;          return done;
466  }  }
467    
468  int AddAliasPolicy(char *data, const int is_delete)  /**
469     * ccs_write_aggregator_policy - Write "struct ccs_aggregator_entry" list.
470     *
471     * @data:      String to parse.
472     * @is_delete: True if it is a delete request.
473     *
474     * Returns 0 on success, negative value otherwise.
475     */
476    int ccs_write_aggregator_policy(char *data, const bool is_delete)
477  {  {
478          char *cp = strchr(data, ' ');          char *w[2];
479          if (!cp) return -EINVAL;          if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
480          *cp++ = '\0';                  return -EINVAL;
481          return AddAliasEntry(data, cp, is_delete);          return ccs_update_aggregator_entry(w[0], w[1], is_delete);
482  }  }
483    
484  /*************************  DOMAIN AGGREGATOR HANDLER  *************************/  /* Domain create/delete handler. */
   
 static struct aggregator_entry *aggregator_list = NULL;  
485    
486  static int AddAggregatorEntry(const char *original_name, const char *aggregated_name, const int is_delete)  /**
487     * ccs_delete_domain - Delete a domain.
488     *
489     * @domainname: The name of domain.
490     *
491     * Returns 0.
492     */
493    int ccs_delete_domain(char *domainname)
494  {  {
495          struct aggregator_entry *new_entry, *ptr;          struct ccs_domain_info *domain;
496          static DECLARE_MUTEX(lock);          struct ccs_path_info name;
497          const struct path_info *saved_original_name, *saved_aggregated_name;          name.name = domainname;
498          int error = -ENOMEM;          ccs_fill_path_info(&name);
499          if (!IsCorrectPath(original_name, 1, 0, -1, __FUNCTION__) || !IsCorrectPath(aggregated_name, 1, -1, -1, __FUNCTION__)) return -EINVAL;          mutex_lock(&ccs_policy_lock);
500          if ((saved_original_name = SaveName(original_name)) == NULL || (saved_aggregated_name = SaveName(aggregated_name)) == NULL) return -ENOMEM;          /* Is there an active domain? */
501          down(&lock);          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
502          for (ptr = aggregator_list; ptr; ptr = ptr->next) {                  /* Never delete ccs_kernel_domain */
503                  if (ptr->original_name == saved_original_name && ptr->aggregated_name == saved_aggregated_name) {                  if (domain == &ccs_kernel_domain)
504                          ptr->is_deleted = is_delete;                          continue;
505                          error = 0;                  if (domain->is_deleted ||
506                          goto out;                      ccs_pathcmp(domain->domainname, &name))
507                  }                          continue;
508          }                  domain->is_deleted = true;
509          if (is_delete) {                  break;
                 error = -ENOENT;  
                 goto out;  
         }  
         if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;  
         new_entry->original_name = saved_original_name;  
         new_entry->aggregated_name = saved_aggregated_name;  
         mb(); /* Instead of using spinlock. */  
         if ((ptr = aggregator_list) != NULL) {  
                 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;  
         } else {  
                 aggregator_list = new_entry;  
510          }          }
511          error = 0;          mutex_unlock(&ccs_policy_lock);
512   out:          return 0;
         up(&lock);  
         return error;  
513  }  }
514    
515  int ReadAggregatorPolicy(struct io_buffer *head)  /**
516     * ccs_find_or_assign_new_domain - Create a domain.
517     *
518     * @domainname: The name of domain.
519     * @profile:    Profile number to assign if the domain was newly created.
520     *
521     * Returns pointer to "struct ccs_domain_info" on success, NULL otherwise.
522     */
523    struct ccs_domain_info *ccs_find_or_assign_new_domain(const char *domainname,
524                                                          const u8 profile)
525  {  {
526          struct aggregator_entry *ptr = head->read_var2;          struct ccs_domain_info *entry;
527          if (!ptr) ptr = aggregator_list;          struct ccs_domain_info *domain;
528          while (ptr) {          const struct ccs_path_info *saved_domainname;
529                  head->read_var2 = ptr;          bool found = false;
530                  if (!ptr->is_deleted && io_printf(head, KEYWORD_AGGREGATOR "%s %s\n", ptr->original_name->name, ptr->aggregated_name->name)) break;  
531                  ptr = ptr->next;          if (!ccs_is_correct_domain(domainname))
532                    return NULL;
533            saved_domainname = ccs_get_name(domainname);
534            if (!saved_domainname)
535                    return NULL;
536            entry = kzalloc(sizeof(*entry), GFP_KERNEL);
537            mutex_lock(&ccs_policy_lock);
538            list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
539                    if (domain->is_deleted ||
540                        ccs_pathcmp(saved_domainname, domain->domainname))
541                            continue;
542                    found = true;
543                    break;
544          }          }
545          return ptr ? -ENOMEM : 0;          if (!found && ccs_memory_ok(entry, sizeof(*entry))) {
546                    INIT_LIST_HEAD(&entry->acl_info_list);
547                    entry->domainname = saved_domainname;
548                    saved_domainname = NULL;
549                    entry->profile = profile;
550                    list_add_tail_rcu(&entry->list, &ccs_domain_list);
551                    domain = entry;
552                    entry = NULL;
553                    found = true;
554            }
555            mutex_unlock(&ccs_policy_lock);
556            ccs_put_name(saved_domainname);
557            kfree(entry);
558            return found ? domain : NULL;
559  }  }
560    
561  int AddAggregatorPolicy(char *data, const int is_delete)  /**
562     * ccs_find_next_domain - Find a domain.
563     *
564     * @ee: Pointer to "struct ccs_execve_entry".
565     *
566     * Returns 0 on success, negative value otherwise.
567     *
568     * Caller holds ccs_read_lock().
569     */
570    static int ccs_find_next_domain(struct ccs_execve_entry *ee)
571  {  {
572          char *cp = strchr(data, ' ');          struct ccs_request_info *r = &ee->r;
573          if (!cp) return -EINVAL;          const struct ccs_path_info *handler = ee->handler;
574          *cp++ = '\0';          struct ccs_domain_info *domain = NULL;
575          return AddAggregatorEntry(data, cp, is_delete);          const char *old_domain_name = r->domain->domainname->name;
576  }          struct linux_binprm *bprm = ee->bprm;
577            const u32 ccs_flags = current->ccs_flags;
578            struct ccs_path_info rn = { }; /* real name */
579            struct ccs_path_info ln; /* last name */
580            int retval;
581            bool need_kfree = false;
582            ln.name = ccs_last_word(old_domain_name);
583            ccs_fill_path_info(&ln);
584     retry:
585            current->ccs_flags = ccs_flags;
586            r->cond = NULL;
587            if (need_kfree) {
588                    kfree(rn.name);
589                    need_kfree = false;
590            }
591    
592  /*************************  DOMAIN DELETION HANDLER  *************************/          /* Get symlink's pathname of program. */
593            retval = ccs_symlink_path(bprm->filename, &rn);
594            if (retval < 0)
595                    goto out;
596            need_kfree = true;
597    
598  /* #define DEBUG_DOMAIN_UNDELETE */          if (handler) {
599                    if (ccs_pathcmp(&rn, handler)) {
600                            /* Failed to verify execute handler. */
601                            static u8 counter = 20;
602                            if (counter) {
603                                    counter--;
604                                    printk(KERN_WARNING "Failed to verify: %s\n",
605                                           handler->name);
606                            }
607                            goto out;
608                    }
609            } else {
610                    struct ccs_aggregator_entry *ptr;
611                    /* Check 'aggregator' directive. */
612                    list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
613                            if (ptr->is_deleted ||
614                                !ccs_path_matches_pattern(&rn, ptr->original_name))
615                                    continue;
616                            kfree(rn.name);
617                            need_kfree = false;
618                            /* This is OK because it is read only. */
619                            rn = *ptr->aggregated_name;
620                            break;
621                    }
622    
623  int DeleteDomain(char *domainname0)                  /* Check execute permission. */
624  {                  retval = ccs_exec_perm(r, &rn);
625          struct domain_info *domain;                  if (retval == 1)
626          struct path_info domainname;                          goto retry;
627          domainname.name = domainname0;                  if (retval < 0)
628          fill_path_info(&domainname);                          goto out;
         down(&new_domain_assign_lock);  
 #ifdef DEBUG_DOMAIN_UNDELETE  
         printk("DeleteDomain %s\n", domainname0);  
         for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {  
                 if (pathcmp(domain->domainname, &domainname)) continue;  
                 printk("List: %p %u\n", domain, domain->is_deleted);  
629          }          }
630  #endif  
631          /* Is there an active domain? */          /* Calculate domain to transit to. */
632          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) { /* Never delete KERNEL_DOMAIN */          if (ccs_is_domain_initializer(r->domain->domainname, &rn, &ln)) {
633                  if (domain->is_deleted || pathcmp(domain->domainname, &domainname)) continue;                  /* Transit to the child of ccs_kernel_domain domain. */
634                  break;                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, ROOT_NAME " " "%s",
635                             rn.name);
636            } else if (r->domain == &ccs_kernel_domain && !ccs_policy_loaded) {
637                    /*
638                     * Needn't to transit from kernel domain before starting
639                     * /sbin/init. But transit from kernel domain if executing
640                     * initializers because they might start before /sbin/init.
641                     */
642                    domain = r->domain;
643            } else if (ccs_is_domain_keeper(r->domain->domainname, &rn, &ln)) {
644                    /* Keep current domain. */
645                    domain = r->domain;
646            } else {
647                    /* Normal domain transition. */
648                    snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s %s",
649                             old_domain_name, rn.name);
650          }          }
651          if (domain) {          if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10)
652                  struct domain_info *domain2;                  goto done;
653                  /* Mark already deleted domains as non undeletable. */          domain = ccs_find_domain(ee->tmp);
654                  for (domain2 = KERNEL_DOMAIN.next; domain2; domain2 = domain2->next) {          if (domain)
655                          if (!domain2->is_deleted || pathcmp(domain2->domainname, &domainname)) continue;                  goto done;
656  #ifdef DEBUG_DOMAIN_UNDELETE          if (r->mode == CCS_CONFIG_ENFORCING) {
657                          if (domain2->is_deleted != 255) printk("Marked %p as non undeletable\n", domain2);                  int error = ccs_supervisor(r, "# wants to create domain\n"
658  #endif                                             "%s\n", ee->tmp);
659                          domain2->is_deleted = 255;                  if (error == 1)
660                  }                          goto retry;
661                  /* Delete and mark active domain as undeletable. */                  if (error < 0)
662                  domain->is_deleted = 1;                          goto done;
663  #ifdef DEBUG_DOMAIN_UNDELETE          }
664                  printk("Marked %p as undeletable\n", domain);          domain = ccs_find_or_assign_new_domain(ee->tmp, r->profile);
665  #endif          if (domain)
666                    ccs_audit_domain_creation_log(r->domain);
667     done:
668            if (!domain) {
669                    printk(KERN_WARNING "ERROR: Domain '%s' not defined.\n",
670                           ee->tmp);
671                    if (r->mode == CCS_CONFIG_ENFORCING)
672                            retval = -EPERM;
673                    else {
674                            retval = 0;
675                            r->domain->domain_transition_failed = true;
676                    }
677            } else {
678                    retval = 0;
679          }          }
680          up(&new_domain_assign_lock);   out:
681          return 0;          if (domain)
682                    r->domain = domain;
683            if (need_kfree)
684                    kfree(rn.name);
685            return retval;
686  }  }
687    
688  struct domain_info *UndeleteDomain(const char *domainname0)  /**
689     * ccs_environ - Check permission for environment variable names.
690     *
691     * @ee: Pointer to "struct ccs_execve_entry".
692     *
693     * Returns 0 on success, negative value otherwise.
694     */
695    static int ccs_environ(struct ccs_execve_entry *ee)
696  {  {
697          struct domain_info *domain, *candidate_domain = NULL;          struct ccs_request_info *r = &ee->r;
698          struct path_info domainname;          struct linux_binprm *bprm = ee->bprm;
699          domainname.name = domainname0;          char *arg_ptr = ee->tmp;
700          fill_path_info(&domainname);          int arg_len = 0;
701          down(&new_domain_assign_lock);          unsigned long pos = bprm->p;
702  #ifdef DEBUG_DOMAIN_UNDELETE          int offset = pos % PAGE_SIZE;
703          printk("UndeleteDomain %s\n", domainname0);          int argv_count = bprm->argc;
704          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {          int envp_count = bprm->envc;
705                  if (pathcmp(domain->domainname, &domainname)) continue;          /* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */
706                  printk("List: %p %u\n", domain, domain->is_deleted);          int error = -ENOMEM;
707          }          if (!r->mode || !envp_count)
708  #endif                  return 0;
709          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {          while (error == -ENOMEM) {
710                  if (pathcmp(&domainname, domain->domainname)) continue;                  if (!ccs_dump_page(bprm, pos, &ee->dump))
711                  if (!domain->is_deleted) {                          goto out;
712                          /* This domain is active. I can't undelete. */                  pos += PAGE_SIZE - offset;
713                          candidate_domain = NULL;                  /* Read. */
714  #ifdef DEBUG_DOMAIN_UNDELETE                  while (argv_count && offset < PAGE_SIZE) {
715                          printk("%p is active. I can't undelete.\n", domain);                          const char *kaddr = ee->dump.data;
716  #endif                          if (!kaddr[offset++])
717                          break;                                  argv_count--;
718                  }                  }
719                  /* Is this domain undeletable? */                  if (argv_count) {
720                  if (domain->is_deleted == 1) candidate_domain = domain;                          offset = 0;
721          }                          continue;
722          if (candidate_domain) {                  }
723                  candidate_domain->is_deleted = 0;                  while (offset < PAGE_SIZE) {
724  #ifdef DEBUG_DOMAIN_UNDELETE                          const char *kaddr = ee->dump.data;
725                  printk("%p was undeleted.\n", candidate_domain);                          const unsigned char c = kaddr[offset++];
726  #endif                          if (c && arg_len < CCS_EXEC_TMPSIZE - 10) {
727          }                                  if (c == '=') {
728          up(&new_domain_assign_lock);                                          arg_ptr[arg_len++] = '\0';
729          return candidate_domain;                                  } else if (c == '\\') {
730  }                                          arg_ptr[arg_len++] = '\\';
731                                            arg_ptr[arg_len++] = '\\';
732  /*************************  DOMAIN TRANSITION HANDLER  *************************/                                  } else if (c > ' ' && c < 127) {
733                                            arg_ptr[arg_len++] = c;
734  struct domain_info *FindOrAssignNewDomain(const char *domainname, const u8 profile)                                  } else {
735  {                                          arg_ptr[arg_len++] = '\\';
736          struct domain_info *domain = NULL;                                          arg_ptr[arg_len++] = (c >> 6) + '0';
737          const struct path_info *saved_domainname;                                          arg_ptr[arg_len++]
738          down(&new_domain_assign_lock);                                                  = ((c >> 3) & 7) + '0';
739          if ((domain = FindDomain(domainname)) != NULL) goto out;                                          arg_ptr[arg_len++] = (c & 7) + '0';
740          if (!IsCorrectDomain(domainname, __FUNCTION__)) goto out;                                  }
741          if ((saved_domainname = SaveName(domainname)) == NULL) goto out;                          } else {
742          /* Can I reuse memory of deleted domain? */                                  arg_ptr[arg_len] = '\0';
743          for (domain = KERNEL_DOMAIN.next; domain; domain = domain->next) {                          }
744                  struct task_struct *p;                          if (c)
745                  struct acl_info *ptr;                                  continue;
746                  int flag;                          if (ccs_env_perm(r, arg_ptr)) {
747                  if (!domain->is_deleted || domain->domainname != saved_domainname) continue;                                  error = -EPERM;
748                  flag = 0;                                  break;
749                  /***** CRITICAL SECTION START *****/                          }
750                  read_lock(&tasklist_lock);                          if (!--envp_count) {
751                  for_each_process(p) {                                  error = 0;
752                          if (p->domain_info == domain) { flag = 1; break; }                                  break;
753                  }                          }
754                  read_unlock(&tasklist_lock);                          arg_len = 0;
755                  /***** CRITICAL SECTION END *****/                  }
756                  if (flag) continue;                  offset = 0;
 #ifdef DEBUG_DOMAIN_UNDELETE  
                 printk("Reusing %p %s\n", domain, domain->domainname->name);  
 #endif  
                 for (ptr = domain->first_acl_ptr; ptr; ptr = ptr->next) ptr->is_deleted = 1;  
                 domain->profile = profile;  
                 domain->quota_warned = 0;  
                 mb(); /* Instead of using spinlock. */  
                 domain->is_deleted = 0;  
                 goto out;  
757          }          }
758          /* No memory reusable. Create using new memory. */   out:
759          if ((domain = alloc_element(sizeof(*domain))) != NULL) {          if (r->mode != 3)
760                  struct domain_info *ptr = &KERNEL_DOMAIN;                  error = 0;
761                  domain->domainname = saved_domainname;          return error;
                 domain->profile = profile;  
                 mb(); /* Instead of using spinlock. */  
                 while (ptr->next) ptr = ptr->next; ptr->next = domain;  
         }  
  out: ;  
         up(&new_domain_assign_lock);  
         return domain;  
762  }  }
763    
764  static int Escape(char *dest, const char *src, int dest_len)  /**
765     * ccs_unescape - Unescape escaped string.
766     *
767     * @dest: String to unescape.
768     *
769     * Returns nothing.
770     */
771    static void ccs_unescape(unsigned char *dest)
772  {  {
773          while (*src) {          unsigned char *src = dest;
774                  const unsigned char c = * (const unsigned char *) src;          unsigned char c;
775            unsigned char d;
776            unsigned char e;
777            while (1) {
778                    c = *src++;
779                    if (!c)
780                            break;
781                    if (c != '\\') {
782                            *dest++ = c;
783                            continue;
784                    }
785                    c = *src++;
786                  if (c == '\\') {                  if (c == '\\') {
                         dest_len -= 2;  
                         if (dest_len <= 0) goto out;  
                         *dest++ = '\\';  
                         *dest++ = '\\';  
                 } else if (c > ' ' && c < 127) {  
                         if (--dest_len <= 0) goto out;  
787                          *dest++ = c;                          *dest++ = c;
788                  } else {                          continue;
                         dest_len -= 4;  
                         if (dest_len <= 0) goto out;  
                         *dest++ = '\\';  
                         *dest++ = (c >> 6) + '0';  
                         *dest++ = ((c >> 3) & 7) + '0';  
                         *dest++ = (c & 7) + '0';  
789                  }                  }
790                  src++;                  if (c < '0' || c > '3')
791                            break;
792                    d = *src++;
793                    if (d < '0' || d > '7')
794                            break;
795                    e = *src++;
796                    if (e < '0' || e > '7')
797                            break;
798                    *dest++ = ((c - '0') << 6) + ((d - '0') << 3) + (e - '0');
799          }          }
         if (--dest_len <= 0) goto out;  
800          *dest = '\0';          *dest = '\0';
         return 0;  
  out:  
         return -ENOMEM;  
801  }  }
802    
803  static char *get_argv0(struct linux_binprm *bprm)  /**
804     * ccs_root_depth - Get number of directories to strip.
805     *
806     * @dentry: Pointer to "struct dentry".
807     * @vfsmnt: Pointer to "struct vfsmount".
808     *
809     * Returns number of directories to strip.
810     */
811    static inline int ccs_root_depth(struct dentry *dentry, struct vfsmount *vfsmnt)
812  {  {
813          char *arg_ptr = ccs_alloc(PAGE_SIZE); /* Initial buffer. */          int depth = 0;
814          int arg_len = 0;          ccs_realpath_lock();
815          unsigned long pos = bprm->p;          for (;;) {
816          int i = pos / PAGE_SIZE, offset = pos % PAGE_SIZE;                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
817          if (!bprm->argc || !arg_ptr) goto out;                          /* Global root? */
818          while (1) {                          if (vfsmnt->mnt_parent == vfsmnt)
819                  struct page *page;                                  break;
820  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)                          dentry = vfsmnt->mnt_mountpoint;
821                  if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0) goto out;                          vfsmnt = vfsmnt->mnt_parent;
822  #else                          continue;
823                  page = bprm->page[i];                  }
824                    dentry = dentry->d_parent;
825                    depth++;
826            }
827            ccs_realpath_unlock();
828            return depth;
829    }
830    
831    /**
832     * ccs_get_root_depth - return the depth of root directory.
833     *
834     * Returns number of directories to strip.
835     */
836    static int ccs_get_root_depth(void)
837    {
838            int depth;
839            struct dentry *dentry;
840            struct vfsmount *vfsmnt;
841    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
842            struct path root;
843  #endif  #endif
844                  { /* Map and copy to kernel buffer and unmap. */          read_lock(&current->fs->lock);
845                          const char *kaddr = kmap(page);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
846                          if (!kaddr) { /* Mapping failed. */          root = current->fs->root;
847  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)          path_get(&current->fs->root);
848                                  put_page(page);          dentry = root.dentry;
849            vfsmnt = root.mnt;
850    #else
851            dentry = dget(current->fs->root);
852            vfsmnt = mntget(current->fs->rootmnt);
853  #endif  #endif
854                                  goto out;          read_unlock(&current->fs->lock);
855                          }          depth = ccs_root_depth(dentry, vfsmnt);
856                          memmove(arg_ptr + arg_len, kaddr + offset, PAGE_SIZE - offset);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
857                          kunmap(page);          path_put(&root);
858                  }  #else
859  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) && defined(CONFIG_MMU)          dput(dentry);
860                  put_page(page);          mntput(vfsmnt);
                 pos += PAGE_SIZE - offset;  
861  #endif  #endif
862                  arg_len += PAGE_SIZE - offset;          return depth;
863                  if (memchr(arg_ptr, '\0', arg_len)) break;  }
864                  { /* Initial buffer was too small for argv[0]. Retry after expanding buffer. */  
865                          char *tmp_arg_ptr = ccs_alloc(arg_len + PAGE_SIZE);  static LIST_HEAD(ccs_execve_list);
866                          if (!tmp_arg_ptr) goto out;  DEFINE_SPINLOCK(ccs_execve_list_lock);
867                          memmove(tmp_arg_ptr, arg_ptr, arg_len);  unsigned int ccs_in_execve_counter;
868                          ccs_free(arg_ptr);  
869                          arg_ptr = tmp_arg_ptr;  /**
870                  }   * ccs_allocate_execve_entry - Allocate memory for execve().
871                  i++;   *
872                  offset = 0;   * Returns pointer to "struct ccs_execve_entry" on success, NULL otherwise.
873          }   */
874          return arg_ptr;  static inline struct ccs_execve_entry *ccs_allocate_execve_entry(void)
875   out: /* Release initial buffer. */  {
876          ccs_free(arg_ptr);          struct ccs_execve_entry *ee = kzalloc(sizeof(*ee), GFP_KERNEL);
877          return NULL;          if (!ee)
878  }                  return NULL;
879            ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL);
880  static int FindNextDomain(struct linux_binprm *bprm, struct domain_info **next_domain)          if (!ee->tmp) {
881  {                  kfree(ee);
882          /* This function assumes that the size of buffer returned by realpath() = CCS_MAX_PATHNAME_LEN. */                  return NULL;
883          struct domain_info *old_domain = current->domain_info, *domain = NULL;          }
884          const char *old_domain_name = old_domain->domainname->name;          ee->reader_idx = ccs_read_lock();
885          const char *original_name = bprm->filename;          /* ee->dump->data is allocated by ccs_dump_page(). */
886          struct file *filp = bprm->file;          ee->task = current;
887          char *new_domain_name = NULL;          ee->previous_domain = ee->task->ccs_domain_info;
888          char *real_program_name = NULL, *symlink_program_name = NULL;          spin_lock(&ccs_execve_list_lock);
889          const int is_enforce = CheckCCSEnforce(CCS_TOMOYO_MAC_FOR_FILE);          ccs_in_execve_counter++;
890            list_add(&ee->list, &ccs_execve_list);
891            spin_unlock(&ccs_execve_list_lock);
892            return ee;
893    }
894    
895    /**
896     * ccs_free_execve_entry - Free memory for execve().
897     *
898     * @ee: Pointer to "struct ccs_execve_entry".
899     */
900    static inline void ccs_free_execve_entry(struct ccs_execve_entry *ee)
901    {
902            if (!ee)
903                    return;
904            spin_lock(&ccs_execve_list_lock);
905            list_del(&ee->list);
906            ccs_in_execve_counter--;
907            spin_unlock(&ccs_execve_list_lock);
908            kfree(ee->handler_path);
909            kfree(ee->tmp);
910            kfree(ee->dump.data);
911            ccs_read_unlock(ee->reader_idx);
912            kfree(ee);
913    }
914    
915    /**
916     * ccs_try_alt_exec - Try to start execute handler.
917     *
918     * @ee: Pointer to "struct ccs_execve_entry".
919     *
920     * Returns 0 on success, negative value otherwise.
921     */
922    static int ccs_try_alt_exec(struct ccs_execve_entry *ee)
923    {
924            /*
925             * Contents of modified bprm.
926             * The envp[] in original bprm is moved to argv[] so that
927             * the alternatively executed program won't be affected by
928             * some dangerous environment variables like LD_PRELOAD.
929             *
930             * modified bprm->argc
931             *    = original bprm->argc + original bprm->envc + 7
932             * modified bprm->envc
933             *    = 0
934             *
935             * modified bprm->argv[0]
936             *    = the program's name specified by execute_handler
937             * modified bprm->argv[1]
938             *    = ccs_current_domain()->domainname->name
939             * modified bprm->argv[2]
940             *    = the current process's name
941             * modified bprm->argv[3]
942             *    = the current process's information (e.g. uid/gid).
943             * modified bprm->argv[4]
944             *    = original bprm->filename
945             * modified bprm->argv[5]
946             *    = original bprm->argc in string expression
947             * modified bprm->argv[6]
948             *    = original bprm->envc in string expression
949             * modified bprm->argv[7]
950             *    = original bprm->argv[0]
951             *  ...
952             * modified bprm->argv[bprm->argc + 6]
953             *     = original bprm->argv[bprm->argc - 1]
954             * modified bprm->argv[bprm->argc + 7]
955             *     = original bprm->envp[0]
956             *  ...
957             * modified bprm->argv[bprm->envc + bprm->argc + 6]
958             *     = original bprm->envp[bprm->envc - 1]
959             */
960            struct linux_binprm *bprm = ee->bprm;
961            struct file *filp;
962          int retval;          int retval;
963          struct path_info r, s, l;          const int original_argc = bprm->argc;
964            const int original_envc = bprm->envc;
965            struct task_struct *task = current;
966    
967            /* Close the requested program's dentry. */
968            allow_write_access(bprm->file);
969            fput(bprm->file);
970            bprm->file = NULL;
971    
972            /* Invalidate page dump cache. */
973            ee->dump.page = NULL;
974    
975            /* Move envp[] to argv[] */
976            bprm->argc += bprm->envc;
977            bprm->envc = 0;
978    
979            /* Set argv[6] */
980          {          {
981                  /*                  char *cp = ee->tmp;
982                   * Built-in initializers. This is needed because policies are not loaded until starting /sbin/init .                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_envc);
983                   */                  retval = copy_strings_kernel(1, &cp, bprm);
984                  static int first = 1;                  if (retval < 0)
985                  if (first) {                          goto out;
986                          AddDomainInitializerEntry(NULL, "/sbin/hotplug", 0, 0);                  bprm->argc++;
                         AddDomainInitializerEntry(NULL, "/sbin/modprobe", 0, 0);  
                         first = 0;  
                 }  
987          }          }
988    
989          /* Get realpath of program. */          /* Set argv[5] */
990          retval = -ENOENT; /* I hope realpath() won't fail with -ENOMEM. */          {
991          if ((real_program_name = realpath(original_name)) == NULL) goto out;                  char *cp = ee->tmp;
992          /* Get realpath of symbolic link. */                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%d", original_argc);
993          if ((symlink_program_name = realpath_nofollow(original_name)) == NULL) goto out;                  retval = copy_strings_kernel(1, &cp, bprm);
994                    if (retval < 0)
995          r.name = real_program_name;                          goto out;
996          fill_path_info(&r);                  bprm->argc++;
         s.name = symlink_program_name;  
         fill_path_info(&s);  
         if ((l.name = strrchr(old_domain_name, ' ')) != NULL) l.name++;  
         else l.name = old_domain_name;  
         fill_path_info(&l);  
   
         /* Check 'alias' directive. */  
         if (pathcmp(&r, &s)) {  
                 struct alias_entry *ptr;  
                 /* Is this program allowed to be called via symbolic links? */  
                 for (ptr = alias_list; ptr; ptr = ptr->next) {  
                         if (ptr->is_deleted || pathcmp(&r, ptr->original_name) || pathcmp(&s, ptr->aliased_name)) continue;  
                         memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);  
                         strncpy(real_program_name, ptr->aliased_name->name, CCS_MAX_PATHNAME_LEN - 1);  
                         fill_path_info(&r);  
                         break;  
                 }  
997          }          }
998            
999          /* Compare basename of real_program_name and argv[0] */          /* Set argv[4] */
1000          if (bprm->argc > 0 && CheckCCSFlags(CCS_TOMOYO_MAC_FOR_ARGV0)) {          {
1001                  char *org_argv0 = get_argv0(bprm);                  retval = copy_strings_kernel(1, &bprm->filename, bprm);
1002                  retval = -ENOMEM;                  if (retval < 0)
1003                  if (org_argv0) {                          goto out;
1004                          const int len = strlen(org_argv0);                  bprm->argc++;
                         char *printable_argv0 = ccs_alloc(len * 4 + 8);  
                         if (printable_argv0 && Escape(printable_argv0, org_argv0, len * 4 + 8) == 0) {  
                                 const char *base_argv0, *base_filename;  
                                 if ((base_argv0 = strrchr(printable_argv0, '/')) == NULL) base_argv0 = printable_argv0; else base_argv0++;  
                                 if ((base_filename = strrchr(real_program_name, '/')) == NULL) base_filename = real_program_name; else base_filename++;  
                                 if (strcmp(base_argv0, base_filename)) retval = CheckArgv0Perm(&r, base_argv0);  
                                 else retval = 0;  
                         }  
                         ccs_free(printable_argv0);  
                         ccs_free(org_argv0);  
                 }  
                 if (retval) goto out;  
1005          }          }
1006            
1007          /* Check 'aggregator' directive. */          /* Set argv[3] */
1008          {          {
1009                  struct aggregator_entry *ptr;                  char *cp = ee->tmp;
1010                  /* Is this program allowed to be aggregated? */                  const u32 ccs_flags = task->ccs_flags;
1011                  for (ptr = aggregator_list; ptr; ptr = ptr->next) {                  snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1,
1012                          if (ptr->is_deleted || !PathMatchesToPattern(&r, ptr->original_name)) continue;                           "pid=%d uid=%d gid=%d euid=%d egid=%d suid=%d "
1013                          memset(real_program_name, 0, CCS_MAX_PATHNAME_LEN);                           "sgid=%d fsuid=%d fsgid=%d state[0]=%u "
1014                          strncpy(real_program_name, ptr->aggregated_name->name, CCS_MAX_PATHNAME_LEN - 1);                           "state[1]=%u state[2]=%u",
1015                          fill_path_info(&r);                           (pid_t) sys_getpid(), current_uid(), current_gid(),
1016                          break;                           current_euid(), current_egid(), current_suid(),
1017                  }                           current_sgid(), current_fsuid(), current_fsgid(),
1018                             (u8) (ccs_flags >> 24), (u8) (ccs_flags >> 16),
1019                             (u8) (ccs_flags >> 8));
1020                    retval = copy_strings_kernel(1, &cp, bprm);
1021                    if (retval < 0)
1022                            goto out;
1023                    bprm->argc++;
1024          }          }
1025    
1026          /* Check execute permission. */          /* Set argv[2] */
1027          if ((retval = CheckExecPerm(&r, filp)) < 0) goto out;          {
1028                    char *exe = (char *) ccs_get_exe();
1029                    if (exe) {
1030                            retval = copy_strings_kernel(1, &exe, bprm);
1031                            kfree(exe);
1032                    } else {
1033                            exe = ee->tmp;
1034                            snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "<unknown>");
1035                            retval = copy_strings_kernel(1, &exe, bprm);
1036                    }
1037                    if (retval < 0)
1038                            goto out;
1039                    bprm->argc++;
1040            }
1041    
1042          /* Allocate memory for calcurating domain name. */          /* Set argv[1] */
1043          retval = -ENOMEM;          {
1044          if ((new_domain_name = ccs_alloc(CCS_MAX_PATHNAME_LEN + 16)) == NULL) goto out;                  char *cp = ee->tmp;
1045                            snprintf(ee->tmp, CCS_EXEC_TMPSIZE - 1, "%s",
1046          if (IsDomainInitializer(old_domain->domainname, &r, &l)) {                           ccs_current_domain()->domainname->name);
1047                  /* Transit to the child of KERNEL_DOMAIN domain. */                  retval = copy_strings_kernel(1, &cp, bprm);
1048                  snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1, ROOT_NAME " " "%s", real_program_name);                  if (retval < 0)
1049          } else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) {                          goto out;
1050                  /*                  bprm->argc++;
                  * Needn't to transit from kernel domain before starting /sbin/init .  
                  * But transit from kernel domain if executing initializers, for they might start before /sbin/init .  
                  */  
                 domain = old_domain;  
         } else if (IsDomainKeeper(old_domain->domainname, &r, &l)) {  
                 /* Keep current domain. */  
                 domain = old_domain;  
         } else {  
                 /* Normal domain transition. */  
                 snprintf(new_domain_name, CCS_MAX_PATHNAME_LEN + 1, "%s %s", old_domain_name, real_program_name);  
1051          }          }
1052          if (!domain && strlen(new_domain_name) < CCS_MAX_PATHNAME_LEN) {  
1053                  if (is_enforce) {          /* Set argv[0] */
1054                          domain = FindDomain(new_domain_name);          {
1055                          if (!domain) if (CheckSupervisor("#Need to create domain\n%s\n", new_domain_name) == 0) domain = FindOrAssignNewDomain(new_domain_name, current->domain_info->profile);                  int depth = ccs_get_root_depth();
1056                  } else {                  int len = ee->handler->total_len + 1;
1057                          domain = FindOrAssignNewDomain(new_domain_name, current->domain_info->profile);                  char *cp = kmalloc(len, GFP_KERNEL);
1058                    if (!cp) {
1059                            retval = ENOMEM;
1060                            goto out;
1061                  }                  }
1062                    ee->handler_path = cp;
1063                    memmove(cp, ee->handler->name, len);
1064                    ccs_unescape(cp);
1065                    retval = -ENOENT;
1066                    if (!*cp || *cp != '/')
1067                            goto out;
1068                    /* Adjust root directory for open_exec(). */
1069                    while (depth) {
1070                            cp = strchr(cp + 1, '/');
1071                            if (!cp)
1072                                    goto out;
1073                            depth--;
1074                    }
1075                    memmove(ee->handler_path, cp, strlen(cp) + 1);
1076                    cp = ee->handler_path;
1077                    retval = copy_strings_kernel(1, &cp, bprm);
1078                    if (retval < 0)
1079                            goto out;
1080                    bprm->argc++;
1081          }          }
1082          if (!domain) {  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
1083                  printk("TOMOYO-ERROR: Domain '%s' not defined.\n", new_domain_name);  #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
1084                  if (is_enforce) retval = -EPERM;          bprm->argv_len = bprm->exec - bprm->p;
1085          } else {  #endif
1086                  retval = 0;  #endif
1087    
1088            /* OK, now restart the process with execute handler program's dentry. */
1089            filp = open_exec(ee->handler_path);
1090            if (IS_ERR(filp)) {
1091                    retval = PTR_ERR(filp);
1092                    goto out;
1093          }          }
1094   out: ;          bprm->file = filp;
1095          ccs_free(new_domain_name);          bprm->filename = ee->handler_path;
1096          ccs_free(real_program_name);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1097          ccs_free(symlink_program_name);          bprm->interp = bprm->filename;
1098          *next_domain = domain ? domain : old_domain;  #endif
1099            retval = prepare_binprm(bprm);
1100            if (retval < 0)
1101                    goto out;
1102            task->ccs_flags |= CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1103            retval = ccs_find_next_domain(ee);
1104            task->ccs_flags &= ~CCS_DONT_SLEEP_ON_ENFORCE_ERROR;
1105     out:
1106          return retval;          return retval;
1107  }  }
1108    
1109  #endif  /**
1110     * ccs_find_execute_handler - Find an execute handler.
1111     *
1112     * @ee:   Pointer to "struct ccs_execve_entry".
1113     * @type: Type of execute handler.
1114     *
1115     * Returns true if found, false otherwise.
1116     *
1117     * Caller holds ccs_read_lock().
1118     */
1119    static bool ccs_find_execute_handler(struct ccs_execve_entry *ee,
1120                                         const u8 type)
1121    {
1122            struct task_struct *task = current;
1123            const struct ccs_domain_info *domain = ccs_current_domain();
1124            struct ccs_acl_info *ptr;
1125            bool found = false;
1126            /*
1127             * Don't use execute handler if the current process is
1128             * marked as execute handler to avoid infinite execute handler loop.
1129             */
1130            if (task->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)
1131                    return false;
1132            list_for_each_entry(ptr, &domain->acl_info_list, list) {
1133                    struct ccs_execute_handler_record *acl;
1134                    if (ptr->type != type)
1135                            continue;
1136                    acl = container_of(ptr, struct ccs_execute_handler_record,
1137                                       head);
1138                    ee->handler = acl->handler;
1139                    found = true;
1140                    break;
1141            }
1142            return found;
1143    }
1144    
1145  int search_binary_handler_with_transition(struct linux_binprm *bprm, struct pt_regs *regs)  /**
1146     * ccs_dump_page - Dump a page to buffer.
1147     *
1148     * @bprm: Pointer to "struct linux_binprm".
1149     * @pos:  Location to dump.
1150     * @dump: Poiner to "struct ccs_page_dump".
1151     *
1152     * Returns true on success, false otherwise.
1153     */
1154    bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
1155                       struct ccs_page_dump *dump)
1156  {  {
1157          struct domain_info *next_domain = NULL, *prev_domain = current->domain_info;          struct page *page;
1158          int retval;          /* dump->data is released by ccs_free_execve_entry(). */
1159  #if defined(CONFIG_SAKURA) || defined(CONFIG_TOMOYO)          if (!dump->data) {
1160          extern void CCS_LoadPolicy(const char *filename);                  dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL);
1161          CCS_LoadPolicy(bprm->filename);                  if (!dump->data)
1162  #endif                          return false;
1163  #if defined(CONFIG_TOMOYO)          }
1164          retval = FindNextDomain(bprm, &next_domain);          /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
1165    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1166            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1167                    return false;
1168    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1169            if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
1170                    return false;
1171  #else  #else
1172          retval = 0; next_domain = prev_domain;          page = bprm->page[pos / PAGE_SIZE];
1173    #endif
1174            if (page != dump->page) {
1175                    const unsigned int offset = pos % PAGE_SIZE;
1176                    /*
1177                     * Maybe kmap()/kunmap() should be used here.
1178                     * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
1179                     * So do I.
1180                     */
1181                    char *kaddr = kmap_atomic(page, KM_USER0);
1182                    dump->page = page;
1183                    memcpy(dump->data + offset, kaddr + offset, PAGE_SIZE - offset);
1184                    kunmap_atomic(kaddr, KM_USER0);
1185            }
1186            /* Same with put_arg_page(page) in fs/exec.c */
1187    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) && defined(CONFIG_MMU)
1188            put_page(page);
1189    #elif defined(RHEL_MAJOR) && RHEL_MAJOR == 5 && defined(RHEL_MINOR) && RHEL_MINOR == 3 && defined(CONFIG_MMU)
1190            put_page(page);
1191  #endif  #endif
1192          if (retval == 0) {          return true;
1193                  current->tomoyo_flags |= TOMOYO_CHECK_READ_FOR_OPEN_EXEC;  }
1194                  current->domain_info = next_domain;  
1195                  retval = search_binary_handler(bprm, regs);  /**
1196                  if (retval < 0) current->domain_info = prev_domain;   * ccs_start_execve - Prepare for execve() operation.
1197                  current->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC;   *
1198     * @bprm: Pointer to "struct linux_binprm".
1199     *
1200     * Returns 0 on success, negative value otherwise.
1201     */
1202    int ccs_start_execve(struct linux_binprm *bprm)
1203    {
1204            int retval;
1205            struct task_struct *task = current;
1206            struct ccs_execve_entry *ee = ccs_allocate_execve_entry();
1207            if (!ccs_policy_loaded)
1208                    ccs_load_policy(bprm->filename);
1209            if (!ee)
1210                    return -ENOMEM;
1211            ccs_init_request_info(&ee->r, NULL, CCS_MAC_FILE_EXECUTE);
1212            ee->r.ee = ee;
1213            ee->bprm = bprm;
1214            ee->r.obj = &ee->obj;
1215            ee->obj.path1.dentry = bprm->file->f_dentry;
1216            ee->obj.path1.mnt = bprm->file->f_vfsmnt;
1217            /* Clear manager flag. */
1218            task->ccs_flags &= ~CCS_TASK_IS_POLICY_MANAGER;
1219            if (ccs_find_execute_handler(ee, CCS_TYPE_EXECUTE_HANDLER)) {
1220                    retval = ccs_try_alt_exec(ee);
1221                    if (!retval)
1222                            ccs_audit_execute_handler_log(ee, true);
1223                    goto ok;
1224            }
1225            retval = ccs_find_next_domain(ee);
1226            if (retval != -EPERM)
1227                    goto ok;
1228            if (ccs_find_execute_handler(ee, CCS_TYPE_DENIED_EXECUTE_HANDLER)) {
1229                    retval = ccs_try_alt_exec(ee);
1230                    if (!retval)
1231                            ccs_audit_execute_handler_log(ee, false);
1232          }          }
1233     ok:
1234            if (retval < 0)
1235                    goto out;
1236            /*
1237             * Proceed to the next domain in order to allow reaching via PID.
1238             * It will be reverted if execve() failed. Reverting is not good.
1239             * But it is better than being unable to reach via PID in interactive
1240             * enforcing mode.
1241             */
1242            task->ccs_domain_info = ee->r.domain;
1243            ee->r.mode = ccs_get_mode(ee->r.domain->profile, CCS_MAC_ENVIRON);
1244            retval = ccs_environ(ee);
1245            if (retval < 0)
1246                    goto out;
1247            task->ccs_flags |= CCS_CHECK_READ_FOR_OPEN_EXEC;
1248            retval = 0;
1249     out:
1250            if (retval)
1251                    ccs_finish_execve(retval);
1252          return retval;          return retval;
1253  }  }
1254    
1255  /***** TOMOYO Linux end. *****/  /**
1256     * ccs_finish_execve - Clean up execve() operation.
1257     *
1258     * @retval: Return code of an execve() operation.
1259     *
1260     * Caller holds ccs_read_lock().
1261     */
1262    void ccs_finish_execve(int retval)
1263    {
1264            struct task_struct *task = current;
1265            struct ccs_execve_entry *ee = NULL;
1266            struct ccs_execve_entry *p;
1267            task->ccs_flags &= ~CCS_CHECK_READ_FOR_OPEN_EXEC;
1268            spin_lock(&ccs_execve_list_lock);
1269            list_for_each_entry(p, &ccs_execve_list, list) {
1270                    if (p->task != task)
1271                            continue;
1272                    ee = p;
1273                    break;
1274            }
1275            spin_unlock(&ccs_execve_list_lock);
1276            if (!ee)
1277                    return;
1278            if (retval < 0) {
1279                    task->ccs_domain_info = ee->previous_domain;
1280                    goto out;
1281            }
1282            /* Mark the current process as execute handler. */
1283            if (ee->handler)
1284                    task->ccs_flags |= CCS_TASK_IS_EXECUTE_HANDLER;
1285            /* Mark the current process as normal process. */
1286            else
1287                    task->ccs_flags &= ~CCS_TASK_IS_EXECUTE_HANDLER;
1288     out:
1289            ccs_free_execve_entry(ee);
1290    }

Legend:
Removed from v.502  
changed lines
  Added in v.2975

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