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