linux/security/tomoyo/domain.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * security/tomoyo/domain.c
   4 *
   5 * Copyright (C) 2005-2011  NTT DATA CORPORATION
   6 */
   7
   8#include "common.h"
   9
  10#include <linux/binfmts.h>
  11#include <linux/slab.h>
  12#include <linux/rculist.h>
  13
  14/* Variables definitions.*/
  15
  16/* The initial domain. */
  17struct tomoyo_domain_info tomoyo_kernel_domain;
  18
  19/**
  20 * tomoyo_update_policy - Update an entry for exception policy.
  21 *
  22 * @new_entry:       Pointer to "struct tomoyo_acl_info".
  23 * @size:            Size of @new_entry in bytes.
  24 * @param:           Pointer to "struct tomoyo_acl_param".
  25 * @check_duplicate: Callback function to find duplicated entry.
  26 *
  27 * Returns 0 on success, negative value otherwise.
  28 *
  29 * Caller holds tomoyo_read_lock().
  30 */
  31int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
  32                         struct tomoyo_acl_param *param,
  33                         bool (*check_duplicate)(const struct tomoyo_acl_head
  34                                                 *,
  35                                                 const struct tomoyo_acl_head
  36                                                 *))
  37{
  38        int error = param->is_delete ? -ENOENT : -ENOMEM;
  39        struct tomoyo_acl_head *entry;
  40        struct list_head *list = param->list;
  41
  42        if (mutex_lock_interruptible(&tomoyo_policy_lock))
  43                return -ENOMEM;
  44        list_for_each_entry_rcu(entry, list, list) {
  45                if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
  46                        continue;
  47                if (!check_duplicate(entry, new_entry))
  48                        continue;
  49                entry->is_deleted = param->is_delete;
  50                error = 0;
  51                break;
  52        }
  53        if (error && !param->is_delete) {
  54                entry = tomoyo_commit_ok(new_entry, size);
  55                if (entry) {
  56                        list_add_tail_rcu(&entry->list, list);
  57                        error = 0;
  58                }
  59        }
  60        mutex_unlock(&tomoyo_policy_lock);
  61        return error;
  62}
  63
  64/**
  65 * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
  66 *
  67 * @a: Pointer to "struct tomoyo_acl_info".
  68 * @b: Pointer to "struct tomoyo_acl_info".
  69 *
  70 * Returns true if @a == @b, false otherwise.
  71 */
  72static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
  73                                        const struct tomoyo_acl_info *b)
  74{
  75        return a->type == b->type && a->cond == b->cond;
  76}
  77
  78/**
  79 * tomoyo_update_domain - Update an entry for domain policy.
  80 *
  81 * @new_entry:       Pointer to "struct tomoyo_acl_info".
  82 * @size:            Size of @new_entry in bytes.
  83 * @param:           Pointer to "struct tomoyo_acl_param".
  84 * @check_duplicate: Callback function to find duplicated entry.
  85 * @merge_duplicate: Callback function to merge duplicated entry.
  86 *
  87 * Returns 0 on success, negative value otherwise.
  88 *
  89 * Caller holds tomoyo_read_lock().
  90 */
  91int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
  92                         struct tomoyo_acl_param *param,
  93                         bool (*check_duplicate)(const struct tomoyo_acl_info
  94                                                 *,
  95                                                 const struct tomoyo_acl_info
  96                                                 *),
  97                         bool (*merge_duplicate)(struct tomoyo_acl_info *,
  98                                                 struct tomoyo_acl_info *,
  99                                                 const bool))
 100{
 101        const bool is_delete = param->is_delete;
 102        int error = is_delete ? -ENOENT : -ENOMEM;
 103        struct tomoyo_acl_info *entry;
 104        struct list_head * const list = param->list;
 105
 106        if (param->data[0]) {
 107                new_entry->cond = tomoyo_get_condition(param);
 108                if (!new_entry->cond)
 109                        return -EINVAL;
 110                /*
 111                 * Domain transition preference is allowed for only
 112                 * "file execute" entries.
 113                 */
 114                if (new_entry->cond->transit &&
 115                    !(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
 116                      container_of(new_entry, struct tomoyo_path_acl, head)
 117                      ->perm == 1 << TOMOYO_TYPE_EXECUTE))
 118                        goto out;
 119        }
 120        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 121                goto out;
 122        list_for_each_entry_rcu(entry, list, list) {
 123                if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
 124                        continue;
 125                if (!tomoyo_same_acl_head(entry, new_entry) ||
 126                    !check_duplicate(entry, new_entry))
 127                        continue;
 128                if (merge_duplicate)
 129                        entry->is_deleted = merge_duplicate(entry, new_entry,
 130                                                            is_delete);
 131                else
 132                        entry->is_deleted = is_delete;
 133                error = 0;
 134                break;
 135        }
 136        if (error && !is_delete) {
 137                entry = tomoyo_commit_ok(new_entry, size);
 138                if (entry) {
 139                        list_add_tail_rcu(&entry->list, list);
 140                        error = 0;
 141                }
 142        }
 143        mutex_unlock(&tomoyo_policy_lock);
 144out:
 145        tomoyo_put_condition(new_entry->cond);
 146        return error;
 147}
 148
 149/**
 150 * tomoyo_check_acl - Do permission check.
 151 *
 152 * @r:           Pointer to "struct tomoyo_request_info".
 153 * @check_entry: Callback function to check type specific parameters.
 154 *
 155 * Returns 0 on success, negative value otherwise.
 156 *
 157 * Caller holds tomoyo_read_lock().
 158 */
 159void tomoyo_check_acl(struct tomoyo_request_info *r,
 160                      bool (*check_entry)(struct tomoyo_request_info *,
 161                                          const struct tomoyo_acl_info *))
 162{
 163        const struct tomoyo_domain_info *domain = r->domain;
 164        struct tomoyo_acl_info *ptr;
 165        const struct list_head *list = &domain->acl_info_list;
 166        u16 i = 0;
 167
 168retry:
 169        list_for_each_entry_rcu(ptr, list, list) {
 170                if (ptr->is_deleted || ptr->type != r->param_type)
 171                        continue;
 172                if (!check_entry(r, ptr))
 173                        continue;
 174                if (!tomoyo_condition(r, ptr->cond))
 175                        continue;
 176                r->matched_acl = ptr;
 177                r->granted = true;
 178                return;
 179        }
 180        for (; i < TOMOYO_MAX_ACL_GROUPS; i++) {
 181                if (!test_bit(i, domain->group))
 182                        continue;
 183                list = &domain->ns->acl_group[i++];
 184                goto retry;
 185        }
 186        r->granted = false;
 187}
 188
 189/* The list for "struct tomoyo_domain_info". */
 190LIST_HEAD(tomoyo_domain_list);
 191
 192/**
 193 * tomoyo_last_word - Get last component of a domainname.
 194 *
 195 * @name: Domainname to check.
 196 *
 197 * Returns the last word of @domainname.
 198 */
 199static const char *tomoyo_last_word(const char *name)
 200{
 201        const char *cp = strrchr(name, ' ');
 202
 203        if (cp)
 204                return cp + 1;
 205        return name;
 206}
 207
 208/**
 209 * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
 210 *
 211 * @a: Pointer to "struct tomoyo_acl_head".
 212 * @b: Pointer to "struct tomoyo_acl_head".
 213 *
 214 * Returns true if @a == @b, false otherwise.
 215 */
 216static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
 217                                           const struct tomoyo_acl_head *b)
 218{
 219        const struct tomoyo_transition_control *p1 = container_of(a,
 220                                                                  typeof(*p1),
 221                                                                  head);
 222        const struct tomoyo_transition_control *p2 = container_of(b,
 223                                                                  typeof(*p2),
 224                                                                  head);
 225
 226        return p1->type == p2->type && p1->is_last_name == p2->is_last_name
 227                && p1->domainname == p2->domainname
 228                && p1->program == p2->program;
 229}
 230
 231/**
 232 * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
 233 *
 234 * @param: Pointer to "struct tomoyo_acl_param".
 235 * @type:  Type of this entry.
 236 *
 237 * Returns 0 on success, negative value otherwise.
 238 */
 239int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
 240                                    const u8 type)
 241{
 242        struct tomoyo_transition_control e = { .type = type };
 243        int error = param->is_delete ? -ENOENT : -ENOMEM;
 244        char *program = param->data;
 245        char *domainname = strstr(program, " from ");
 246
 247        if (domainname) {
 248                *domainname = '\0';
 249                domainname += 6;
 250        } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
 251                   type == TOMOYO_TRANSITION_CONTROL_KEEP) {
 252                domainname = program;
 253                program = NULL;
 254        }
 255        if (program && strcmp(program, "any")) {
 256                if (!tomoyo_correct_path(program))
 257                        return -EINVAL;
 258                e.program = tomoyo_get_name(program);
 259                if (!e.program)
 260                        goto out;
 261        }
 262        if (domainname && strcmp(domainname, "any")) {
 263                if (!tomoyo_correct_domain(domainname)) {
 264                        if (!tomoyo_correct_path(domainname))
 265                                goto out;
 266                        e.is_last_name = true;
 267                }
 268                e.domainname = tomoyo_get_name(domainname);
 269                if (!e.domainname)
 270                        goto out;
 271        }
 272        param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
 273        error = tomoyo_update_policy(&e.head, sizeof(e), param,
 274                                     tomoyo_same_transition_control);
 275out:
 276        tomoyo_put_name(e.domainname);
 277        tomoyo_put_name(e.program);
 278        return error;
 279}
 280
 281/**
 282 * tomoyo_scan_transition - Try to find specific domain transition type.
 283 *
 284 * @list:       Pointer to "struct list_head".
 285 * @domainname: The name of current domain.
 286 * @program:    The name of requested program.
 287 * @last_name:  The last component of @domainname.
 288 * @type:       One of values in "enum tomoyo_transition_type".
 289 *
 290 * Returns true if found one, false otherwise.
 291 *
 292 * Caller holds tomoyo_read_lock().
 293 */
 294static inline bool tomoyo_scan_transition
 295(const struct list_head *list, const struct tomoyo_path_info *domainname,
 296 const struct tomoyo_path_info *program, const char *last_name,
 297 const enum tomoyo_transition_type type)
 298{
 299        const struct tomoyo_transition_control *ptr;
 300
 301        list_for_each_entry_rcu(ptr, list, head.list) {
 302                if (ptr->head.is_deleted || ptr->type != type)
 303                        continue;
 304                if (ptr->domainname) {
 305                        if (!ptr->is_last_name) {
 306                                if (ptr->domainname != domainname)
 307                                        continue;
 308                        } else {
 309                                /*
 310                                 * Use direct strcmp() since this is
 311                                 * unlikely used.
 312                                 */
 313                                if (strcmp(ptr->domainname->name, last_name))
 314                                        continue;
 315                        }
 316                }
 317                if (ptr->program && tomoyo_pathcmp(ptr->program, program))
 318                        continue;
 319                return true;
 320        }
 321        return false;
 322}
 323
 324/**
 325 * tomoyo_transition_type - Get domain transition type.
 326 *
 327 * @ns:         Pointer to "struct tomoyo_policy_namespace".
 328 * @domainname: The name of current domain.
 329 * @program:    The name of requested program.
 330 *
 331 * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
 332 * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
 333 * executing @program reinitializes domain transition within that namespace,
 334 * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
 335 * others otherwise.
 336 *
 337 * Caller holds tomoyo_read_lock().
 338 */
 339static enum tomoyo_transition_type tomoyo_transition_type
 340(const struct tomoyo_policy_namespace *ns,
 341 const struct tomoyo_path_info *domainname,
 342 const struct tomoyo_path_info *program)
 343{
 344        const char *last_name = tomoyo_last_word(domainname->name);
 345        enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
 346
 347        while (type < TOMOYO_MAX_TRANSITION_TYPE) {
 348                const struct list_head * const list =
 349                        &ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
 350
 351                if (!tomoyo_scan_transition(list, domainname, program,
 352                                            last_name, type)) {
 353                        type++;
 354                        continue;
 355                }
 356                if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
 357                    type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
 358                        break;
 359                /*
 360                 * Do not check for reset_domain if no_reset_domain matched.
 361                 * Do not check for initialize_domain if no_initialize_domain
 362                 * matched.
 363                 */
 364                type++;
 365                type++;
 366        }
 367        return type;
 368}
 369
 370/**
 371 * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
 372 *
 373 * @a: Pointer to "struct tomoyo_acl_head".
 374 * @b: Pointer to "struct tomoyo_acl_head".
 375 *
 376 * Returns true if @a == @b, false otherwise.
 377 */
 378static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
 379                                   const struct tomoyo_acl_head *b)
 380{
 381        const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
 382                                                          head);
 383        const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
 384                                                          head);
 385
 386        return p1->original_name == p2->original_name &&
 387                p1->aggregated_name == p2->aggregated_name;
 388}
 389
 390/**
 391 * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
 392 *
 393 * @param: Pointer to "struct tomoyo_acl_param".
 394 *
 395 * Returns 0 on success, negative value otherwise.
 396 *
 397 * Caller holds tomoyo_read_lock().
 398 */
 399int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
 400{
 401        struct tomoyo_aggregator e = { };
 402        int error = param->is_delete ? -ENOENT : -ENOMEM;
 403        const char *original_name = tomoyo_read_token(param);
 404        const char *aggregated_name = tomoyo_read_token(param);
 405
 406        if (!tomoyo_correct_word(original_name) ||
 407            !tomoyo_correct_path(aggregated_name))
 408                return -EINVAL;
 409        e.original_name = tomoyo_get_name(original_name);
 410        e.aggregated_name = tomoyo_get_name(aggregated_name);
 411        if (!e.original_name || !e.aggregated_name ||
 412            e.aggregated_name->is_patterned) /* No patterns allowed. */
 413                goto out;
 414        param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
 415        error = tomoyo_update_policy(&e.head, sizeof(e), param,
 416                                     tomoyo_same_aggregator);
 417out:
 418        tomoyo_put_name(e.original_name);
 419        tomoyo_put_name(e.aggregated_name);
 420        return error;
 421}
 422
 423/**
 424 * tomoyo_find_namespace - Find specified namespace.
 425 *
 426 * @name: Name of namespace to find.
 427 * @len:  Length of @name.
 428 *
 429 * Returns pointer to "struct tomoyo_policy_namespace" if found,
 430 * NULL otherwise.
 431 *
 432 * Caller holds tomoyo_read_lock().
 433 */
 434static struct tomoyo_policy_namespace *tomoyo_find_namespace
 435(const char *name, const unsigned int len)
 436{
 437        struct tomoyo_policy_namespace *ns;
 438
 439        list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
 440                if (strncmp(name, ns->name, len) ||
 441                    (name[len] && name[len] != ' '))
 442                        continue;
 443                return ns;
 444        }
 445        return NULL;
 446}
 447
 448/**
 449 * tomoyo_assign_namespace - Create a new namespace.
 450 *
 451 * @domainname: Name of namespace to create.
 452 *
 453 * Returns pointer to "struct tomoyo_policy_namespace" on success,
 454 * NULL otherwise.
 455 *
 456 * Caller holds tomoyo_read_lock().
 457 */
 458struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
 459{
 460        struct tomoyo_policy_namespace *ptr;
 461        struct tomoyo_policy_namespace *entry;
 462        const char *cp = domainname;
 463        unsigned int len = 0;
 464
 465        while (*cp && *cp++ != ' ')
 466                len++;
 467        ptr = tomoyo_find_namespace(domainname, len);
 468        if (ptr)
 469                return ptr;
 470        if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
 471                return NULL;
 472        entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
 473        if (!entry)
 474                return NULL;
 475        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 476                goto out;
 477        ptr = tomoyo_find_namespace(domainname, len);
 478        if (!ptr && tomoyo_memory_ok(entry)) {
 479                char *name = (char *) (entry + 1);
 480
 481                ptr = entry;
 482                memmove(name, domainname, len);
 483                name[len] = '\0';
 484                entry->name = name;
 485                tomoyo_init_policy_namespace(entry);
 486                entry = NULL;
 487        }
 488        mutex_unlock(&tomoyo_policy_lock);
 489out:
 490        kfree(entry);
 491        return ptr;
 492}
 493
 494/**
 495 * tomoyo_namespace_jump - Check for namespace jump.
 496 *
 497 * @domainname: Name of domain.
 498 *
 499 * Returns true if namespace differs, false otherwise.
 500 */
 501static bool tomoyo_namespace_jump(const char *domainname)
 502{
 503        const char *namespace = tomoyo_current_namespace()->name;
 504        const int len = strlen(namespace);
 505
 506        return strncmp(domainname, namespace, len) ||
 507                (domainname[len] && domainname[len] != ' ');
 508}
 509
 510/**
 511 * tomoyo_assign_domain - Create a domain or a namespace.
 512 *
 513 * @domainname: The name of domain.
 514 * @transit:    True if transit to domain found or created.
 515 *
 516 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
 517 *
 518 * Caller holds tomoyo_read_lock().
 519 */
 520struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
 521                                                const bool transit)
 522{
 523        struct tomoyo_domain_info e = { };
 524        struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
 525        bool created = false;
 526
 527        if (entry) {
 528                if (transit) {
 529                        /*
 530                         * Since namespace is created at runtime, profiles may
 531                         * not be created by the moment the process transits to
 532                         * that domain. Do not perform domain transition if
 533                         * profile for that domain is not yet created.
 534                         */
 535                        if (tomoyo_policy_loaded &&
 536                            !entry->ns->profile_ptr[entry->profile])
 537                                return NULL;
 538                }
 539                return entry;
 540        }
 541        /* Requested domain does not exist. */
 542        /* Don't create requested domain if domainname is invalid. */
 543        if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
 544            !tomoyo_correct_domain(domainname))
 545                return NULL;
 546        /*
 547         * Since definition of profiles and acl_groups may differ across
 548         * namespaces, do not inherit "use_profile" and "use_group" settings
 549         * by automatically creating requested domain upon domain transition.
 550         */
 551        if (transit && tomoyo_namespace_jump(domainname))
 552                return NULL;
 553        e.ns = tomoyo_assign_namespace(domainname);
 554        if (!e.ns)
 555                return NULL;
 556        /*
 557         * "use_profile" and "use_group" settings for automatically created
 558         * domains are inherited from current domain. These are 0 for manually
 559         * created domains.
 560         */
 561        if (transit) {
 562                const struct tomoyo_domain_info *domain = tomoyo_domain();
 563
 564                e.profile = domain->profile;
 565                memcpy(e.group, domain->group, sizeof(e.group));
 566        }
 567        e.domainname = tomoyo_get_name(domainname);
 568        if (!e.domainname)
 569                return NULL;
 570        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 571                goto out;
 572        entry = tomoyo_find_domain(domainname);
 573        if (!entry) {
 574                entry = tomoyo_commit_ok(&e, sizeof(e));
 575                if (entry) {
 576                        INIT_LIST_HEAD(&entry->acl_info_list);
 577                        list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
 578                        created = true;
 579                }
 580        }
 581        mutex_unlock(&tomoyo_policy_lock);
 582out:
 583        tomoyo_put_name(e.domainname);
 584        if (entry && transit) {
 585                if (created) {
 586                        struct tomoyo_request_info r;
 587                        int i;
 588
 589                        tomoyo_init_request_info(&r, entry,
 590                                                 TOMOYO_MAC_FILE_EXECUTE);
 591                        r.granted = false;
 592                        tomoyo_write_log(&r, "use_profile %u\n",
 593                                         entry->profile);
 594                        for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
 595                                if (test_bit(i, entry->group))
 596                                        tomoyo_write_log(&r, "use_group %u\n",
 597                                                         i);
 598                        tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
 599                }
 600        }
 601        return entry;
 602}
 603
 604/**
 605 * tomoyo_environ - Check permission for environment variable names.
 606 *
 607 * @ee: Pointer to "struct tomoyo_execve".
 608 *
 609 * Returns 0 on success, negative value otherwise.
 610 */
 611static int tomoyo_environ(struct tomoyo_execve *ee)
 612{
 613        struct tomoyo_request_info *r = &ee->r;
 614        struct linux_binprm *bprm = ee->bprm;
 615        /* env_page.data is allocated by tomoyo_dump_page(). */
 616        struct tomoyo_page_dump env_page = { };
 617        char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
 618        int arg_len = 0;
 619        unsigned long pos = bprm->p;
 620        int offset = pos % PAGE_SIZE;
 621        int argv_count = bprm->argc;
 622        int envp_count = bprm->envc;
 623        int error = -ENOMEM;
 624
 625        ee->r.type = TOMOYO_MAC_ENVIRON;
 626        ee->r.profile = r->domain->profile;
 627        ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
 628                                     TOMOYO_MAC_ENVIRON);
 629        if (!r->mode || !envp_count)
 630                return 0;
 631        arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
 632        if (!arg_ptr)
 633                goto out;
 634        while (error == -ENOMEM) {
 635                if (!tomoyo_dump_page(bprm, pos, &env_page))
 636                        goto out;
 637                pos += PAGE_SIZE - offset;
 638                /* Read. */
 639                while (argv_count && offset < PAGE_SIZE) {
 640                        if (!env_page.data[offset++])
 641                                argv_count--;
 642                }
 643                if (argv_count) {
 644                        offset = 0;
 645                        continue;
 646                }
 647                while (offset < PAGE_SIZE) {
 648                        const unsigned char c = env_page.data[offset++];
 649
 650                        if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
 651                                if (c == '=') {
 652                                        arg_ptr[arg_len++] = '\0';
 653                                } else if (c == '\\') {
 654                                        arg_ptr[arg_len++] = '\\';
 655                                        arg_ptr[arg_len++] = '\\';
 656                                } else if (c > ' ' && c < 127) {
 657                                        arg_ptr[arg_len++] = c;
 658                                } else {
 659                                        arg_ptr[arg_len++] = '\\';
 660                                        arg_ptr[arg_len++] = (c >> 6) + '0';
 661                                        arg_ptr[arg_len++]
 662                                                = ((c >> 3) & 7) + '0';
 663                                        arg_ptr[arg_len++] = (c & 7) + '0';
 664                                }
 665                        } else {
 666                                arg_ptr[arg_len] = '\0';
 667                        }
 668                        if (c)
 669                                continue;
 670                        if (tomoyo_env_perm(r, arg_ptr)) {
 671                                error = -EPERM;
 672                                break;
 673                        }
 674                        if (!--envp_count) {
 675                                error = 0;
 676                                break;
 677                        }
 678                        arg_len = 0;
 679                }
 680                offset = 0;
 681        }
 682out:
 683        if (r->mode != TOMOYO_CONFIG_ENFORCING)
 684                error = 0;
 685        kfree(env_page.data);
 686        kfree(arg_ptr);
 687        return error;
 688}
 689
 690/**
 691 * tomoyo_find_next_domain - Find a domain.
 692 *
 693 * @bprm: Pointer to "struct linux_binprm".
 694 *
 695 * Returns 0 on success, negative value otherwise.
 696 *
 697 * Caller holds tomoyo_read_lock().
 698 */
 699int tomoyo_find_next_domain(struct linux_binprm *bprm)
 700{
 701        struct tomoyo_domain_info *old_domain = tomoyo_domain();
 702        struct tomoyo_domain_info *domain = NULL;
 703        const char *original_name = bprm->filename;
 704        int retval = -ENOMEM;
 705        bool reject_on_transition_failure = false;
 706        const struct tomoyo_path_info *candidate;
 707        struct tomoyo_path_info exename;
 708        struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
 709
 710        if (!ee)
 711                return -ENOMEM;
 712        ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
 713        if (!ee->tmp) {
 714                kfree(ee);
 715                return -ENOMEM;
 716        }
 717        /* ee->dump->data is allocated by tomoyo_dump_page(). */
 718        tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
 719        ee->r.ee = ee;
 720        ee->bprm = bprm;
 721        ee->r.obj = &ee->obj;
 722        ee->obj.path1 = bprm->file->f_path;
 723        /* Get symlink's pathname of program. */
 724        retval = -ENOENT;
 725        exename.name = tomoyo_realpath_nofollow(original_name);
 726        if (!exename.name)
 727                goto out;
 728        tomoyo_fill_path_info(&exename);
 729retry:
 730        /* Check 'aggregator' directive. */
 731        {
 732                struct tomoyo_aggregator *ptr;
 733                struct list_head *list =
 734                        &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
 735
 736                /* Check 'aggregator' directive. */
 737                candidate = &exename;
 738                list_for_each_entry_rcu(ptr, list, head.list) {
 739                        if (ptr->head.is_deleted ||
 740                            !tomoyo_path_matches_pattern(&exename,
 741                                                         ptr->original_name))
 742                                continue;
 743                        candidate = ptr->aggregated_name;
 744                        break;
 745                }
 746        }
 747
 748        /* Check execute permission. */
 749        retval = tomoyo_execute_permission(&ee->r, candidate);
 750        if (retval == TOMOYO_RETRY_REQUEST)
 751                goto retry;
 752        if (retval < 0)
 753                goto out;
 754        /*
 755         * To be able to specify domainnames with wildcards, use the
 756         * pathname specified in the policy (which may contain
 757         * wildcard) rather than the pathname passed to execve()
 758         * (which never contains wildcard).
 759         */
 760        if (ee->r.param.path.matched_path)
 761                candidate = ee->r.param.path.matched_path;
 762
 763        /*
 764         * Check for domain transition preference if "file execute" matched.
 765         * If preference is given, make do_execve() fail if domain transition
 766         * has failed, for domain transition preference should be used with
 767         * destination domain defined.
 768         */
 769        if (ee->transition) {
 770                const char *domainname = ee->transition->name;
 771
 772                reject_on_transition_failure = true;
 773                if (!strcmp(domainname, "keep"))
 774                        goto force_keep_domain;
 775                if (!strcmp(domainname, "child"))
 776                        goto force_child_domain;
 777                if (!strcmp(domainname, "reset"))
 778                        goto force_reset_domain;
 779                if (!strcmp(domainname, "initialize"))
 780                        goto force_initialize_domain;
 781                if (!strcmp(domainname, "parent")) {
 782                        char *cp;
 783
 784                        strncpy(ee->tmp, old_domain->domainname->name,
 785                                TOMOYO_EXEC_TMPSIZE - 1);
 786                        cp = strrchr(ee->tmp, ' ');
 787                        if (cp)
 788                                *cp = '\0';
 789                } else if (*domainname == '<')
 790                        strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
 791                else
 792                        snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
 793                                 old_domain->domainname->name, domainname);
 794                goto force_jump_domain;
 795        }
 796        /*
 797         * No domain transition preference specified.
 798         * Calculate domain to transit to.
 799         */
 800        switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
 801                                       candidate)) {
 802        case TOMOYO_TRANSITION_CONTROL_RESET:
 803force_reset_domain:
 804                /* Transit to the root of specified namespace. */
 805                snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
 806                         candidate->name);
 807                /*
 808                 * Make do_execve() fail if domain transition across namespaces
 809                 * has failed.
 810                 */
 811                reject_on_transition_failure = true;
 812                break;
 813        case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
 814force_initialize_domain:
 815                /* Transit to the child of current namespace's root. */
 816                snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
 817                         old_domain->ns->name, candidate->name);
 818                break;
 819        case TOMOYO_TRANSITION_CONTROL_KEEP:
 820force_keep_domain:
 821                /* Keep current domain. */
 822                domain = old_domain;
 823                break;
 824        default:
 825                if (old_domain == &tomoyo_kernel_domain &&
 826                    !tomoyo_policy_loaded) {
 827                        /*
 828                         * Needn't to transit from kernel domain before
 829                         * starting /sbin/init. But transit from kernel domain
 830                         * if executing initializers because they might start
 831                         * before /sbin/init.
 832                         */
 833                        domain = old_domain;
 834                        break;
 835                }
 836force_child_domain:
 837                /* Normal domain transition. */
 838                snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
 839                         old_domain->domainname->name, candidate->name);
 840                break;
 841        }
 842force_jump_domain:
 843        if (!domain)
 844                domain = tomoyo_assign_domain(ee->tmp, true);
 845        if (domain)
 846                retval = 0;
 847        else if (reject_on_transition_failure) {
 848                pr_warn("ERROR: Domain '%s' not ready.\n", ee->tmp);
 849                retval = -ENOMEM;
 850        } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
 851                retval = -ENOMEM;
 852        else {
 853                retval = 0;
 854                if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
 855                        old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
 856                        ee->r.granted = false;
 857                        tomoyo_write_log(&ee->r, "%s", tomoyo_dif
 858                                         [TOMOYO_DIF_TRANSITION_FAILED]);
 859                        pr_warn("ERROR: Domain '%s' not defined.\n", ee->tmp);
 860                }
 861        }
 862 out:
 863        if (!domain)
 864                domain = old_domain;
 865        /* Update reference count on "struct tomoyo_domain_info". */
 866        {
 867                struct tomoyo_task *s = tomoyo_task(current);
 868
 869                s->old_domain_info = s->domain_info;
 870                s->domain_info = domain;
 871                atomic_inc(&domain->users);
 872        }
 873        kfree(exename.name);
 874        if (!retval) {
 875                ee->r.domain = domain;
 876                retval = tomoyo_environ(ee);
 877        }
 878        kfree(ee->tmp);
 879        kfree(ee->dump.data);
 880        kfree(ee);
 881        return retval;
 882}
 883
 884/**
 885 * tomoyo_dump_page - Dump a page to buffer.
 886 *
 887 * @bprm: Pointer to "struct linux_binprm".
 888 * @pos:  Location to dump.
 889 * @dump: Poiner to "struct tomoyo_page_dump".
 890 *
 891 * Returns true on success, false otherwise.
 892 */
 893bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
 894                      struct tomoyo_page_dump *dump)
 895{
 896        struct page *page;
 897
 898        /* dump->data is released by tomoyo_find_next_domain(). */
 899        if (!dump->data) {
 900                dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
 901                if (!dump->data)
 902                        return false;
 903        }
 904        /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
 905#ifdef CONFIG_MMU
 906        /*
 907         * This is called at execve() time in order to dig around
 908         * in the argv/environment of the new proceess
 909         * (represented by bprm).  'current' is the process doing
 910         * the execve().
 911         */
 912        if (get_user_pages_remote(current, bprm->mm, pos, 1,
 913                                FOLL_FORCE, &page, NULL, NULL) <= 0)
 914                return false;
 915#else
 916        page = bprm->page[pos / PAGE_SIZE];
 917#endif
 918        if (page != dump->page) {
 919                const unsigned int offset = pos % PAGE_SIZE;
 920                /*
 921                 * Maybe kmap()/kunmap() should be used here.
 922                 * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
 923                 * So do I.
 924                 */
 925                char *kaddr = kmap_atomic(page);
 926
 927                dump->page = page;
 928                memcpy(dump->data + offset, kaddr + offset,
 929                       PAGE_SIZE - offset);
 930                kunmap_atomic(kaddr);
 931        }
 932        /* Same with put_arg_page(page) in fs/exec.c */
 933#ifdef CONFIG_MMU
 934        put_page(page);
 935#endif
 936        return true;
 937}
 938