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