root/security/tomoyo/domain.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tomoyo_update_policy
  2. tomoyo_same_acl_head
  3. tomoyo_update_domain
  4. tomoyo_check_acl
  5. tomoyo_last_word
  6. tomoyo_same_transition_control
  7. tomoyo_write_transition_control
  8. tomoyo_same_aggregator
  9. tomoyo_write_aggregator
  10. tomoyo_assign_namespace
  11. tomoyo_namespace_jump
  12. tomoyo_assign_domain
  13. tomoyo_environ
  14. tomoyo_find_next_domain
  15. tomoyo_dump_page

   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. */
  17 struct 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  */
  31 int 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  */
  73 static 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  */
  92 int 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);
 146 out:
 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  */
 161 void 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 
 170 retry:
 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". */
 193 LIST_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  */
 202 static 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  */
 219 static 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  */
 242 int 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);
 278 out:
 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  */
 297 static 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  */
 343 static 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  */
 382 static 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  */
 403 int 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);
 421 out:
 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  */
 438 static 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  */
 462 struct 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);
 477         if (!entry)
 478                 return NULL;
 479         if (mutex_lock_interruptible(&tomoyo_policy_lock))
 480                 goto out;
 481         ptr = tomoyo_find_namespace(domainname, len);
 482         if (!ptr && tomoyo_memory_ok(entry)) {
 483                 char *name = (char *) (entry + 1);
 484 
 485                 ptr = entry;
 486                 memmove(name, domainname, len);
 487                 name[len] = '\0';
 488                 entry->name = name;
 489                 tomoyo_init_policy_namespace(entry);
 490                 entry = NULL;
 491         }
 492         mutex_unlock(&tomoyo_policy_lock);
 493 out:
 494         kfree(entry);
 495         return ptr;
 496 }
 497 
 498 /**
 499  * tomoyo_namespace_jump - Check for namespace jump.
 500  *
 501  * @domainname: Name of domain.
 502  *
 503  * Returns true if namespace differs, false otherwise.
 504  */
 505 static bool tomoyo_namespace_jump(const char *domainname)
 506 {
 507         const char *namespace = tomoyo_current_namespace()->name;
 508         const int len = strlen(namespace);
 509 
 510         return strncmp(domainname, namespace, len) ||
 511                 (domainname[len] && domainname[len] != ' ');
 512 }
 513 
 514 /**
 515  * tomoyo_assign_domain - Create a domain or a namespace.
 516  *
 517  * @domainname: The name of domain.
 518  * @transit:    True if transit to domain found or created.
 519  *
 520  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
 521  *
 522  * Caller holds tomoyo_read_lock().
 523  */
 524 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
 525                                                 const bool transit)
 526 {
 527         struct tomoyo_domain_info e = { };
 528         struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
 529         bool created = false;
 530 
 531         if (entry) {
 532                 if (transit) {
 533                         /*
 534                          * Since namespace is created at runtime, profiles may
 535                          * not be created by the moment the process transits to
 536                          * that domain. Do not perform domain transition if
 537                          * profile for that domain is not yet created.
 538                          */
 539                         if (tomoyo_policy_loaded &&
 540                             !entry->ns->profile_ptr[entry->profile])
 541                                 return NULL;
 542                 }
 543                 return entry;
 544         }
 545         /* Requested domain does not exist. */
 546         /* Don't create requested domain if domainname is invalid. */
 547         if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
 548             !tomoyo_correct_domain(domainname))
 549                 return NULL;
 550         /*
 551          * Since definition of profiles and acl_groups may differ across
 552          * namespaces, do not inherit "use_profile" and "use_group" settings
 553          * by automatically creating requested domain upon domain transition.
 554          */
 555         if (transit && tomoyo_namespace_jump(domainname))
 556                 return NULL;
 557         e.ns = tomoyo_assign_namespace(domainname);
 558         if (!e.ns)
 559                 return NULL;
 560         /*
 561          * "use_profile" and "use_group" settings for automatically created
 562          * domains are inherited from current domain. These are 0 for manually
 563          * created domains.
 564          */
 565         if (transit) {
 566                 const struct tomoyo_domain_info *domain = tomoyo_domain();
 567 
 568                 e.profile = domain->profile;
 569                 memcpy(e.group, domain->group, sizeof(e.group));
 570         }
 571         e.domainname = tomoyo_get_name(domainname);
 572         if (!e.domainname)
 573                 return NULL;
 574         if (mutex_lock_interruptible(&tomoyo_policy_lock))
 575                 goto out;
 576         entry = tomoyo_find_domain(domainname);
 577         if (!entry) {
 578                 entry = tomoyo_commit_ok(&e, sizeof(e));
 579                 if (entry) {
 580                         INIT_LIST_HEAD(&entry->acl_info_list);
 581                         list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
 582                         created = true;
 583                 }
 584         }
 585         mutex_unlock(&tomoyo_policy_lock);
 586 out:
 587         tomoyo_put_name(e.domainname);
 588         if (entry && transit) {
 589                 if (created) {
 590                         struct tomoyo_request_info r;
 591                         int i;
 592 
 593                         tomoyo_init_request_info(&r, entry,
 594                                                  TOMOYO_MAC_FILE_EXECUTE);
 595                         r.granted = false;
 596                         tomoyo_write_log(&r, "use_profile %u\n",
 597                                          entry->profile);
 598                         for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
 599                                 if (test_bit(i, entry->group))
 600                                         tomoyo_write_log(&r, "use_group %u\n",
 601                                                          i);
 602                         tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
 603                 }
 604         }
 605         return entry;
 606 }
 607 
 608 /**
 609  * tomoyo_environ - Check permission for environment variable names.
 610  *
 611  * @ee: Pointer to "struct tomoyo_execve".
 612  *
 613  * Returns 0 on success, negative value otherwise.
 614  */
 615 static int tomoyo_environ(struct tomoyo_execve *ee)
 616 {
 617         struct tomoyo_request_info *r = &ee->r;
 618         struct linux_binprm *bprm = ee->bprm;
 619         /* env_page.data is allocated by tomoyo_dump_page(). */
 620         struct tomoyo_page_dump env_page = { };
 621         char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
 622         int arg_len = 0;
 623         unsigned long pos = bprm->p;
 624         int offset = pos % PAGE_SIZE;
 625         int argv_count = bprm->argc;
 626         int envp_count = bprm->envc;
 627         int error = -ENOMEM;
 628 
 629         ee->r.type = TOMOYO_MAC_ENVIRON;
 630         ee->r.profile = r->domain->profile;
 631         ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
 632                                      TOMOYO_MAC_ENVIRON);
 633         if (!r->mode || !envp_count)
 634                 return 0;
 635         arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
 636         if (!arg_ptr)
 637                 goto out;
 638         while (error == -ENOMEM) {
 639                 if (!tomoyo_dump_page(bprm, pos, &env_page))
 640                         goto out;
 641                 pos += PAGE_SIZE - offset;
 642                 /* Read. */
 643                 while (argv_count && offset < PAGE_SIZE) {
 644                         if (!env_page.data[offset++])
 645                                 argv_count--;
 646                 }
 647                 if (argv_count) {
 648                         offset = 0;
 649                         continue;
 650                 }
 651                 while (offset < PAGE_SIZE) {
 652                         const unsigned char c = env_page.data[offset++];
 653 
 654                         if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
 655                                 if (c == '=') {
 656                                         arg_ptr[arg_len++] = '\0';
 657                                 } else if (c == '\\') {
 658                                         arg_ptr[arg_len++] = '\\';
 659                                         arg_ptr[arg_len++] = '\\';
 660                                 } else if (c > ' ' && c < 127) {
 661                                         arg_ptr[arg_len++] = c;
 662                                 } else {
 663                                         arg_ptr[arg_len++] = '\\';
 664                                         arg_ptr[arg_len++] = (c >> 6) + '0';
 665                                         arg_ptr[arg_len++]
 666                                                 = ((c >> 3) & 7) + '0';
 667                                         arg_ptr[arg_len++] = (c & 7) + '0';
 668                                 }
 669                         } else {
 670                                 arg_ptr[arg_len] = '\0';
 671                         }
 672                         if (c)
 673                                 continue;
 674                         if (tomoyo_env_perm(r, arg_ptr)) {
 675                                 error = -EPERM;
 676                                 break;
 677                         }
 678                         if (!--envp_count) {
 679                                 error = 0;
 680                                 break;
 681                         }
 682                         arg_len = 0;
 683                 }
 684                 offset = 0;
 685         }
 686 out:
 687         if (r->mode != TOMOYO_CONFIG_ENFORCING)
 688                 error = 0;
 689         kfree(env_page.data);
 690         kfree(arg_ptr);
 691         return error;
 692 }
 693 
 694 /**
 695  * tomoyo_find_next_domain - Find a domain.
 696  *
 697  * @bprm: Pointer to "struct linux_binprm".
 698  *
 699  * Returns 0 on success, negative value otherwise.
 700  *
 701  * Caller holds tomoyo_read_lock().
 702  */
 703 int tomoyo_find_next_domain(struct linux_binprm *bprm)
 704 {
 705         struct tomoyo_domain_info *old_domain = tomoyo_domain();
 706         struct tomoyo_domain_info *domain = NULL;
 707         const char *original_name = bprm->filename;
 708         int retval = -ENOMEM;
 709         bool reject_on_transition_failure = false;
 710         const struct tomoyo_path_info *candidate;
 711         struct tomoyo_path_info exename;
 712         struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
 713 
 714         if (!ee)
 715                 return -ENOMEM;
 716         ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
 717         if (!ee->tmp) {
 718                 kfree(ee);
 719                 return -ENOMEM;
 720         }
 721         /* ee->dump->data is allocated by tomoyo_dump_page(). */
 722         tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
 723         ee->r.ee = ee;
 724         ee->bprm = bprm;
 725         ee->r.obj = &ee->obj;
 726         ee->obj.path1 = bprm->file->f_path;
 727         /* Get symlink's pathname of program. */
 728         retval = -ENOENT;
 729         exename.name = tomoyo_realpath_nofollow(original_name);
 730         if (!exename.name)
 731                 goto out;
 732         tomoyo_fill_path_info(&exename);
 733 retry:
 734         /* Check 'aggregator' directive. */
 735         {
 736                 struct tomoyo_aggregator *ptr;
 737                 struct list_head *list =
 738                         &old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
 739 
 740                 /* Check 'aggregator' directive. */
 741                 candidate = &exename;
 742                 list_for_each_entry_rcu(ptr, list, head.list,
 743                                         srcu_read_lock_held(&tomoyo_ss)) {
 744                         if (ptr->head.is_deleted ||
 745                             !tomoyo_path_matches_pattern(&exename,
 746                                                          ptr->original_name))
 747                                 continue;
 748                         candidate = ptr->aggregated_name;
 749                         break;
 750                 }
 751         }
 752 
 753         /* Check execute permission. */
 754         retval = tomoyo_execute_permission(&ee->r, candidate);
 755         if (retval == TOMOYO_RETRY_REQUEST)
 756                 goto retry;
 757         if (retval < 0)
 758                 goto out;
 759         /*
 760          * To be able to specify domainnames with wildcards, use the
 761          * pathname specified in the policy (which may contain
 762          * wildcard) rather than the pathname passed to execve()
 763          * (which never contains wildcard).
 764          */
 765         if (ee->r.param.path.matched_path)
 766                 candidate = ee->r.param.path.matched_path;
 767 
 768         /*
 769          * Check for domain transition preference if "file execute" matched.
 770          * If preference is given, make do_execve() fail if domain transition
 771          * has failed, for domain transition preference should be used with
 772          * destination domain defined.
 773          */
 774         if (ee->transition) {
 775                 const char *domainname = ee->transition->name;
 776 
 777                 reject_on_transition_failure = true;
 778                 if (!strcmp(domainname, "keep"))
 779                         goto force_keep_domain;
 780                 if (!strcmp(domainname, "child"))
 781                         goto force_child_domain;
 782                 if (!strcmp(domainname, "reset"))
 783                         goto force_reset_domain;
 784                 if (!strcmp(domainname, "initialize"))
 785                         goto force_initialize_domain;
 786                 if (!strcmp(domainname, "parent")) {
 787                         char *cp;
 788 
 789                         strncpy(ee->tmp, old_domain->domainname->name,
 790                                 TOMOYO_EXEC_TMPSIZE - 1);
 791                         cp = strrchr(ee->tmp, ' ');
 792                         if (cp)
 793                                 *cp = '\0';
 794                 } else if (*domainname == '<')
 795                         strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
 796                 else
 797                         snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
 798                                  old_domain->domainname->name, domainname);
 799                 goto force_jump_domain;
 800         }
 801         /*
 802          * No domain transition preference specified.
 803          * Calculate domain to transit to.
 804          */
 805         switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
 806                                        candidate)) {
 807         case TOMOYO_TRANSITION_CONTROL_RESET:
 808 force_reset_domain:
 809                 /* Transit to the root of specified namespace. */
 810                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
 811                          candidate->name);
 812                 /*
 813                  * Make do_execve() fail if domain transition across namespaces
 814                  * has failed.
 815                  */
 816                 reject_on_transition_failure = true;
 817                 break;
 818         case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
 819 force_initialize_domain:
 820                 /* Transit to the child of current namespace's root. */
 821                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
 822                          old_domain->ns->name, candidate->name);
 823                 break;
 824         case TOMOYO_TRANSITION_CONTROL_KEEP:
 825 force_keep_domain:
 826                 /* Keep current domain. */
 827                 domain = old_domain;
 828                 break;
 829         default:
 830                 if (old_domain == &tomoyo_kernel_domain &&
 831                     !tomoyo_policy_loaded) {
 832                         /*
 833                          * Needn't to transit from kernel domain before
 834                          * starting /sbin/init. But transit from kernel domain
 835                          * if executing initializers because they might start
 836                          * before /sbin/init.
 837                          */
 838                         domain = old_domain;
 839                         break;
 840                 }
 841 force_child_domain:
 842                 /* Normal domain transition. */
 843                 snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
 844                          old_domain->domainname->name, candidate->name);
 845                 break;
 846         }
 847 force_jump_domain:
 848         if (!domain)
 849                 domain = tomoyo_assign_domain(ee->tmp, true);
 850         if (domain)
 851                 retval = 0;
 852         else if (reject_on_transition_failure) {
 853                 pr_warn("ERROR: Domain '%s' not ready.\n", ee->tmp);
 854                 retval = -ENOMEM;
 855         } else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
 856                 retval = -ENOMEM;
 857         else {
 858                 retval = 0;
 859                 if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
 860                         old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
 861                         ee->r.granted = false;
 862                         tomoyo_write_log(&ee->r, "%s", tomoyo_dif
 863                                          [TOMOYO_DIF_TRANSITION_FAILED]);
 864                         pr_warn("ERROR: Domain '%s' not defined.\n", ee->tmp);
 865                 }
 866         }
 867  out:
 868         if (!domain)
 869                 domain = old_domain;
 870         /* Update reference count on "struct tomoyo_domain_info". */
 871         {
 872                 struct tomoyo_task *s = tomoyo_task(current);
 873 
 874                 s->old_domain_info = s->domain_info;
 875                 s->domain_info = domain;
 876                 atomic_inc(&domain->users);
 877         }
 878         kfree(exename.name);
 879         if (!retval) {
 880                 ee->r.domain = domain;
 881                 retval = tomoyo_environ(ee);
 882         }
 883         kfree(ee->tmp);
 884         kfree(ee->dump.data);
 885         kfree(ee);
 886         return retval;
 887 }
 888 
 889 /**
 890  * tomoyo_dump_page - Dump a page to buffer.
 891  *
 892  * @bprm: Pointer to "struct linux_binprm".
 893  * @pos:  Location to dump.
 894  * @dump: Poiner to "struct tomoyo_page_dump".
 895  *
 896  * Returns true on success, false otherwise.
 897  */
 898 bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
 899                       struct tomoyo_page_dump *dump)
 900 {
 901         struct page *page;
 902 
 903         /* dump->data is released by tomoyo_find_next_domain(). */
 904         if (!dump->data) {
 905                 dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
 906                 if (!dump->data)
 907                         return false;
 908         }
 909         /* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
 910 #ifdef CONFIG_MMU
 911         /*
 912          * This is called at execve() time in order to dig around
 913          * in the argv/environment of the new proceess
 914          * (represented by bprm).  'current' is the process doing
 915          * the execve().
 916          */
 917         if (get_user_pages_remote(current, bprm->mm, pos, 1,
 918                                 FOLL_FORCE, &page, NULL, NULL) <= 0)
 919                 return false;
 920 #else
 921         page = bprm->page[pos / PAGE_SIZE];
 922 #endif
 923         if (page != dump->page) {
 924                 const unsigned int offset = pos % PAGE_SIZE;
 925                 /*
 926                  * Maybe kmap()/kunmap() should be used here.
 927                  * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
 928                  * So do I.
 929                  */
 930                 char *kaddr = kmap_atomic(page);
 931 
 932                 dump->page = page;
 933                 memcpy(dump->data + offset, kaddr + offset,
 934                        PAGE_SIZE - offset);
 935                 kunmap_atomic(kaddr);
 936         }
 937         /* Same with put_arg_page(page) in fs/exec.c */
 938 #ifdef CONFIG_MMU
 939         put_page(page);
 940 #endif
 941         return true;
 942 }

/* [<][>][^][v][top][bottom][index][help] */