file.c revision bcb86975dbcc24f820f1a37918d53914af29ace7
1/* 2 * security/tomoyo/file.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#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) 16 17/* Structure for "allow_read" keyword. */ 18struct tomoyo_globally_readable_file_entry { 19 struct list_head list; 20 const struct tomoyo_path_info *filename; 21 bool is_deleted; 22}; 23 24/* Structure for "file_pattern" keyword. */ 25struct tomoyo_pattern_entry { 26 struct list_head list; 27 const struct tomoyo_path_info *pattern; 28 bool is_deleted; 29}; 30 31/* Structure for "deny_rewrite" keyword. */ 32struct tomoyo_no_rewrite_entry { 33 struct list_head list; 34 const struct tomoyo_path_info *pattern; 35 bool is_deleted; 36}; 37 38/* Keyword array for single path operations. */ 39static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { 40 [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", 41 [TOMOYO_TYPE_EXECUTE_ACL] = "execute", 42 [TOMOYO_TYPE_READ_ACL] = "read", 43 [TOMOYO_TYPE_WRITE_ACL] = "write", 44 [TOMOYO_TYPE_CREATE_ACL] = "create", 45 [TOMOYO_TYPE_UNLINK_ACL] = "unlink", 46 [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", 47 [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", 48 [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", 49 [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", 50 [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", 51 [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", 52 [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", 53 [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", 54 [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", 55}; 56 57/* Keyword array for double path operations. */ 58static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { 59 [TOMOYO_TYPE_LINK_ACL] = "link", 60 [TOMOYO_TYPE_RENAME_ACL] = "rename", 61}; 62 63/** 64 * tomoyo_sp2keyword - Get the name of single path operation. 65 * 66 * @operation: Type of operation. 67 * 68 * Returns the name of single path operation. 69 */ 70const char *tomoyo_sp2keyword(const u8 operation) 71{ 72 return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) 73 ? tomoyo_sp_keyword[operation] : NULL; 74} 75 76/** 77 * tomoyo_dp2keyword - Get the name of double path operation. 78 * 79 * @operation: Type of operation. 80 * 81 * Returns the name of double path operation. 82 */ 83const char *tomoyo_dp2keyword(const u8 operation) 84{ 85 return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) 86 ? tomoyo_dp_keyword[operation] : NULL; 87} 88 89/** 90 * tomoyo_strendswith - Check whether the token ends with the given token. 91 * 92 * @name: The token to check. 93 * @tail: The token to find. 94 * 95 * Returns true if @name ends with @tail, false otherwise. 96 */ 97static bool tomoyo_strendswith(const char *name, const char *tail) 98{ 99 int len; 100 101 if (!name || !tail) 102 return false; 103 len = strlen(name) - strlen(tail); 104 return len >= 0 && !strcmp(name + len, tail); 105} 106 107/** 108 * tomoyo_get_path - Get realpath. 109 * 110 * @path: Pointer to "struct path". 111 * 112 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 113 */ 114static struct tomoyo_path_info *tomoyo_get_path(struct path *path) 115{ 116 int error; 117 struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); 118 119 if (!buf) 120 return NULL; 121 /* Reserve one byte for appending "/". */ 122 error = tomoyo_realpath_from_path2(path, buf->body, 123 sizeof(buf->body) - 2); 124 if (!error) { 125 buf->head.name = buf->body; 126 tomoyo_fill_path_info(&buf->head); 127 return &buf->head; 128 } 129 tomoyo_free(buf); 130 return NULL; 131} 132 133/* Lock for domain->acl_info_list. */ 134DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); 135 136static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, 137 const char *filename2, 138 struct tomoyo_domain_info * 139 const domain, const bool is_delete); 140static int tomoyo_update_single_path_acl(const u8 type, const char *filename, 141 struct tomoyo_domain_info * 142 const domain, const bool is_delete); 143 144/* The list for "struct tomoyo_globally_readable_file_entry". */ 145static LIST_HEAD(tomoyo_globally_readable_list); 146static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); 147 148/** 149 * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 150 * 151 * @filename: Filename unconditionally permitted to open() for reading. 152 * @is_delete: True if it is a delete request. 153 * 154 * Returns 0 on success, negative value otherwise. 155 */ 156static int tomoyo_update_globally_readable_entry(const char *filename, 157 const bool is_delete) 158{ 159 struct tomoyo_globally_readable_file_entry *new_entry; 160 struct tomoyo_globally_readable_file_entry *ptr; 161 const struct tomoyo_path_info *saved_filename; 162 int error = -ENOMEM; 163 164 if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) 165 return -EINVAL; 166 saved_filename = tomoyo_save_name(filename); 167 if (!saved_filename) 168 return -ENOMEM; 169 down_write(&tomoyo_globally_readable_list_lock); 170 list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { 171 if (ptr->filename != saved_filename) 172 continue; 173 ptr->is_deleted = is_delete; 174 error = 0; 175 goto out; 176 } 177 if (is_delete) { 178 error = -ENOENT; 179 goto out; 180 } 181 new_entry = tomoyo_alloc_element(sizeof(*new_entry)); 182 if (!new_entry) 183 goto out; 184 new_entry->filename = saved_filename; 185 list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); 186 error = 0; 187 out: 188 up_write(&tomoyo_globally_readable_list_lock); 189 return error; 190} 191 192/** 193 * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 194 * 195 * @filename: The filename to check. 196 * 197 * Returns true if any domain can open @filename for reading, false otherwise. 198 */ 199static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * 200 filename) 201{ 202 struct tomoyo_globally_readable_file_entry *ptr; 203 bool found = false; 204 down_read(&tomoyo_globally_readable_list_lock); 205 list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { 206 if (!ptr->is_deleted && 207 tomoyo_path_matches_pattern(filename, ptr->filename)) { 208 found = true; 209 break; 210 } 211 } 212 up_read(&tomoyo_globally_readable_list_lock); 213 return found; 214} 215 216/** 217 * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 218 * 219 * @data: String to parse. 220 * @is_delete: True if it is a delete request. 221 * 222 * Returns 0 on success, negative value otherwise. 223 */ 224int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 225{ 226 return tomoyo_update_globally_readable_entry(data, is_delete); 227} 228 229/** 230 * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 231 * 232 * @head: Pointer to "struct tomoyo_io_buffer". 233 * 234 * Returns true on success, false otherwise. 235 */ 236bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 237{ 238 struct list_head *pos; 239 bool done = true; 240 241 down_read(&tomoyo_globally_readable_list_lock); 242 list_for_each_cookie(pos, head->read_var2, 243 &tomoyo_globally_readable_list) { 244 struct tomoyo_globally_readable_file_entry *ptr; 245 ptr = list_entry(pos, 246 struct tomoyo_globally_readable_file_entry, 247 list); 248 if (ptr->is_deleted) 249 continue; 250 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 251 ptr->filename->name); 252 if (!done) 253 break; 254 } 255 up_read(&tomoyo_globally_readable_list_lock); 256 return done; 257} 258 259/* The list for "struct tomoyo_pattern_entry". */ 260static LIST_HEAD(tomoyo_pattern_list); 261static DECLARE_RWSEM(tomoyo_pattern_list_lock); 262 263/** 264 * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 265 * 266 * @pattern: Pathname pattern. 267 * @is_delete: True if it is a delete request. 268 * 269 * Returns 0 on success, negative value otherwise. 270 */ 271static int tomoyo_update_file_pattern_entry(const char *pattern, 272 const bool is_delete) 273{ 274 struct tomoyo_pattern_entry *new_entry; 275 struct tomoyo_pattern_entry *ptr; 276 const struct tomoyo_path_info *saved_pattern; 277 int error = -ENOMEM; 278 279 if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) 280 return -EINVAL; 281 saved_pattern = tomoyo_save_name(pattern); 282 if (!saved_pattern) 283 return -ENOMEM; 284 down_write(&tomoyo_pattern_list_lock); 285 list_for_each_entry(ptr, &tomoyo_pattern_list, list) { 286 if (saved_pattern != ptr->pattern) 287 continue; 288 ptr->is_deleted = is_delete; 289 error = 0; 290 goto out; 291 } 292 if (is_delete) { 293 error = -ENOENT; 294 goto out; 295 } 296 new_entry = tomoyo_alloc_element(sizeof(*new_entry)); 297 if (!new_entry) 298 goto out; 299 new_entry->pattern = saved_pattern; 300 list_add_tail(&new_entry->list, &tomoyo_pattern_list); 301 error = 0; 302 out: 303 up_write(&tomoyo_pattern_list_lock); 304 return error; 305} 306 307/** 308 * tomoyo_get_file_pattern - Get patterned pathname. 309 * 310 * @filename: The filename to find patterned pathname. 311 * 312 * Returns pointer to pathname pattern if matched, @filename otherwise. 313 */ 314static const struct tomoyo_path_info * 315tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 316{ 317 struct tomoyo_pattern_entry *ptr; 318 const struct tomoyo_path_info *pattern = NULL; 319 320 down_read(&tomoyo_pattern_list_lock); 321 list_for_each_entry(ptr, &tomoyo_pattern_list, list) { 322 if (ptr->is_deleted) 323 continue; 324 if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 325 continue; 326 pattern = ptr->pattern; 327 if (tomoyo_strendswith(pattern->name, "/\\*")) { 328 /* Do nothing. Try to find the better match. */ 329 } else { 330 /* This would be the better match. Use this. */ 331 break; 332 } 333 } 334 up_read(&tomoyo_pattern_list_lock); 335 if (pattern) 336 filename = pattern; 337 return filename; 338} 339 340/** 341 * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 342 * 343 * @data: String to parse. 344 * @is_delete: True if it is a delete request. 345 * 346 * Returns 0 on success, negative value otherwise. 347 */ 348int tomoyo_write_pattern_policy(char *data, const bool is_delete) 349{ 350 return tomoyo_update_file_pattern_entry(data, is_delete); 351} 352 353/** 354 * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 355 * 356 * @head: Pointer to "struct tomoyo_io_buffer". 357 * 358 * Returns true on success, false otherwise. 359 */ 360bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 361{ 362 struct list_head *pos; 363 bool done = true; 364 365 down_read(&tomoyo_pattern_list_lock); 366 list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { 367 struct tomoyo_pattern_entry *ptr; 368 ptr = list_entry(pos, struct tomoyo_pattern_entry, list); 369 if (ptr->is_deleted) 370 continue; 371 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 372 "%s\n", ptr->pattern->name); 373 if (!done) 374 break; 375 } 376 up_read(&tomoyo_pattern_list_lock); 377 return done; 378} 379 380/* The list for "struct tomoyo_no_rewrite_entry". */ 381static LIST_HEAD(tomoyo_no_rewrite_list); 382static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); 383 384/** 385 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 386 * 387 * @pattern: Pathname pattern that are not rewritable by default. 388 * @is_delete: True if it is a delete request. 389 * 390 * Returns 0 on success, negative value otherwise. 391 */ 392static int tomoyo_update_no_rewrite_entry(const char *pattern, 393 const bool is_delete) 394{ 395 struct tomoyo_no_rewrite_entry *new_entry, *ptr; 396 const struct tomoyo_path_info *saved_pattern; 397 int error = -ENOMEM; 398 399 if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) 400 return -EINVAL; 401 saved_pattern = tomoyo_save_name(pattern); 402 if (!saved_pattern) 403 return -ENOMEM; 404 down_write(&tomoyo_no_rewrite_list_lock); 405 list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { 406 if (ptr->pattern != saved_pattern) 407 continue; 408 ptr->is_deleted = is_delete; 409 error = 0; 410 goto out; 411 } 412 if (is_delete) { 413 error = -ENOENT; 414 goto out; 415 } 416 new_entry = tomoyo_alloc_element(sizeof(*new_entry)); 417 if (!new_entry) 418 goto out; 419 new_entry->pattern = saved_pattern; 420 list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); 421 error = 0; 422 out: 423 up_write(&tomoyo_no_rewrite_list_lock); 424 return error; 425} 426 427/** 428 * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 429 * 430 * @filename: Filename to check. 431 * 432 * Returns true if @filename is specified by "deny_rewrite" directive, 433 * false otherwise. 434 */ 435static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) 436{ 437 struct tomoyo_no_rewrite_entry *ptr; 438 bool found = false; 439 440 down_read(&tomoyo_no_rewrite_list_lock); 441 list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { 442 if (ptr->is_deleted) 443 continue; 444 if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 445 continue; 446 found = true; 447 break; 448 } 449 up_read(&tomoyo_no_rewrite_list_lock); 450 return found; 451} 452 453/** 454 * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 455 * 456 * @data: String to parse. 457 * @is_delete: True if it is a delete request. 458 * 459 * Returns 0 on success, negative value otherwise. 460 */ 461int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 462{ 463 return tomoyo_update_no_rewrite_entry(data, is_delete); 464} 465 466/** 467 * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 468 * 469 * @head: Pointer to "struct tomoyo_io_buffer". 470 * 471 * Returns true on success, false otherwise. 472 */ 473bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 474{ 475 struct list_head *pos; 476 bool done = true; 477 478 down_read(&tomoyo_no_rewrite_list_lock); 479 list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { 480 struct tomoyo_no_rewrite_entry *ptr; 481 ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); 482 if (ptr->is_deleted) 483 continue; 484 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 485 "%s\n", ptr->pattern->name); 486 if (!done) 487 break; 488 } 489 up_read(&tomoyo_no_rewrite_list_lock); 490 return done; 491} 492 493/** 494 * tomoyo_update_file_acl - Update file's read/write/execute ACL. 495 * 496 * @filename: Filename. 497 * @perm: Permission (between 1 to 7). 498 * @domain: Pointer to "struct tomoyo_domain_info". 499 * @is_delete: True if it is a delete request. 500 * 501 * Returns 0 on success, negative value otherwise. 502 * 503 * This is legacy support interface for older policy syntax. 504 * Current policy syntax uses "allow_read/write" instead of "6", 505 * "allow_read" instead of "4", "allow_write" instead of "2", 506 * "allow_execute" instead of "1". 507 */ 508static int tomoyo_update_file_acl(const char *filename, u8 perm, 509 struct tomoyo_domain_info * const domain, 510 const bool is_delete) 511{ 512 if (perm > 7 || !perm) { 513 printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", 514 __func__, perm, filename); 515 return -EINVAL; 516 } 517 if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) 518 /* 519 * Only 'allow_mkdir' and 'allow_rmdir' are valid for 520 * directory permissions. 521 */ 522 return 0; 523 if (perm & 4) 524 tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, 525 domain, is_delete); 526 if (perm & 2) 527 tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, 528 domain, is_delete); 529 if (perm & 1) 530 tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, 531 filename, domain, is_delete); 532 return 0; 533} 534 535/** 536 * tomoyo_check_single_path_acl2 - Check permission for single path operation. 537 * 538 * @domain: Pointer to "struct tomoyo_domain_info". 539 * @filename: Filename to check. 540 * @perm: Permission. 541 * @may_use_pattern: True if patterned ACL is permitted. 542 * 543 * Returns 0 on success, -EPERM otherwise. 544 */ 545static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * 546 domain, 547 const struct tomoyo_path_info * 548 filename, 549 const u16 perm, 550 const bool may_use_pattern) 551{ 552 struct tomoyo_acl_info *ptr; 553 int error = -EPERM; 554 555 down_read(&tomoyo_domain_acl_info_list_lock); 556 list_for_each_entry(ptr, &domain->acl_info_list, list) { 557 struct tomoyo_single_path_acl_record *acl; 558 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 559 continue; 560 acl = container_of(ptr, struct tomoyo_single_path_acl_record, 561 head); 562 if (!(acl->perm & perm)) 563 continue; 564 if (may_use_pattern || !acl->filename->is_patterned) { 565 if (!tomoyo_path_matches_pattern(filename, 566 acl->filename)) 567 continue; 568 } else { 569 continue; 570 } 571 error = 0; 572 break; 573 } 574 up_read(&tomoyo_domain_acl_info_list_lock); 575 return error; 576} 577 578/** 579 * tomoyo_check_file_acl - Check permission for opening files. 580 * 581 * @domain: Pointer to "struct tomoyo_domain_info". 582 * @filename: Filename to check. 583 * @operation: Mode ("read" or "write" or "read/write" or "execute"). 584 * 585 * Returns 0 on success, -EPERM otherwise. 586 */ 587static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, 588 const struct tomoyo_path_info *filename, 589 const u8 operation) 590{ 591 u16 perm = 0; 592 593 if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 594 return 0; 595 if (operation == 6) 596 perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; 597 else if (operation == 4) 598 perm = 1 << TOMOYO_TYPE_READ_ACL; 599 else if (operation == 2) 600 perm = 1 << TOMOYO_TYPE_WRITE_ACL; 601 else if (operation == 1) 602 perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; 603 else 604 BUG(); 605 return tomoyo_check_single_path_acl2(domain, filename, perm, 606 operation != 1); 607} 608 609/** 610 * tomoyo_check_file_perm2 - Check permission for opening files. 611 * 612 * @domain: Pointer to "struct tomoyo_domain_info". 613 * @filename: Filename to check. 614 * @perm: Mode ("read" or "write" or "read/write" or "execute"). 615 * @operation: Operation name passed used for verbose mode. 616 * @mode: Access control mode. 617 * 618 * Returns 0 on success, negative value otherwise. 619 */ 620static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, 621 const struct tomoyo_path_info *filename, 622 const u8 perm, const char *operation, 623 const u8 mode) 624{ 625 const bool is_enforce = (mode == 3); 626 const char *msg = "<unknown>"; 627 int error = 0; 628 629 if (!filename) 630 return 0; 631 error = tomoyo_check_file_acl(domain, filename, perm); 632 if (error && perm == 4 && 633 (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 634 && tomoyo_is_globally_readable_file(filename)) 635 error = 0; 636 if (perm == 6) 637 msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); 638 else if (perm == 4) 639 msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); 640 else if (perm == 2) 641 msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); 642 else if (perm == 1) 643 msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); 644 else 645 BUG(); 646 if (!error) 647 return 0; 648 if (tomoyo_verbose_mode(domain)) 649 printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " 650 "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, 651 filename->name, tomoyo_get_last_name(domain)); 652 if (is_enforce) 653 return error; 654 if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 655 /* Don't use patterns for execute permission. */ 656 const struct tomoyo_path_info *patterned_file = (perm != 1) ? 657 tomoyo_get_file_pattern(filename) : filename; 658 tomoyo_update_file_acl(patterned_file->name, perm, 659 domain, false); 660 } 661 return 0; 662} 663 664/** 665 * tomoyo_write_file_policy - Update file related list. 666 * 667 * @data: String to parse. 668 * @domain: Pointer to "struct tomoyo_domain_info". 669 * @is_delete: True if it is a delete request. 670 * 671 * Returns 0 on success, negative value otherwise. 672 */ 673int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 674 const bool is_delete) 675{ 676 char *filename = strchr(data, ' '); 677 char *filename2; 678 unsigned int perm; 679 u8 type; 680 681 if (!filename) 682 return -EINVAL; 683 *filename++ = '\0'; 684 if (sscanf(data, "%u", &perm) == 1) 685 return tomoyo_update_file_acl(filename, (u8) perm, domain, 686 is_delete); 687 if (strncmp(data, "allow_", 6)) 688 goto out; 689 data += 6; 690 for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { 691 if (strcmp(data, tomoyo_sp_keyword[type])) 692 continue; 693 return tomoyo_update_single_path_acl(type, filename, 694 domain, is_delete); 695 } 696 filename2 = strchr(filename, ' '); 697 if (!filename2) 698 goto out; 699 *filename2++ = '\0'; 700 for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { 701 if (strcmp(data, tomoyo_dp_keyword[type])) 702 continue; 703 return tomoyo_update_double_path_acl(type, filename, filename2, 704 domain, is_delete); 705 } 706 out: 707 return -EINVAL; 708} 709 710/** 711 * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. 712 * 713 * @type: Type of operation. 714 * @filename: Filename. 715 * @domain: Pointer to "struct tomoyo_domain_info". 716 * @is_delete: True if it is a delete request. 717 * 718 * Returns 0 on success, negative value otherwise. 719 */ 720static int tomoyo_update_single_path_acl(const u8 type, const char *filename, 721 struct tomoyo_domain_info * 722 const domain, const bool is_delete) 723{ 724 static const u16 rw_mask = 725 (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); 726 const struct tomoyo_path_info *saved_filename; 727 struct tomoyo_acl_info *ptr; 728 struct tomoyo_single_path_acl_record *acl; 729 int error = -ENOMEM; 730 const u16 perm = 1 << type; 731 732 if (!domain) 733 return -EINVAL; 734 if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) 735 return -EINVAL; 736 saved_filename = tomoyo_save_name(filename); 737 if (!saved_filename) 738 return -ENOMEM; 739 down_write(&tomoyo_domain_acl_info_list_lock); 740 if (is_delete) 741 goto delete; 742 list_for_each_entry(ptr, &domain->acl_info_list, list) { 743 if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 744 continue; 745 acl = container_of(ptr, struct tomoyo_single_path_acl_record, 746 head); 747 if (acl->filename != saved_filename) 748 continue; 749 /* Special case. Clear all bits if marked as deleted. */ 750 if (ptr->type & TOMOYO_ACL_DELETED) 751 acl->perm = 0; 752 acl->perm |= perm; 753 if ((acl->perm & rw_mask) == rw_mask) 754 acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; 755 else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) 756 acl->perm |= rw_mask; 757 ptr->type &= ~TOMOYO_ACL_DELETED; 758 error = 0; 759 goto out; 760 } 761 /* Not found. Append it to the tail. */ 762 acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); 763 if (!acl) 764 goto out; 765 acl->perm = perm; 766 if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) 767 acl->perm |= rw_mask; 768 acl->filename = saved_filename; 769 list_add_tail(&acl->head.list, &domain->acl_info_list); 770 error = 0; 771 goto out; 772 delete: 773 error = -ENOENT; 774 list_for_each_entry(ptr, &domain->acl_info_list, list) { 775 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) 776 continue; 777 acl = container_of(ptr, struct tomoyo_single_path_acl_record, 778 head); 779 if (acl->filename != saved_filename) 780 continue; 781 acl->perm &= ~perm; 782 if ((acl->perm & rw_mask) != rw_mask) 783 acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); 784 else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) 785 acl->perm &= ~rw_mask; 786 if (!acl->perm) 787 ptr->type |= TOMOYO_ACL_DELETED; 788 error = 0; 789 break; 790 } 791 out: 792 up_write(&tomoyo_domain_acl_info_list_lock); 793 return error; 794} 795 796/** 797 * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. 798 * 799 * @type: Type of operation. 800 * @filename1: First filename. 801 * @filename2: Second filename. 802 * @domain: Pointer to "struct tomoyo_domain_info". 803 * @is_delete: True if it is a delete request. 804 * 805 * Returns 0 on success, negative value otherwise. 806 */ 807static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, 808 const char *filename2, 809 struct tomoyo_domain_info * 810 const domain, const bool is_delete) 811{ 812 const struct tomoyo_path_info *saved_filename1; 813 const struct tomoyo_path_info *saved_filename2; 814 struct tomoyo_acl_info *ptr; 815 struct tomoyo_double_path_acl_record *acl; 816 int error = -ENOMEM; 817 const u8 perm = 1 << type; 818 819 if (!domain) 820 return -EINVAL; 821 if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || 822 !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) 823 return -EINVAL; 824 saved_filename1 = tomoyo_save_name(filename1); 825 saved_filename2 = tomoyo_save_name(filename2); 826 if (!saved_filename1 || !saved_filename2) 827 return -ENOMEM; 828 down_write(&tomoyo_domain_acl_info_list_lock); 829 if (is_delete) 830 goto delete; 831 list_for_each_entry(ptr, &domain->acl_info_list, list) { 832 if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 833 continue; 834 acl = container_of(ptr, struct tomoyo_double_path_acl_record, 835 head); 836 if (acl->filename1 != saved_filename1 || 837 acl->filename2 != saved_filename2) 838 continue; 839 /* Special case. Clear all bits if marked as deleted. */ 840 if (ptr->type & TOMOYO_ACL_DELETED) 841 acl->perm = 0; 842 acl->perm |= perm; 843 ptr->type &= ~TOMOYO_ACL_DELETED; 844 error = 0; 845 goto out; 846 } 847 /* Not found. Append it to the tail. */ 848 acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); 849 if (!acl) 850 goto out; 851 acl->perm = perm; 852 acl->filename1 = saved_filename1; 853 acl->filename2 = saved_filename2; 854 list_add_tail(&acl->head.list, &domain->acl_info_list); 855 error = 0; 856 goto out; 857 delete: 858 error = -ENOENT; 859 list_for_each_entry(ptr, &domain->acl_info_list, list) { 860 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 861 continue; 862 acl = container_of(ptr, struct tomoyo_double_path_acl_record, 863 head); 864 if (acl->filename1 != saved_filename1 || 865 acl->filename2 != saved_filename2) 866 continue; 867 acl->perm &= ~perm; 868 if (!acl->perm) 869 ptr->type |= TOMOYO_ACL_DELETED; 870 error = 0; 871 break; 872 } 873 out: 874 up_write(&tomoyo_domain_acl_info_list_lock); 875 return error; 876} 877 878/** 879 * tomoyo_check_single_path_acl - Check permission for single path operation. 880 * 881 * @domain: Pointer to "struct tomoyo_domain_info". 882 * @type: Type of operation. 883 * @filename: Filename to check. 884 * 885 * Returns 0 on success, negative value otherwise. 886 */ 887static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, 888 const u8 type, 889 const struct tomoyo_path_info *filename) 890{ 891 if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 892 return 0; 893 return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); 894} 895 896/** 897 * tomoyo_check_double_path_acl - Check permission for double path operation. 898 * 899 * @domain: Pointer to "struct tomoyo_domain_info". 900 * @type: Type of operation. 901 * @filename1: First filename to check. 902 * @filename2: Second filename to check. 903 * 904 * Returns 0 on success, -EPERM otherwise. 905 */ 906static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, 907 const u8 type, 908 const struct tomoyo_path_info * 909 filename1, 910 const struct tomoyo_path_info * 911 filename2) 912{ 913 struct tomoyo_acl_info *ptr; 914 const u8 perm = 1 << type; 915 int error = -EPERM; 916 917 if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) 918 return 0; 919 down_read(&tomoyo_domain_acl_info_list_lock); 920 list_for_each_entry(ptr, &domain->acl_info_list, list) { 921 struct tomoyo_double_path_acl_record *acl; 922 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) 923 continue; 924 acl = container_of(ptr, struct tomoyo_double_path_acl_record, 925 head); 926 if (!(acl->perm & perm)) 927 continue; 928 if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) 929 continue; 930 if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) 931 continue; 932 error = 0; 933 break; 934 } 935 up_read(&tomoyo_domain_acl_info_list_lock); 936 return error; 937} 938 939/** 940 * tomoyo_check_single_path_permission2 - Check permission for single path operation. 941 * 942 * @domain: Pointer to "struct tomoyo_domain_info". 943 * @operation: Type of operation. 944 * @filename: Filename to check. 945 * @mode: Access control mode. 946 * 947 * Returns 0 on success, negative value otherwise. 948 */ 949static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * 950 const domain, u8 operation, 951 const struct tomoyo_path_info * 952 filename, const u8 mode) 953{ 954 const char *msg; 955 int error; 956 const bool is_enforce = (mode == 3); 957 958 if (!mode) 959 return 0; 960 next: 961 error = tomoyo_check_single_path_acl(domain, operation, filename); 962 msg = tomoyo_sp2keyword(operation); 963 if (!error) 964 goto ok; 965 if (tomoyo_verbose_mode(domain)) 966 printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", 967 tomoyo_get_msg(is_enforce), msg, filename->name, 968 tomoyo_get_last_name(domain)); 969 if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 970 const char *name = tomoyo_get_file_pattern(filename)->name; 971 tomoyo_update_single_path_acl(operation, name, domain, false); 972 } 973 if (!is_enforce) 974 error = 0; 975 ok: 976 /* 977 * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 978 * we need to check "allow_rewrite" permission if the filename is 979 * specified by "deny_rewrite" keyword. 980 */ 981 if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && 982 tomoyo_is_no_rewrite_file(filename)) { 983 operation = TOMOYO_TYPE_REWRITE_ACL; 984 goto next; 985 } 986 return error; 987} 988 989/** 990 * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write". 991 * 992 * @domain: Pointer to "struct tomoyo_domain_info". 993 * @filename: Filename to check. 994 * @perm: Mode ("read" or "write" or "read/write"). 995 * Returns 0 on success, negative value otherwise. 996 */ 997int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, 998 const char *filename, const u8 perm) 999{ 1000 struct tomoyo_path_info name; 1001 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1002 1003 if (!mode) 1004 return 0; 1005 name.name = filename; 1006 tomoyo_fill_path_info(&name); 1007 return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode); 1008} 1009 1010/** 1011 * tomoyo_check_exec_perm - Check permission for "execute". 1012 * 1013 * @domain: Pointer to "struct tomoyo_domain_info". 1014 * @filename: Check permission for "execute". 1015 * 1016 * Returns 0 on success, negativevalue otherwise. 1017 */ 1018int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, 1019 const struct tomoyo_path_info *filename) 1020{ 1021 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1022 1023 if (!mode) 1024 return 0; 1025 return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); 1026} 1027 1028/** 1029 * tomoyo_check_open_permission - Check permission for "read" and "write". 1030 * 1031 * @domain: Pointer to "struct tomoyo_domain_info". 1032 * @path: Pointer to "struct path". 1033 * @flag: Flags for open(). 1034 * 1035 * Returns 0 on success, negative value otherwise. 1036 */ 1037int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1038 struct path *path, const int flag) 1039{ 1040 const u8 acc_mode = ACC_MODE(flag); 1041 int error = -ENOMEM; 1042 struct tomoyo_path_info *buf; 1043 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1044 const bool is_enforce = (mode == 3); 1045 1046 if (!mode || !path->mnt) 1047 return 0; 1048 if (acc_mode == 0) 1049 return 0; 1050 if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) 1051 /* 1052 * I don't check directories here because mkdir() and rmdir() 1053 * don't call me. 1054 */ 1055 return 0; 1056 buf = tomoyo_get_path(path); 1057 if (!buf) 1058 goto out; 1059 error = 0; 1060 /* 1061 * If the filename is specified by "deny_rewrite" keyword, 1062 * we need to check "allow_rewrite" permission when the filename is not 1063 * opened for append mode or the filename is truncated at open time. 1064 */ 1065 if ((acc_mode & MAY_WRITE) && 1066 ((flag & O_TRUNC) || !(flag & O_APPEND)) && 1067 (tomoyo_is_no_rewrite_file(buf))) { 1068 error = tomoyo_check_single_path_permission2(domain, 1069 TOMOYO_TYPE_REWRITE_ACL, 1070 buf, mode); 1071 } 1072 if (!error) 1073 error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", 1074 mode); 1075 if (!error && (flag & O_TRUNC)) 1076 error = tomoyo_check_single_path_permission2(domain, 1077 TOMOYO_TYPE_TRUNCATE_ACL, 1078 buf, mode); 1079 out: 1080 tomoyo_free(buf); 1081 if (!is_enforce) 1082 error = 0; 1083 return error; 1084} 1085 1086/** 1087 * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". 1088 * 1089 * @domain: Pointer to "struct tomoyo_domain_info". 1090 * @operation: Type of operation. 1091 * @path: Pointer to "struct path". 1092 * 1093 * Returns 0 on success, negative value otherwise. 1094 */ 1095int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, 1096 const u8 operation, struct path *path) 1097{ 1098 int error = -ENOMEM; 1099 struct tomoyo_path_info *buf; 1100 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1101 const bool is_enforce = (mode == 3); 1102 1103 if (!mode || !path->mnt) 1104 return 0; 1105 buf = tomoyo_get_path(path); 1106 if (!buf) 1107 goto out; 1108 switch (operation) { 1109 case TOMOYO_TYPE_MKDIR_ACL: 1110 case TOMOYO_TYPE_RMDIR_ACL: 1111 if (!buf->is_dir) { 1112 /* 1113 * tomoyo_get_path() reserves space for appending "/." 1114 */ 1115 strcat((char *) buf->name, "/"); 1116 tomoyo_fill_path_info(buf); 1117 } 1118 } 1119 error = tomoyo_check_single_path_permission2(domain, operation, buf, 1120 mode); 1121 out: 1122 tomoyo_free(buf); 1123 if (!is_enforce) 1124 error = 0; 1125 return error; 1126} 1127 1128/** 1129 * tomoyo_check_rewrite_permission - Check permission for "rewrite". 1130 * 1131 * @domain: Pointer to "struct tomoyo_domain_info". 1132 * @filp: Pointer to "struct file". 1133 * 1134 * Returns 0 on success, negative value otherwise. 1135 */ 1136int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, 1137 struct file *filp) 1138{ 1139 int error = -ENOMEM; 1140 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1141 const bool is_enforce = (mode == 3); 1142 struct tomoyo_path_info *buf; 1143 1144 if (!mode || !filp->f_path.mnt) 1145 return 0; 1146 buf = tomoyo_get_path(&filp->f_path); 1147 if (!buf) 1148 goto out; 1149 if (!tomoyo_is_no_rewrite_file(buf)) { 1150 error = 0; 1151 goto out; 1152 } 1153 error = tomoyo_check_single_path_permission2(domain, 1154 TOMOYO_TYPE_REWRITE_ACL, 1155 buf, mode); 1156 out: 1157 tomoyo_free(buf); 1158 if (!is_enforce) 1159 error = 0; 1160 return error; 1161} 1162 1163/** 1164 * tomoyo_check_2path_perm - Check permission for "rename" and "link". 1165 * 1166 * @domain: Pointer to "struct tomoyo_domain_info". 1167 * @operation: Type of operation. 1168 * @path1: Pointer to "struct path". 1169 * @path2: Pointer to "struct path". 1170 * 1171 * Returns 0 on success, negative value otherwise. 1172 */ 1173int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, 1174 const u8 operation, struct path *path1, 1175 struct path *path2) 1176{ 1177 int error = -ENOMEM; 1178 struct tomoyo_path_info *buf1, *buf2; 1179 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); 1180 const bool is_enforce = (mode == 3); 1181 const char *msg; 1182 1183 if (!mode || !path1->mnt || !path2->mnt) 1184 return 0; 1185 buf1 = tomoyo_get_path(path1); 1186 buf2 = tomoyo_get_path(path2); 1187 if (!buf1 || !buf2) 1188 goto out; 1189 { 1190 struct dentry *dentry = path1->dentry; 1191 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { 1192 /* 1193 * tomoyo_get_path() reserves space for appending "/." 1194 */ 1195 if (!buf1->is_dir) { 1196 strcat((char *) buf1->name, "/"); 1197 tomoyo_fill_path_info(buf1); 1198 } 1199 if (!buf2->is_dir) { 1200 strcat((char *) buf2->name, "/"); 1201 tomoyo_fill_path_info(buf2); 1202 } 1203 } 1204 } 1205 error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); 1206 msg = tomoyo_dp2keyword(operation); 1207 if (!error) 1208 goto out; 1209 if (tomoyo_verbose_mode(domain)) 1210 printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " 1211 "denied for %s\n", tomoyo_get_msg(is_enforce), 1212 msg, buf1->name, buf2->name, 1213 tomoyo_get_last_name(domain)); 1214 if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { 1215 const char *name1 = tomoyo_get_file_pattern(buf1)->name; 1216 const char *name2 = tomoyo_get_file_pattern(buf2)->name; 1217 tomoyo_update_double_path_acl(operation, name1, name2, domain, 1218 false); 1219 } 1220 out: 1221 tomoyo_free(buf1); 1222 tomoyo_free(buf2); 1223 if (!is_enforce) 1224 error = 0; 1225 return error; 1226} 1227