Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * security/tomoyo/domain.c
0004  *
0005  * Copyright (C) 2005-2011  NTT DATA CORPORATION
0006  */
0007 
0008 #include "common.h"
0009 
0010 #include <linux/binfmts.h>
0011 #include <linux/slab.h>
0012 #include <linux/rculist.h>
0013 
0014 /* Variables definitions.*/
0015 
0016 /* The initial domain. */
0017 struct tomoyo_domain_info tomoyo_kernel_domain;
0018 
0019 /**
0020  * tomoyo_update_policy - Update an entry for exception policy.
0021  *
0022  * @new_entry:       Pointer to "struct tomoyo_acl_info".
0023  * @size:            Size of @new_entry in bytes.
0024  * @param:           Pointer to "struct tomoyo_acl_param".
0025  * @check_duplicate: Callback function to find duplicated entry.
0026  *
0027  * Returns 0 on success, negative value otherwise.
0028  *
0029  * Caller holds tomoyo_read_lock().
0030  */
0031 int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
0032              struct tomoyo_acl_param *param,
0033              bool (*check_duplicate)(const struct tomoyo_acl_head
0034                          *,
0035                          const struct tomoyo_acl_head
0036                          *))
0037 {
0038     int error = param->is_delete ? -ENOENT : -ENOMEM;
0039     struct tomoyo_acl_head *entry;
0040     struct list_head *list = param->list;
0041 
0042     if (mutex_lock_interruptible(&tomoyo_policy_lock))
0043         return -ENOMEM;
0044     list_for_each_entry_rcu(entry, list, list,
0045                 srcu_read_lock_held(&tomoyo_ss)) {
0046         if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
0047             continue;
0048         if (!check_duplicate(entry, new_entry))
0049             continue;
0050         entry->is_deleted = param->is_delete;
0051         error = 0;
0052         break;
0053     }
0054     if (error && !param->is_delete) {
0055         entry = tomoyo_commit_ok(new_entry, size);
0056         if (entry) {
0057             list_add_tail_rcu(&entry->list, list);
0058             error = 0;
0059         }
0060     }
0061     mutex_unlock(&tomoyo_policy_lock);
0062     return error;
0063 }
0064 
0065 /**
0066  * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
0067  *
0068  * @a: Pointer to "struct tomoyo_acl_info".
0069  * @b: Pointer to "struct tomoyo_acl_info".
0070  *
0071  * Returns true if @a == @b, false otherwise.
0072  */
0073 static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
0074                     const struct tomoyo_acl_info *b)
0075 {
0076     return a->type == b->type && a->cond == b->cond;
0077 }
0078 
0079 /**
0080  * tomoyo_update_domain - Update an entry for domain policy.
0081  *
0082  * @new_entry:       Pointer to "struct tomoyo_acl_info".
0083  * @size:            Size of @new_entry in bytes.
0084  * @param:           Pointer to "struct tomoyo_acl_param".
0085  * @check_duplicate: Callback function to find duplicated entry.
0086  * @merge_duplicate: Callback function to merge duplicated entry.
0087  *
0088  * Returns 0 on success, negative value otherwise.
0089  *
0090  * Caller holds tomoyo_read_lock().
0091  */
0092 int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
0093              struct tomoyo_acl_param *param,
0094              bool (*check_duplicate)(const struct tomoyo_acl_info
0095                          *,
0096                          const struct tomoyo_acl_info
0097                          *),
0098              bool (*merge_duplicate)(struct tomoyo_acl_info *,
0099                          struct tomoyo_acl_info *,
0100                          const bool))
0101 {
0102     const bool is_delete = param->is_delete;
0103     int error = is_delete ? -ENOENT : -ENOMEM;
0104     struct tomoyo_acl_info *entry;
0105     struct list_head * const list = param->list;
0106 
0107     if (param->data[0]) {
0108         new_entry->cond = tomoyo_get_condition(param);
0109         if (!new_entry->cond)
0110             return -EINVAL;
0111         /*
0112          * Domain transition preference is allowed for only
0113          * "file execute" entries.
0114          */
0115         if (new_entry->cond->transit &&
0116             !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
0117               container_of(new_entry, struct tomoyo_path_acl, head)
0118               ->perm == 1 << TOMOYO_TYPE_EXECUTE))
0119             goto out;
0120     }
0121     if (mutex_lock_interruptible(&tomoyo_policy_lock))
0122         goto out;
0123     list_for_each_entry_rcu(entry, list, list,
0124                 srcu_read_lock_held(&tomoyo_ss)) {
0125         if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
0126             continue;
0127         if (!tomoyo_same_acl_head(entry, new_entry) ||
0128             !check_duplicate(entry, new_entry))
0129             continue;
0130         if (merge_duplicate)
0131             entry->is_deleted = merge_duplicate(entry, new_entry,
0132                                 is_delete);
0133         else
0134             entry->is_deleted = is_delete;
0135         error = 0;
0136         break;
0137     }
0138     if (error && !is_delete) {
0139         entry = tomoyo_commit_ok(new_entry, size);
0140         if (entry) {
0141             list_add_tail_rcu(&entry->list, list);
0142             error = 0;
0143         }
0144     }
0145     mutex_unlock(&tomoyo_policy_lock);
0146 out:
0147     tomoyo_put_condition(new_entry->cond);
0148     return error;
0149 }
0150 
0151 /**
0152  * tomoyo_check_acl - Do permission check.
0153  *
0154  * @r:           Pointer to "struct tomoyo_request_info".
0155  * @check_entry: Callback function to check type specific parameters.
0156  *
0157  * Returns 0 on success, negative value otherwise.
0158  *
0159  * Caller holds tomoyo_read_lock().
0160  */
0161 void tomoyo_check_acl(struct tomoyo_request_info *r,
0162               bool (*check_entry)(struct tomoyo_request_info *,
0163                       const struct tomoyo_acl_info *))
0164 {
0165     const struct tomoyo_domain_info *domain = r->domain;
0166     struct tomoyo_acl_info *ptr;
0167     const struct list_head *list = &domain->acl_info_list;
0168     u16 i = 0;
0169 
0170 retry:
0171     list_for_each_entry_rcu(ptr, list, list,
0172                 srcu_read_lock_held(&tomoyo_ss)) {
0173         if (ptr->is_deleted || ptr->type != r->param_type)
0174             continue;
0175         if (!check_entry(r, ptr))
0176             continue;
0177         if (!tomoyo_condition(r, ptr->cond))
0178             continue;
0179         r->matched_acl = ptr;
0180         r->granted = true;
0181         return;
0182     }
0183     for (; i < TOMOYO_MAX_ACL_GROUPS; i++) {
0184         if (!test_bit(i, domain->group))
0185             continue;
0186         list = &domain->ns->acl_group[i++];
0187         goto retry;
0188     }
0189     r->granted = false;
0190 }
0191 
0192 /* The list for "struct tomoyo_domain_info". */
0193 LIST_HEAD(tomoyo_domain_list);
0194 
0195 /**
0196  * tomoyo_last_word - Get last component of a domainname.
0197  *
0198  * @name: Domainname to check.
0199  *
0200  * Returns the last word of @domainname.
0201  */
0202 static const char *tomoyo_last_word(const char *name)
0203 {
0204     const char *cp = strrchr(name, ' ');
0205 
0206     if (cp)
0207         return cp + 1;
0208     return name;
0209 }
0210 
0211 /**
0212  * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
0213  *
0214  * @a: Pointer to "struct tomoyo_acl_head".
0215  * @b: Pointer to "struct tomoyo_acl_head".
0216  *
0217  * Returns true if @a == @b, false otherwise.
0218  */
0219 static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
0220                        const struct tomoyo_acl_head *b)
0221 {
0222     const struct tomoyo_transition_control *p1 = container_of(a,
0223                                   typeof(*p1),
0224                                   head);
0225     const struct tomoyo_transition_control *p2 = container_of(b,
0226                                   typeof(*p2),
0227                                   head);
0228 
0229     return p1->type == p2->type && p1->is_last_name == p2->is_last_name
0230         && p1->domainname == p2->domainname
0231         && p1->program == p2->program;
0232 }
0233 
0234 /**
0235  * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
0236  *
0237  * @param: Pointer to "struct tomoyo_acl_param".
0238  * @type:  Type of this entry.
0239  *
0240  * Returns 0 on success, negative value otherwise.
0241  */
0242 int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
0243                     const u8 type)
0244 {
0245     struct tomoyo_transition_control e = { .type = type };
0246     int error = param->is_delete ? -ENOENT : -ENOMEM;
0247     char *program = param->data;
0248     char *domainname = strstr(program, " from ");
0249 
0250     if (domainname) {
0251         *domainname = '\0';
0252         domainname += 6;
0253     } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
0254            type == TOMOYO_TRANSITION_CONTROL_KEEP) {
0255         domainname = program;
0256         program = NULL;
0257     }
0258     if (program && strcmp(program, "any")) {
0259         if (!tomoyo_correct_path(program))
0260             return -EINVAL;
0261         e.program = tomoyo_get_name(program);
0262         if (!e.program)
0263             goto out;
0264     }
0265     if (domainname && strcmp(domainname, "any")) {
0266         if (!tomoyo_correct_domain(domainname)) {
0267             if (!tomoyo_correct_path(domainname))
0268                 goto out;
0269             e.is_last_name = true;
0270         }
0271         e.domainname = tomoyo_get_name(domainname);
0272         if (!e.domainname)
0273             goto out;
0274     }
0275     param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
0276     error = tomoyo_update_policy(&e.head, sizeof(e), param,
0277                      tomoyo_same_transition_control);
0278 out:
0279     tomoyo_put_name(e.domainname);
0280     tomoyo_put_name(e.program);
0281     return error;
0282 }
0283 
0284 /**
0285  * tomoyo_scan_transition - Try to find specific domain transition type.
0286  *
0287  * @list:       Pointer to "struct list_head".
0288  * @domainname: The name of current domain.
0289  * @program:    The name of requested program.
0290  * @last_name:  The last component of @domainname.
0291  * @type:       One of values in "enum tomoyo_transition_type".
0292  *
0293  * Returns true if found one, false otherwise.
0294  *
0295  * Caller holds tomoyo_read_lock().
0296  */
0297 static inline bool tomoyo_scan_transition
0298 (const struct list_head *list, const struct tomoyo_path_info *domainname,
0299  const struct tomoyo_path_info *program, const char *last_name,
0300  const enum tomoyo_transition_type type)
0301 {
0302     const struct tomoyo_transition_control *ptr;
0303 
0304     list_for_each_entry_rcu(ptr, list, head.list,
0305                 srcu_read_lock_held(&tomoyo_ss)) {
0306         if (ptr->head.is_deleted || ptr->type != type)
0307             continue;
0308         if (ptr->domainname) {
0309             if (!ptr->is_last_name) {
0310                 if (ptr->domainname != domainname)
0311                     continue;
0312             } else {
0313                 /*
0314                  * Use direct strcmp() since this is
0315                  * unlikely used.
0316                  */
0317                 if (strcmp(ptr->domainname->name, last_name))
0318                     continue;
0319             }
0320         }
0321         if (ptr->program && tomoyo_pathcmp(ptr->program, program))
0322             continue;
0323         return true;
0324     }
0325     return false;
0326 }
0327 
0328 /**
0329  * tomoyo_transition_type - Get domain transition type.
0330  *
0331  * @ns:         Pointer to "struct tomoyo_policy_namespace".
0332  * @domainname: The name of current domain.
0333  * @program:    The name of requested program.
0334  *
0335  * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
0336  * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
0337  * executing @program reinitializes domain transition within that namespace,
0338  * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
0339  * others otherwise.
0340  *
0341  * Caller holds tomoyo_read_lock().
0342  */
0343 static enum tomoyo_transition_type tomoyo_transition_type
0344 (const struct tomoyo_policy_namespace *ns,
0345  const struct tomoyo_path_info *domainname,
0346  const struct tomoyo_path_info *program)
0347 {
0348     const char *last_name = tomoyo_last_word(domainname->name);
0349     enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
0350 
0351     while (type < TOMOYO_MAX_TRANSITION_TYPE) {
0352         const struct list_head * const list =
0353             &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
0354 
0355         if (!tomoyo_scan_transition(list, domainname, program,
0356                         last_name, type)) {
0357             type++;
0358             continue;
0359         }
0360         if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
0361             type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
0362             break;
0363         /*
0364          * Do not check for reset_domain if no_reset_domain matched.
0365          * Do not check for initialize_domain if no_initialize_domain
0366          * matched.
0367          */
0368         type++;
0369         type++;
0370     }
0371     return type;
0372 }
0373 
0374 /**
0375  * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
0376  *
0377  * @a: Pointer to "struct tomoyo_acl_head".
0378  * @b: Pointer to "struct tomoyo_acl_head".
0379  *
0380  * Returns true if @a == @b, false otherwise.
0381  */
0382 static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
0383                    const struct tomoyo_acl_head *b)
0384 {
0385     const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
0386                               head);
0387     const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
0388                               head);
0389 
0390     return p1->original_name == p2->original_name &&
0391         p1->aggregated_name == p2->aggregated_name;
0392 }
0393 
0394 /**
0395  * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
0396  *
0397  * @param: Pointer to "struct tomoyo_acl_param".
0398  *
0399  * Returns 0 on success, negative value otherwise.
0400  *
0401  * Caller holds tomoyo_read_lock().
0402  */
0403 int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
0404 {
0405     struct tomoyo_aggregator e = { };
0406     int error = param->is_delete ? -ENOENT : -ENOMEM;
0407     const char *original_name = tomoyo_read_token(param);
0408     const char *aggregated_name = tomoyo_read_token(param);
0409 
0410     if (!tomoyo_correct_word(original_name) ||
0411         !tomoyo_correct_path(aggregated_name))
0412         return -EINVAL;
0413     e.original_name = tomoyo_get_name(original_name);
0414     e.aggregated_name = tomoyo_get_name(aggregated_name);
0415     if (!e.original_name || !e.aggregated_name ||
0416         e.aggregated_name->is_patterned) /* No patterns allowed. */
0417         goto out;
0418     param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
0419     error = tomoyo_update_policy(&e.head, sizeof(e), param,
0420                      tomoyo_same_aggregator);
0421 out:
0422     tomoyo_put_name(e.original_name);
0423     tomoyo_put_name(e.aggregated_name);
0424     return error;
0425 }
0426 
0427 /**
0428  * tomoyo_find_namespace - Find specified namespace.
0429  *
0430  * @name: Name of namespace to find.
0431  * @len:  Length of @name.
0432  *
0433  * Returns pointer to "struct tomoyo_policy_namespace" if found,
0434  * NULL otherwise.
0435  *
0436  * Caller holds tomoyo_read_lock().
0437  */
0438 static struct tomoyo_policy_namespace *tomoyo_find_namespace
0439 (const char *name, const unsigned int len)
0440 {
0441     struct tomoyo_policy_namespace *ns;
0442 
0443     list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
0444         if (strncmp(name, ns->name, len) ||
0445             (name[len] && name[len] != ' '))
0446             continue;
0447         return ns;
0448     }
0449     return NULL;
0450 }
0451 
0452 /**
0453  * tomoyo_assign_namespace - Create a new namespace.
0454  *
0455  * @domainname: Name of namespace to create.
0456  *
0457  * Returns pointer to "struct tomoyo_policy_namespace" on success,
0458  * NULL otherwise.
0459  *
0460  * Caller holds tomoyo_read_lock().
0461  */
0462 struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
0463 {
0464     struct tomoyo_policy_namespace *ptr;
0465     struct tomoyo_policy_namespace *entry;
0466     const char *cp = domainname;
0467     unsigned int len = 0;
0468 
0469     while (*cp && *cp++ != ' ')
0470         len++;
0471     ptr = tomoyo_find_namespace(domainname, len);
0472     if (ptr)
0473         return ptr;
0474     if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
0475         return NULL;
0476     entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS | __GFP_NOWARN);
0477     if (mutex_lock_interruptible(&tomoyo_policy_lock))
0478         goto out;
0479     ptr = tomoyo_find_namespace(domainname, len);
0480     if (!ptr && tomoyo_memory_ok(entry)) {
0481         char *name = (char *) (entry + 1);
0482 
0483         ptr = entry;
0484         memmove(name, domainname, len);
0485         name[len] = '\0';
0486         entry->name = name;
0487         tomoyo_init_policy_namespace(entry);
0488         entry = NULL;
0489     }
0490     mutex_unlock(&tomoyo_policy_lock);
0491 out:
0492     kfree(entry);
0493     return ptr;
0494 }
0495 
0496 /**
0497  * tomoyo_namespace_jump - Check for namespace jump.
0498  *
0499  * @domainname: Name of domain.
0500  *
0501  * Returns true if namespace differs, false otherwise.
0502  */
0503 static bool tomoyo_namespace_jump(const char *domainname)
0504 {
0505     const char *namespace = tomoyo_current_namespace()->name;
0506     const int len = strlen(namespace);
0507 
0508     return strncmp(domainname, namespace, len) ||
0509         (domainname[len] && domainname[len] != ' ');
0510 }
0511 
0512 /**
0513  * tomoyo_assign_domain - Create a domain or a namespace.
0514  *
0515  * @domainname: The name of domain.
0516  * @transit:    True if transit to domain found or created.
0517  *
0518  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
0519  *
0520  * Caller holds tomoyo_read_lock().
0521  */
0522 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
0523                         const bool transit)
0524 {
0525     struct tomoyo_domain_info e = { };
0526     struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
0527     bool created = false;
0528 
0529     if (entry) {
0530         if (transit) {
0531             /*
0532              * Since namespace is created at runtime, profiles may
0533              * not be created by the moment the process transits to
0534              * that domain. Do not perform domain transition if
0535              * profile for that domain is not yet created.
0536              */
0537             if (tomoyo_policy_loaded &&
0538                 !entry->ns->profile_ptr[entry->profile])
0539                 return NULL;
0540         }
0541         return entry;
0542     }
0543     /* Requested domain does not exist. */
0544     /* Don't create requested domain if domainname is invalid. */
0545     if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
0546         !tomoyo_correct_domain(domainname))
0547         return NULL;
0548     /*
0549      * Since definition of profiles and acl_groups may differ across
0550      * namespaces, do not inherit "use_profile" and "use_group" settings
0551      * by automatically creating requested domain upon domain transition.
0552      */
0553     if (transit && tomoyo_namespace_jump(domainname))
0554         return NULL;
0555     e.ns = tomoyo_assign_namespace(domainname);
0556     if (!e.ns)
0557         return NULL;
0558     /*
0559      * "use_profile" and "use_group" settings for automatically created
0560      * domains are inherited from current domain. These are 0 for manually
0561      * created domains.
0562      */
0563     if (transit) {
0564         const struct tomoyo_domain_info *domain = tomoyo_domain();
0565 
0566         e.profile = domain->profile;
0567         memcpy(e.group, domain->group, sizeof(e.group));
0568     }
0569     e.domainname = tomoyo_get_name(domainname);
0570     if (!e.domainname)
0571         return NULL;
0572     if (mutex_lock_interruptible(&tomoyo_policy_lock))
0573         goto out;
0574     entry = tomoyo_find_domain(domainname);
0575     if (!entry) {
0576         entry = tomoyo_commit_ok(&e, sizeof(e));
0577         if (entry) {
0578             INIT_LIST_HEAD(&entry->acl_info_list);
0579             list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
0580             created = true;
0581         }
0582     }
0583     mutex_unlock(&tomoyo_policy_lock);
0584 out:
0585     tomoyo_put_name(e.domainname);
0586     if (entry && transit) {
0587         if (created) {
0588             struct tomoyo_request_info r;
0589             int i;
0590 
0591             tomoyo_init_request_info(&r, entry,
0592                          TOMOYO_MAC_FILE_EXECUTE);
0593             r.granted = false;
0594             tomoyo_write_log(&r, "use_profile %u\n",
0595                      entry->profile);
0596             for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
0597                 if (test_bit(i, entry->group))
0598                     tomoyo_write_log(&r, "use_group %u\n",
0599                              i);
0600             tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
0601         }
0602     }
0603     return entry;
0604 }
0605 
0606 /**
0607  * tomoyo_environ - Check permission for environment variable names.
0608  *
0609  * @ee: Pointer to "struct tomoyo_execve".
0610  *
0611  * Returns 0 on success, negative value otherwise.
0612  */
0613 static int tomoyo_environ(struct tomoyo_execve *ee)
0614 {
0615     struct tomoyo_request_info *r = &ee->r;
0616     struct linux_binprm *bprm = ee->bprm;
0617     /* env_page.data is allocated by tomoyo_dump_page(). */
0618     struct tomoyo_page_dump env_page = { };
0619     char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
0620     int arg_len = 0;
0621     unsigned long pos = bprm->p;
0622     int offset = pos % PAGE_SIZE;
0623     int argv_count = bprm->argc;
0624     int envp_count = bprm->envc;
0625     int error = -ENOMEM;
0626 
0627     ee->r.type = TOMOYO_MAC_ENVIRON;
0628     ee->r.profile = r->domain->profile;
0629     ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
0630                      TOMOYO_MAC_ENVIRON);
0631     if (!r->mode || !envp_count)
0632         return 0;
0633     arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
0634     if (!arg_ptr)
0635         goto out;
0636     while (error == -ENOMEM) {
0637         if (!tomoyo_dump_page(bprm, pos, &env_page))
0638             goto out;
0639         pos += PAGE_SIZE - offset;
0640         /* Read. */
0641         while (argv_count && offset < PAGE_SIZE) {
0642             if (!env_page.data[offset++])
0643                 argv_count--;
0644         }
0645         if (argv_count) {
0646             offset = 0;
0647             continue;
0648         }
0649         while (offset < PAGE_SIZE) {
0650             const unsigned char c = env_page.data[offset++];
0651 
0652             if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
0653                 if (c == '=') {
0654                     arg_ptr[arg_len++] = '\0';
0655                 } else if (c == '\\') {
0656                     arg_ptr[arg_len++] = '\\';
0657                     arg_ptr[arg_len++] = '\\';
0658                 } else if (c > ' ' && c < 127) {
0659                     arg_ptr[arg_len++] = c;
0660                 } else {
0661                     arg_ptr[arg_len++] = '\\';
0662                     arg_ptr[arg_len++] = (c >> 6) + '0';
0663                     arg_ptr[arg_len++]
0664                         = ((c >> 3) & 7) + '0';
0665                     arg_ptr[arg_len++] = (c & 7) + '0';
0666                 }
0667             } else {
0668                 arg_ptr[arg_len] = '\0';
0669             }
0670             if (c)
0671                 continue;
0672             if (tomoyo_env_perm(r, arg_ptr)) {
0673                 error = -EPERM;
0674                 break;
0675             }
0676             if (!--envp_count) {
0677                 error = 0;
0678                 break;
0679             }
0680             arg_len = 0;
0681         }
0682         offset = 0;
0683     }
0684 out:
0685     if (r->mode != TOMOYO_CONFIG_ENFORCING)
0686         error = 0;
0687     kfree(env_page.data);
0688     kfree(arg_ptr);
0689     return error;
0690 }
0691 
0692 /**
0693  * tomoyo_find_next_domain - Find a domain.
0694  *
0695  * @bprm: Pointer to "struct linux_binprm".
0696  *
0697  * Returns 0 on success, negative value otherwise.
0698  *
0699  * Caller holds tomoyo_read_lock().
0700  */
0701 int tomoyo_find_next_domain(struct linux_binprm *bprm)
0702 {
0703     struct tomoyo_domain_info *old_domain = tomoyo_domain();
0704     struct tomoyo_domain_info *domain = NULL;
0705     const char *original_name = bprm->filename;
0706     int retval = -ENOMEM;
0707     bool reject_on_transition_failure = false;
0708     const struct tomoyo_path_info *candidate;
0709     struct tomoyo_path_info exename;
0710     struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
0711 
0712     if (!ee)
0713         return -ENOMEM;
0714     ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
0715     if (!ee->tmp) {
0716         kfree(ee);
0717         return -ENOMEM;
0718     }
0719     /* ee->dump->data is allocated by tomoyo_dump_page(). */
0720     tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
0721     ee->r.ee = ee;
0722     ee->bprm = bprm;
0723     ee->r.obj = &ee->obj;
0724     ee->obj.path1 = bprm->file->f_path;
0725     /* Get symlink's pathname of program. */
0726     retval = -ENOENT;
0727     exename.name = tomoyo_realpath_nofollow(original_name);
0728     if (!exename.name)
0729         goto out;
0730     tomoyo_fill_path_info(&exename);
0731 retry:
0732     /* Check 'aggregator' directive. */
0733     {
0734         struct tomoyo_aggregator *ptr;
0735         struct list_head *list =
0736             &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
0737 
0738         /* Check 'aggregator' directive. */
0739         candidate = &exename;
0740         list_for_each_entry_rcu(ptr, list, head.list,
0741                     srcu_read_lock_held(&tomoyo_ss)) {
0742             if (ptr->head.is_deleted ||
0743                 !tomoyo_path_matches_pattern(&exename,
0744                              ptr->original_name))
0745                 continue;
0746             candidate = ptr->aggregated_name;
0747             break;
0748         }
0749     }
0750 
0751     /* Check execute permission. */
0752     retval = tomoyo_execute_permission(&ee->r, candidate);
0753     if (retval == TOMOYO_RETRY_REQUEST)
0754         goto retry;
0755     if (retval < 0)
0756         goto out;
0757     /*
0758      * To be able to specify domainnames with wildcards, use the
0759      * pathname specified in the policy (which may contain
0760      * wildcard) rather than the pathname passed to execve()
0761      * (which never contains wildcard).
0762      */
0763     if (ee->r.param.path.matched_path)
0764         candidate = ee->r.param.path.matched_path;
0765 
0766     /*
0767      * Check for domain transition preference if "file execute" matched.
0768      * If preference is given, make execve() fail if domain transition
0769      * has failed, for domain transition preference should be used with
0770      * destination domain defined.
0771      */
0772     if (ee->transition) {
0773         const char *domainname = ee->transition->name;
0774 
0775         reject_on_transition_failure = true;
0776         if (!strcmp(domainname, "keep"))
0777             goto force_keep_domain;
0778         if (!strcmp(domainname, "child"))
0779             goto force_child_domain;
0780         if (!strcmp(domainname, "reset"))
0781             goto force_reset_domain;
0782         if (!strcmp(domainname, "initialize"))
0783             goto force_initialize_domain;
0784         if (!strcmp(domainname, "parent")) {
0785             char *cp;
0786 
0787             strncpy(ee->tmp, old_domain->domainname->name,
0788                 TOMOYO_EXEC_TMPSIZE - 1);
0789             cp = strrchr(ee->tmp, ' ');
0790             if (cp)
0791                 *cp = '\0';
0792         } else if (*domainname == '<')
0793             strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
0794         else
0795             snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
0796                  old_domain->domainname->name, domainname);
0797         goto force_jump_domain;
0798     }
0799     /*
0800      * No domain transition preference specified.
0801      * Calculate domain to transit to.
0802      */
0803     switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
0804                        candidate)) {
0805     case TOMOYO_TRANSITION_CONTROL_RESET:
0806 force_reset_domain:
0807         /* Transit to the root of specified namespace. */
0808         snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
0809              candidate->name);
0810         /*
0811          * Make execve() fail if domain transition across namespaces
0812          * has failed.
0813          */
0814         reject_on_transition_failure = true;
0815         break;
0816     case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
0817 force_initialize_domain:
0818         /* Transit to the child of current namespace's root. */
0819         snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
0820              old_domain->ns->name, candidate->name);
0821         break;
0822     case TOMOYO_TRANSITION_CONTROL_KEEP:
0823 force_keep_domain:
0824         /* Keep current domain. */
0825         domain = old_domain;
0826         break;
0827     default:
0828         if (old_domain == &tomoyo_kernel_domain &&
0829             !tomoyo_policy_loaded) {
0830             /*
0831              * Needn't to transit from kernel domain before
0832              * starting /sbin/init. But transit from kernel domain
0833              * if executing initializers because they might start
0834              * before /sbin/init.
0835              */
0836             domain = old_domain;
0837             break;
0838         }
0839 force_child_domain:
0840         /* Normal domain transition. */
0841         snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
0842              old_domain->domainname->name, candidate->name);
0843         break;
0844     }
0845 force_jump_domain:
0846     if (!domain)
0847         domain = tomoyo_assign_domain(ee->tmp, true);
0848     if (domain)
0849         retval = 0;
0850     else if (reject_on_transition_failure) {
0851         pr_warn("ERROR: Domain '%s' not ready.\n", ee->tmp);
0852         retval = -ENOMEM;
0853     } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
0854         retval = -ENOMEM;
0855     else {
0856         retval = 0;
0857         if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
0858             old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
0859             ee->r.granted = false;
0860             tomoyo_write_log(&ee->r, "%s", tomoyo_dif
0861                      [TOMOYO_DIF_TRANSITION_FAILED]);
0862             pr_warn("ERROR: Domain '%s' not defined.\n", ee->tmp);
0863         }
0864     }
0865  out:
0866     if (!domain)
0867         domain = old_domain;
0868     /* Update reference count on "struct tomoyo_domain_info". */
0869     {
0870         struct tomoyo_task *s = tomoyo_task(current);
0871 
0872         s->old_domain_info = s->domain_info;
0873         s->domain_info = domain;
0874         atomic_inc(&domain->users);
0875     }
0876     kfree(exename.name);
0877     if (!retval) {
0878         ee->r.domain = domain;
0879         retval = tomoyo_environ(ee);
0880     }
0881     kfree(ee->tmp);
0882     kfree(ee->dump.data);
0883     kfree(ee);
0884     return retval;
0885 }
0886 
0887 /**
0888  * tomoyo_dump_page - Dump a page to buffer.
0889  *
0890  * @bprm: Pointer to "struct linux_binprm".
0891  * @pos:  Location to dump.
0892  * @dump: Pointer to "struct tomoyo_page_dump".
0893  *
0894  * Returns true on success, false otherwise.
0895  */
0896 bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
0897               struct tomoyo_page_dump *dump)
0898 {
0899     struct page *page;
0900 #ifdef CONFIG_MMU
0901     int ret;
0902 #endif
0903 
0904     /* dump->data is released by tomoyo_find_next_domain(). */
0905     if (!dump->data) {
0906         dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
0907         if (!dump->data)
0908             return false;
0909     }
0910     /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
0911 #ifdef CONFIG_MMU
0912     /*
0913      * This is called at execve() time in order to dig around
0914      * in the argv/environment of the new proceess
0915      * (represented by bprm).
0916      */
0917     mmap_read_lock(bprm->mm);
0918     ret = get_user_pages_remote(bprm->mm, pos, 1,
0919                     FOLL_FORCE, &page, NULL, NULL);
0920     mmap_read_unlock(bprm->mm);
0921     if (ret <= 0)
0922         return false;
0923 #else
0924     page = bprm->page[pos / PAGE_SIZE];
0925 #endif
0926     if (page != dump->page) {
0927         const unsigned int offset = pos % PAGE_SIZE;
0928         /*
0929          * Maybe kmap()/kunmap() should be used here.
0930          * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
0931          * So do I.
0932          */
0933         char *kaddr = kmap_atomic(page);
0934 
0935         dump->page = page;
0936         memcpy(dump->data + offset, kaddr + offset,
0937                PAGE_SIZE - offset);
0938         kunmap_atomic(kaddr);
0939     }
0940     /* Same with put_arg_page(page) in fs/exec.c */
0941 #ifdef CONFIG_MMU
0942     put_page(page);
0943 #endif
0944     return true;
0945 }