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