linux/security/tomoyo/domain.c
<<
>>
Prefs
   1/*
   2 * security/tomoyo/domain.c
   3 *
   4 * Implementation of the Domain-Based Mandatory Access Control.
   5 *
   6 * Copyright (C) 2005-2009  NTT DATA CORPORATION
   7 *
   8 * Version: 2.2.0   2009/04/01
   9 *
  10 */
  11
  12#include "common.h"
  13#include <linux/binfmts.h>
  14#include <linux/slab.h>
  15
  16/* Variables definitions.*/
  17
  18/* The initial domain. */
  19struct tomoyo_domain_info tomoyo_kernel_domain;
  20
  21/*
  22 * tomoyo_domain_list is used for holding list of domains.
  23 * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
  24 * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
  25 *
  26 * An entry is added by
  27 *
  28 * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
  29 *                                  /sys/kernel/security/tomoyo/domain_policy
  30 *
  31 * and is deleted by
  32 *
  33 * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
  34 *                                  /sys/kernel/security/tomoyo/domain_policy
  35 *
  36 * and all entries are retrieved by
  37 *
  38 * # cat /sys/kernel/security/tomoyo/domain_policy
  39 *
  40 * A domain is added by
  41 *
  42 * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
  43 *
  44 * and is deleted by
  45 *
  46 * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
  47 *
  48 * and all domains are retrieved by
  49 *
  50 * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
  51 *
  52 * Normally, a domainname is monotonically getting longer because a domainname
  53 * which the process will belong to if an execve() operation succeeds is
  54 * defined as a concatenation of "current domainname" + "pathname passed to
  55 * execve()".
  56 * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
  57 * exceptions.
  58 */
  59LIST_HEAD(tomoyo_domain_list);
  60
  61/**
  62 * tomoyo_get_last_name - Get last component of a domainname.
  63 *
  64 * @domain: Pointer to "struct tomoyo_domain_info".
  65 *
  66 * Returns the last component of the domainname.
  67 */
  68const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
  69{
  70        const char *cp0 = domain->domainname->name;
  71        const char *cp1 = strrchr(cp0, ' ');
  72
  73        if (cp1)
  74                return cp1 + 1;
  75        return cp0;
  76}
  77
  78/*
  79 * tomoyo_domain_initializer_list is used for holding list of programs which
  80 * triggers reinitialization of domainname. Normally, a domainname is
  81 * monotonically getting longer. But sometimes, we restart daemon programs.
  82 * It would be convenient for us that "a daemon started upon system boot" and
  83 * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
  84 * provides a way to shorten domainnames.
  85 *
  86 * An entry is added by
  87 *
  88 * # echo 'initialize_domain /usr/sbin/httpd' > \
  89 *                               /sys/kernel/security/tomoyo/exception_policy
  90 *
  91 * and is deleted by
  92 *
  93 * # echo 'delete initialize_domain /usr/sbin/httpd' > \
  94 *                               /sys/kernel/security/tomoyo/exception_policy
  95 *
  96 * and all entries are retrieved by
  97 *
  98 * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
  99 *
 100 * In the example above, /usr/sbin/httpd will belong to
 101 * "<kernel> /usr/sbin/httpd" domain.
 102 *
 103 * You may specify a domainname using "from" keyword.
 104 * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
 105 * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
 106 * domain to belong to "<kernel> /usr/sbin/httpd" domain.
 107 *
 108 * You may add "no_" prefix to "initialize_domain".
 109 * "initialize_domain /usr/sbin/httpd" and
 110 * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
 111 * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
 112 * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
 113 */
 114LIST_HEAD(tomoyo_domain_initializer_list);
 115
 116/**
 117 * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
 118 *
 119 * @domainname: The name of domain. May be NULL.
 120 * @program:    The name of program.
 121 * @is_not:     True if it is "no_initialize_domain" entry.
 122 * @is_delete:  True if it is a delete request.
 123 *
 124 * Returns 0 on success, negative value otherwise.
 125 *
 126 * Caller holds tomoyo_read_lock().
 127 */
 128static int tomoyo_update_domain_initializer_entry(const char *domainname,
 129                                                  const char *program,
 130                                                  const bool is_not,
 131                                                  const bool is_delete)
 132{
 133        struct tomoyo_domain_initializer_entry *ptr;
 134        struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
 135        int error = is_delete ? -ENOENT : -ENOMEM;
 136
 137        if (!tomoyo_is_correct_path(program, 1, -1, -1))
 138                return -EINVAL; /* No patterns allowed. */
 139        if (domainname) {
 140                if (!tomoyo_is_domain_def(domainname) &&
 141                    tomoyo_is_correct_path(domainname, 1, -1, -1))
 142                        e.is_last_name = true;
 143                else if (!tomoyo_is_correct_domain(domainname))
 144                        return -EINVAL;
 145                e.domainname = tomoyo_get_name(domainname);
 146                if (!e.domainname)
 147                        goto out;
 148        }
 149        e.program = tomoyo_get_name(program);
 150        if (!e.program)
 151                goto out;
 152        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 153                goto out;
 154        list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 155                if (!tomoyo_is_same_domain_initializer_entry(ptr, &e))
 156                        continue;
 157                ptr->is_deleted = is_delete;
 158                error = 0;
 159                break;
 160        }
 161        if (!is_delete && error) {
 162                struct tomoyo_domain_initializer_entry *entry =
 163                        tomoyo_commit_ok(&e, sizeof(e));
 164                if (entry) {
 165                        list_add_tail_rcu(&entry->list,
 166                                          &tomoyo_domain_initializer_list);
 167                        error = 0;
 168                }
 169        }
 170        mutex_unlock(&tomoyo_policy_lock);
 171 out:
 172        tomoyo_put_name(e.domainname);
 173        tomoyo_put_name(e.program);
 174        return error;
 175}
 176
 177/**
 178 * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
 179 *
 180 * @head: Pointer to "struct tomoyo_io_buffer".
 181 *
 182 * Returns true on success, false otherwise.
 183 *
 184 * Caller holds tomoyo_read_lock().
 185 */
 186bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
 187{
 188        struct list_head *pos;
 189        bool done = true;
 190
 191        list_for_each_cookie(pos, head->read_var2,
 192                             &tomoyo_domain_initializer_list) {
 193                const char *no;
 194                const char *from = "";
 195                const char *domain = "";
 196                struct tomoyo_domain_initializer_entry *ptr;
 197                ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
 198                                  list);
 199                if (ptr->is_deleted)
 200                        continue;
 201                no = ptr->is_not ? "no_" : "";
 202                if (ptr->domainname) {
 203                        from = " from ";
 204                        domain = ptr->domainname->name;
 205                }
 206                done = tomoyo_io_printf(head,
 207                                        "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
 208                                        "%s%s%s\n", no, ptr->program->name,
 209                                        from, domain);
 210                if (!done)
 211                        break;
 212        }
 213        return done;
 214}
 215
 216/**
 217 * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
 218 *
 219 * @data:      String to parse.
 220 * @is_not:    True if it is "no_initialize_domain" entry.
 221 * @is_delete: True if it is a delete request.
 222 *
 223 * Returns 0 on success, negative value otherwise.
 224 *
 225 * Caller holds tomoyo_read_lock().
 226 */
 227int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
 228                                           const bool is_delete)
 229{
 230        char *cp = strstr(data, " from ");
 231
 232        if (cp) {
 233                *cp = '\0';
 234                return tomoyo_update_domain_initializer_entry(cp + 6, data,
 235                                                              is_not,
 236                                                              is_delete);
 237        }
 238        return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
 239                                                      is_delete);
 240}
 241
 242/**
 243 * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
 244 *
 245 * @domainname: The name of domain.
 246 * @program:    The name of program.
 247 * @last_name:  The last component of @domainname.
 248 *
 249 * Returns true if executing @program reinitializes domain transition,
 250 * false otherwise.
 251 *
 252 * Caller holds tomoyo_read_lock().
 253 */
 254static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
 255                                         domainname,
 256                                         const struct tomoyo_path_info *program,
 257                                         const struct tomoyo_path_info *
 258                                         last_name)
 259{
 260        struct tomoyo_domain_initializer_entry *ptr;
 261        bool flag = false;
 262
 263        list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
 264                if (ptr->is_deleted)
 265                        continue;
 266                if (ptr->domainname) {
 267                        if (!ptr->is_last_name) {
 268                                if (ptr->domainname != domainname)
 269                                        continue;
 270                        } else {
 271                                if (tomoyo_pathcmp(ptr->domainname, last_name))
 272                                        continue;
 273                        }
 274                }
 275                if (tomoyo_pathcmp(ptr->program, program))
 276                        continue;
 277                if (ptr->is_not) {
 278                        flag = false;
 279                        break;
 280                }
 281                flag = true;
 282        }
 283        return flag;
 284}
 285
 286/*
 287 * tomoyo_domain_keeper_list is used for holding list of domainnames which
 288 * suppresses domain transition. Normally, a domainname is monotonically
 289 * getting longer. But sometimes, we want to suppress domain transition.
 290 * It would be convenient for us that programs executed from a login session
 291 * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
 292 * transition.
 293 *
 294 * An entry is added by
 295 *
 296 * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
 297 *                              /sys/kernel/security/tomoyo/exception_policy
 298 *
 299 * and is deleted by
 300 *
 301 * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
 302 *                              /sys/kernel/security/tomoyo/exception_policy
 303 *
 304 * and all entries are retrieved by
 305 *
 306 * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
 307 *
 308 * In the example above, any process which belongs to
 309 * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
 310 * unless explicitly specified by "initialize_domain" or "no_keep_domain".
 311 *
 312 * You may specify a program using "from" keyword.
 313 * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
 314 * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
 315 * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
 316 *
 317 * You may add "no_" prefix to "keep_domain".
 318 * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
 319 * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
 320 * cause "/usr/bin/passwd" to belong to
 321 * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
 322 * explicitly specified by "initialize_domain".
 323 */
 324LIST_HEAD(tomoyo_domain_keeper_list);
 325
 326/**
 327 * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
 328 *
 329 * @domainname: The name of domain.
 330 * @program:    The name of program. May be NULL.
 331 * @is_not:     True if it is "no_keep_domain" entry.
 332 * @is_delete:  True if it is a delete request.
 333 *
 334 * Returns 0 on success, negative value otherwise.
 335 *
 336 * Caller holds tomoyo_read_lock().
 337 */
 338static int tomoyo_update_domain_keeper_entry(const char *domainname,
 339                                             const char *program,
 340                                             const bool is_not,
 341                                             const bool is_delete)
 342{
 343        struct tomoyo_domain_keeper_entry *ptr;
 344        struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
 345        int error = is_delete ? -ENOENT : -ENOMEM;
 346
 347        if (!tomoyo_is_domain_def(domainname) &&
 348            tomoyo_is_correct_path(domainname, 1, -1, -1))
 349                e.is_last_name = true;
 350        else if (!tomoyo_is_correct_domain(domainname))
 351                return -EINVAL;
 352        if (program) {
 353                if (!tomoyo_is_correct_path(program, 1, -1, -1))
 354                        return -EINVAL;
 355                e.program = tomoyo_get_name(program);
 356                if (!e.program)
 357                        goto out;
 358        }
 359        e.domainname = tomoyo_get_name(domainname);
 360        if (!e.domainname)
 361                goto out;
 362        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 363                goto out;
 364        list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 365                if (!tomoyo_is_same_domain_keeper_entry(ptr, &e))
 366                        continue;
 367                ptr->is_deleted = is_delete;
 368                error = 0;
 369                break;
 370        }
 371        if (!is_delete && error) {
 372                struct tomoyo_domain_keeper_entry *entry =
 373                        tomoyo_commit_ok(&e, sizeof(e));
 374                if (entry) {
 375                        list_add_tail_rcu(&entry->list,
 376                                          &tomoyo_domain_keeper_list);
 377                        error = 0;
 378                }
 379        }
 380        mutex_unlock(&tomoyo_policy_lock);
 381 out:
 382        tomoyo_put_name(e.domainname);
 383        tomoyo_put_name(e.program);
 384        return error;
 385}
 386
 387/**
 388 * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
 389 *
 390 * @data:      String to parse.
 391 * @is_not:    True if it is "no_keep_domain" entry.
 392 * @is_delete: True if it is a delete request.
 393 *
 394 * Caller holds tomoyo_read_lock().
 395 */
 396int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
 397                                      const bool is_delete)
 398{
 399        char *cp = strstr(data, " from ");
 400
 401        if (cp) {
 402                *cp = '\0';
 403                return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
 404                                                         is_delete);
 405        }
 406        return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
 407}
 408
 409/**
 410 * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
 411 *
 412 * @head: Pointer to "struct tomoyo_io_buffer".
 413 *
 414 * Returns true on success, false otherwise.
 415 *
 416 * Caller holds tomoyo_read_lock().
 417 */
 418bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
 419{
 420        struct list_head *pos;
 421        bool done = true;
 422
 423        list_for_each_cookie(pos, head->read_var2,
 424                             &tomoyo_domain_keeper_list) {
 425                struct tomoyo_domain_keeper_entry *ptr;
 426                const char *no;
 427                const char *from = "";
 428                const char *program = "";
 429
 430                ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
 431                if (ptr->is_deleted)
 432                        continue;
 433                no = ptr->is_not ? "no_" : "";
 434                if (ptr->program) {
 435                        from = " from ";
 436                        program = ptr->program->name;
 437                }
 438                done = tomoyo_io_printf(head,
 439                                        "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
 440                                        "%s%s%s\n", no, program, from,
 441                                        ptr->domainname->name);
 442                if (!done)
 443                        break;
 444        }
 445        return done;
 446}
 447
 448/**
 449 * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
 450 *
 451 * @domainname: The name of domain.
 452 * @program:    The name of program.
 453 * @last_name:  The last component of @domainname.
 454 *
 455 * Returns true if executing @program supresses domain transition,
 456 * false otherwise.
 457 *
 458 * Caller holds tomoyo_read_lock().
 459 */
 460static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
 461                                    const struct tomoyo_path_info *program,
 462                                    const struct tomoyo_path_info *last_name)
 463{
 464        struct tomoyo_domain_keeper_entry *ptr;
 465        bool flag = false;
 466
 467        list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
 468                if (ptr->is_deleted)
 469                        continue;
 470                if (!ptr->is_last_name) {
 471                        if (ptr->domainname != domainname)
 472                                continue;
 473                } else {
 474                        if (tomoyo_pathcmp(ptr->domainname, last_name))
 475                                continue;
 476                }
 477                if (ptr->program && tomoyo_pathcmp(ptr->program, program))
 478                        continue;
 479                if (ptr->is_not) {
 480                        flag = false;
 481                        break;
 482                }
 483                flag = true;
 484        }
 485        return flag;
 486}
 487
 488/*
 489 * tomoyo_alias_list is used for holding list of symlink's pathnames which are
 490 * allowed to be passed to an execve() request. Normally, the domainname which
 491 * the current process will belong to after execve() succeeds is calculated
 492 * using dereferenced pathnames. But some programs behave differently depending
 493 * on the name passed to argv[0]. For busybox, calculating domainname using
 494 * dereferenced pathnames will cause all programs in the busybox to belong to
 495 * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
 496 * pathname for checking execve()'s permission and calculating domainname which
 497 * the current process will belong to after execve() succeeds.
 498 *
 499 * An entry is added by
 500 *
 501 * # echo 'alias /bin/busybox /bin/cat' > \
 502 *                            /sys/kernel/security/tomoyo/exception_policy
 503 *
 504 * and is deleted by
 505 *
 506 * # echo 'delete alias /bin/busybox /bin/cat' > \
 507 *                            /sys/kernel/security/tomoyo/exception_policy
 508 *
 509 * and all entries are retrieved by
 510 *
 511 * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
 512 *
 513 * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
 514 * of /bin/cat is requested, permission is checked for /bin/cat rather than
 515 * /bin/busybox and domainname which the current process will belong to after
 516 * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
 517 */
 518LIST_HEAD(tomoyo_alias_list);
 519
 520/**
 521 * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
 522 *
 523 * @original_name: The original program's real name.
 524 * @aliased_name:  The symbolic program's symbolic link's name.
 525 * @is_delete:     True if it is a delete request.
 526 *
 527 * Returns 0 on success, negative value otherwise.
 528 *
 529 * Caller holds tomoyo_read_lock().
 530 */
 531static int tomoyo_update_alias_entry(const char *original_name,
 532                                     const char *aliased_name,
 533                                     const bool is_delete)
 534{
 535        struct tomoyo_alias_entry *ptr;
 536        struct tomoyo_alias_entry e = { };
 537        int error = is_delete ? -ENOENT : -ENOMEM;
 538
 539        if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
 540            !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
 541                return -EINVAL; /* No patterns allowed. */
 542        e.original_name = tomoyo_get_name(original_name);
 543        e.aliased_name = tomoyo_get_name(aliased_name);
 544        if (!e.original_name || !e.aliased_name)
 545                goto out;
 546        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 547                goto out;
 548        list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 549                if (!tomoyo_is_same_alias_entry(ptr, &e))
 550                        continue;
 551                ptr->is_deleted = is_delete;
 552                error = 0;
 553                break;
 554        }
 555        if (!is_delete && error) {
 556                struct tomoyo_alias_entry *entry =
 557                        tomoyo_commit_ok(&e, sizeof(e));
 558                if (entry) {
 559                        list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
 560                        error = 0;
 561                }
 562        }
 563        mutex_unlock(&tomoyo_policy_lock);
 564 out:
 565        tomoyo_put_name(e.original_name);
 566        tomoyo_put_name(e.aliased_name);
 567        return error;
 568}
 569
 570/**
 571 * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
 572 *
 573 * @head: Pointer to "struct tomoyo_io_buffer".
 574 *
 575 * Returns true on success, false otherwise.
 576 *
 577 * Caller holds tomoyo_read_lock().
 578 */
 579bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
 580{
 581        struct list_head *pos;
 582        bool done = true;
 583
 584        list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
 585                struct tomoyo_alias_entry *ptr;
 586
 587                ptr = list_entry(pos, struct tomoyo_alias_entry, list);
 588                if (ptr->is_deleted)
 589                        continue;
 590                done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
 591                                        ptr->original_name->name,
 592                                        ptr->aliased_name->name);
 593                if (!done)
 594                        break;
 595        }
 596        return done;
 597}
 598
 599/**
 600 * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
 601 *
 602 * @data:      String to parse.
 603 * @is_delete: True if it is a delete request.
 604 *
 605 * Returns 0 on success, negative value otherwise.
 606 *
 607 * Caller holds tomoyo_read_lock().
 608 */
 609int tomoyo_write_alias_policy(char *data, const bool is_delete)
 610{
 611        char *cp = strchr(data, ' ');
 612
 613        if (!cp)
 614                return -EINVAL;
 615        *cp++ = '\0';
 616        return tomoyo_update_alias_entry(data, cp, is_delete);
 617}
 618
 619/**
 620 * tomoyo_find_or_assign_new_domain - Create a domain.
 621 *
 622 * @domainname: The name of domain.
 623 * @profile:    Profile number to assign if the domain was newly created.
 624 *
 625 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
 626 *
 627 * Caller holds tomoyo_read_lock().
 628 */
 629struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
 630                                                            domainname,
 631                                                            const u8 profile)
 632{
 633        struct tomoyo_domain_info *entry;
 634        struct tomoyo_domain_info *domain = NULL;
 635        const struct tomoyo_path_info *saved_domainname;
 636        bool found = false;
 637
 638        if (!tomoyo_is_correct_domain(domainname))
 639                return NULL;
 640        saved_domainname = tomoyo_get_name(domainname);
 641        if (!saved_domainname)
 642                return NULL;
 643        entry = kzalloc(sizeof(*entry), GFP_NOFS);
 644        if (mutex_lock_interruptible(&tomoyo_policy_lock))
 645                goto out;
 646        list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
 647                if (domain->is_deleted ||
 648                    tomoyo_pathcmp(saved_domainname, domain->domainname))
 649                        continue;
 650                found = true;
 651                break;
 652        }
 653        if (!found && tomoyo_memory_ok(entry)) {
 654                INIT_LIST_HEAD(&entry->acl_info_list);
 655                entry->domainname = saved_domainname;
 656                saved_domainname = NULL;
 657                entry->profile = profile;
 658                list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
 659                domain = entry;
 660                entry = NULL;
 661                found = true;
 662        }
 663        mutex_unlock(&tomoyo_policy_lock);
 664 out:
 665        tomoyo_put_name(saved_domainname);
 666        kfree(entry);
 667        return found ? domain : NULL;
 668}
 669
 670/**
 671 * tomoyo_find_next_domain - Find a domain.
 672 *
 673 * @bprm: Pointer to "struct linux_binprm".
 674 *
 675 * Returns 0 on success, negative value otherwise.
 676 *
 677 * Caller holds tomoyo_read_lock().
 678 */
 679int tomoyo_find_next_domain(struct linux_binprm *bprm)
 680{
 681        /*
 682         * This function assumes that the size of buffer returned by
 683         * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
 684         */
 685        struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
 686        struct tomoyo_domain_info *old_domain = tomoyo_domain();
 687        struct tomoyo_domain_info *domain = NULL;
 688        const char *old_domain_name = old_domain->domainname->name;
 689        const char *original_name = bprm->filename;
 690        char *new_domain_name = NULL;
 691        char *real_program_name = NULL;
 692        char *symlink_program_name = NULL;
 693        const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
 694        const bool is_enforce = (mode == 3);
 695        int retval = -ENOMEM;
 696        struct tomoyo_path_info r; /* real name */
 697        struct tomoyo_path_info s; /* symlink name */
 698        struct tomoyo_path_info l; /* last name */
 699        static bool initialized;
 700
 701        if (!tmp)
 702                goto out;
 703
 704        if (!initialized) {
 705                /*
 706                 * Built-in initializers. This is needed because policies are
 707                 * not loaded until starting /sbin/init.
 708                 */
 709                tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
 710                                                       false, false);
 711                tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
 712                                                       false, false);
 713                initialized = true;
 714        }
 715
 716        /* Get tomoyo_realpath of program. */
 717        retval = -ENOENT;
 718        /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
 719        real_program_name = tomoyo_realpath(original_name);
 720        if (!real_program_name)
 721                goto out;
 722        /* Get tomoyo_realpath of symbolic link. */
 723        symlink_program_name = tomoyo_realpath_nofollow(original_name);
 724        if (!symlink_program_name)
 725                goto out;
 726
 727        r.name = real_program_name;
 728        tomoyo_fill_path_info(&r);
 729        s.name = symlink_program_name;
 730        tomoyo_fill_path_info(&s);
 731        l.name = tomoyo_get_last_name(old_domain);
 732        tomoyo_fill_path_info(&l);
 733
 734        /* Check 'alias' directive. */
 735        if (tomoyo_pathcmp(&r, &s)) {
 736                struct tomoyo_alias_entry *ptr;
 737                /* Is this program allowed to be called via symbolic links? */
 738                list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
 739                        if (ptr->is_deleted ||
 740                            tomoyo_pathcmp(&r, ptr->original_name) ||
 741                            tomoyo_pathcmp(&s, ptr->aliased_name))
 742                                continue;
 743                        memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
 744                        strncpy(real_program_name, ptr->aliased_name->name,
 745                                TOMOYO_MAX_PATHNAME_LEN - 1);
 746                        tomoyo_fill_path_info(&r);
 747                        break;
 748                }
 749        }
 750
 751        /* Check execute permission. */
 752        retval = tomoyo_check_exec_perm(old_domain, &r);
 753        if (retval < 0)
 754                goto out;
 755
 756        new_domain_name = tmp->buffer;
 757        if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
 758                /* Transit to the child of tomoyo_kernel_domain domain. */
 759                snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
 760                         TOMOYO_ROOT_NAME " " "%s", real_program_name);
 761        } else if (old_domain == &tomoyo_kernel_domain &&
 762                   !tomoyo_policy_loaded) {
 763                /*
 764                 * Needn't to transit from kernel domain before starting
 765                 * /sbin/init. But transit from kernel domain if executing
 766                 * initializers because they might start before /sbin/init.
 767                 */
 768                domain = old_domain;
 769        } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
 770                /* Keep current domain. */
 771                domain = old_domain;
 772        } else {
 773                /* Normal domain transition. */
 774                snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
 775                         "%s %s", old_domain_name, real_program_name);
 776        }
 777        if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
 778                goto done;
 779        domain = tomoyo_find_domain(new_domain_name);
 780        if (domain)
 781                goto done;
 782        if (is_enforce)
 783                goto done;
 784        domain = tomoyo_find_or_assign_new_domain(new_domain_name,
 785                                                  old_domain->profile);
 786 done:
 787        if (domain)
 788                goto out;
 789        printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
 790               new_domain_name);
 791        if (is_enforce)
 792                retval = -EPERM;
 793        else
 794                old_domain->transition_failed = true;
 795 out:
 796        if (!domain)
 797                domain = old_domain;
 798        /* Update reference count on "struct tomoyo_domain_info". */
 799        atomic_inc(&domain->users);
 800        bprm->cred->security = domain;
 801        kfree(real_program_name);
 802        kfree(symlink_program_name);
 803        kfree(tmp);
 804        return retval;
 805}
 806