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