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