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