file.c revision a230f9e7121cbcbfe23bd5a630abf6b53cece555
1/* 2 * security/tomoyo/file.c 3 * 4 * Pathname restriction functions. 5 * 6 * Copyright (C) 2005-2010 NTT DATA CORPORATION 7 */ 8 9#include "common.h" 10#include <linux/slab.h> 11 12/* Keyword array for operations with one pathname. */ 13const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { 14 [TOMOYO_TYPE_READ_WRITE] = "read/write", 15 [TOMOYO_TYPE_EXECUTE] = "execute", 16 [TOMOYO_TYPE_READ] = "read", 17 [TOMOYO_TYPE_WRITE] = "write", 18 [TOMOYO_TYPE_UNLINK] = "unlink", 19 [TOMOYO_TYPE_RMDIR] = "rmdir", 20 [TOMOYO_TYPE_TRUNCATE] = "truncate", 21 [TOMOYO_TYPE_SYMLINK] = "symlink", 22 [TOMOYO_TYPE_REWRITE] = "rewrite", 23 [TOMOYO_TYPE_CHROOT] = "chroot", 24 [TOMOYO_TYPE_UMOUNT] = "unmount", 25}; 26 27/* Keyword array for operations with one pathname and three numbers. */ 28const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = { 29 [TOMOYO_TYPE_MKBLOCK] = "mkblock", 30 [TOMOYO_TYPE_MKCHAR] = "mkchar", 31}; 32 33/* Keyword array for operations with two pathnames. */ 34const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { 35 [TOMOYO_TYPE_LINK] = "link", 36 [TOMOYO_TYPE_RENAME] = "rename", 37 [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", 38}; 39 40/* Keyword array for operations with one pathname and one number. */ 41const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 42 [TOMOYO_TYPE_CREATE] = "create", 43 [TOMOYO_TYPE_MKDIR] = "mkdir", 44 [TOMOYO_TYPE_MKFIFO] = "mkfifo", 45 [TOMOYO_TYPE_MKSOCK] = "mksock", 46 [TOMOYO_TYPE_IOCTL] = "ioctl", 47 [TOMOYO_TYPE_CHMOD] = "chmod", 48 [TOMOYO_TYPE_CHOWN] = "chown", 49 [TOMOYO_TYPE_CHGRP] = "chgrp", 50}; 51 52static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { 53 [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN, 54 [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, 55 [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, 56 [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, 57 [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, 58 [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, 59 [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, 60 [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, 61 [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE, 62 [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, 63 [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, 64}; 65 66static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { 67 [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, 68 [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, 69}; 70 71static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { 72 [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, 73 [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, 74 [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, 75}; 76 77static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { 78 [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, 79 [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, 80 [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, 81 [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, 82 [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, 83 [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, 84 [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, 85 [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, 86}; 87 88void tomoyo_put_name_union(struct tomoyo_name_union *ptr) 89{ 90 if (!ptr) 91 return; 92 if (ptr->is_group) 93 tomoyo_put_group(ptr->group); 94 else 95 tomoyo_put_name(ptr->filename); 96} 97 98bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, 99 const struct tomoyo_name_union *ptr) 100{ 101 if (ptr->is_group) 102 return tomoyo_path_matches_group(name, ptr->group); 103 return tomoyo_path_matches_pattern(name, ptr->filename); 104} 105 106void tomoyo_put_number_union(struct tomoyo_number_union *ptr) 107{ 108 if (ptr && ptr->is_group) 109 tomoyo_put_group(ptr->group); 110} 111 112bool tomoyo_compare_number_union(const unsigned long value, 113 const struct tomoyo_number_union *ptr) 114{ 115 if (ptr->is_group) 116 return tomoyo_number_matches_group(value, value, ptr->group); 117 return value >= ptr->values[0] && value <= ptr->values[1]; 118} 119 120static void tomoyo_add_slash(struct tomoyo_path_info *buf) 121{ 122 if (buf->is_dir) 123 return; 124 /* 125 * This is OK because tomoyo_encode() reserves space for appending "/". 126 */ 127 strcat((char *) buf->name, "/"); 128 tomoyo_fill_path_info(buf); 129} 130 131/** 132 * tomoyo_strendswith - Check whether the token ends with the given token. 133 * 134 * @name: The token to check. 135 * @tail: The token to find. 136 * 137 * Returns true if @name ends with @tail, false otherwise. 138 */ 139static bool tomoyo_strendswith(const char *name, const char *tail) 140{ 141 int len; 142 143 if (!name || !tail) 144 return false; 145 len = strlen(name) - strlen(tail); 146 return len >= 0 && !strcmp(name + len, tail); 147} 148 149/** 150 * tomoyo_get_realpath - Get realpath. 151 * 152 * @buf: Pointer to "struct tomoyo_path_info". 153 * @path: Pointer to "struct path". 154 * 155 * Returns true on success, false otherwise. 156 */ 157static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) 158{ 159 buf->name = tomoyo_realpath_from_path(path); 160 if (buf->name) { 161 tomoyo_fill_path_info(buf); 162 return true; 163 } 164 return false; 165} 166 167/** 168 * tomoyo_audit_path_log - Audit path request log. 169 * 170 * @r: Pointer to "struct tomoyo_request_info". 171 * 172 * Returns 0 on success, negative value otherwise. 173 */ 174static int tomoyo_audit_path_log(struct tomoyo_request_info *r) 175{ 176 const char *operation = tomoyo_path_keyword[r->param.path.operation]; 177 const struct tomoyo_path_info *filename = r->param.path.filename; 178 if (r->granted) 179 return 0; 180 tomoyo_warn_log(r, "%s %s", operation, filename->name); 181 return tomoyo_supervisor(r, "allow_%s %s\n", operation, 182 tomoyo_file_pattern(filename)); 183} 184 185/** 186 * tomoyo_audit_path2_log - Audit path/path request log. 187 * 188 * @r: Pointer to "struct tomoyo_request_info". 189 * 190 * Returns 0 on success, negative value otherwise. 191 */ 192static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) 193{ 194 const char *operation = tomoyo_path2_keyword[r->param.path2.operation]; 195 const struct tomoyo_path_info *filename1 = r->param.path2.filename1; 196 const struct tomoyo_path_info *filename2 = r->param.path2.filename2; 197 if (r->granted) 198 return 0; 199 tomoyo_warn_log(r, "%s %s %s", operation, filename1->name, 200 filename2->name); 201 return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, 202 tomoyo_file_pattern(filename1), 203 tomoyo_file_pattern(filename2)); 204} 205 206/** 207 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. 208 * 209 * @r: Pointer to "struct tomoyo_request_info". 210 * 211 * Returns 0 on success, negative value otherwise. 212 */ 213static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) 214{ 215 const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation]; 216 const struct tomoyo_path_info *filename = r->param.mkdev.filename; 217 const unsigned int major = r->param.mkdev.major; 218 const unsigned int minor = r->param.mkdev.minor; 219 const unsigned int mode = r->param.mkdev.mode; 220 if (r->granted) 221 return 0; 222 tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode, 223 major, minor); 224 return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation, 225 tomoyo_file_pattern(filename), mode, major, 226 minor); 227} 228 229/** 230 * tomoyo_audit_path_number_log - Audit path/number request log. 231 * 232 * @r: Pointer to "struct tomoyo_request_info". 233 * @error: Error code. 234 * 235 * Returns 0 on success, negative value otherwise. 236 */ 237static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) 238{ 239 const u8 type = r->param.path_number.operation; 240 u8 radix; 241 const struct tomoyo_path_info *filename = r->param.path_number.filename; 242 const char *operation = tomoyo_path_number_keyword[type]; 243 char buffer[64]; 244 if (r->granted) 245 return 0; 246 switch (type) { 247 case TOMOYO_TYPE_CREATE: 248 case TOMOYO_TYPE_MKDIR: 249 case TOMOYO_TYPE_MKFIFO: 250 case TOMOYO_TYPE_MKSOCK: 251 case TOMOYO_TYPE_CHMOD: 252 radix = TOMOYO_VALUE_TYPE_OCTAL; 253 break; 254 case TOMOYO_TYPE_IOCTL: 255 radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; 256 break; 257 default: 258 radix = TOMOYO_VALUE_TYPE_DECIMAL; 259 break; 260 } 261 tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, 262 radix); 263 tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer); 264 return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, 265 tomoyo_file_pattern(filename), buffer); 266} 267 268static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, 269 const struct tomoyo_acl_head *b) 270{ 271 return container_of(a, struct tomoyo_globally_readable_file_entry, 272 head)->filename == 273 container_of(b, struct tomoyo_globally_readable_file_entry, 274 head)->filename; 275} 276 277/** 278 * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. 279 * 280 * @filename: Filename unconditionally permitted to open() for reading. 281 * @is_delete: True if it is a delete request. 282 * 283 * Returns 0 on success, negative value otherwise. 284 * 285 * Caller holds tomoyo_read_lock(). 286 */ 287static int tomoyo_update_globally_readable_entry(const char *filename, 288 const bool is_delete) 289{ 290 struct tomoyo_globally_readable_file_entry e = { }; 291 int error; 292 293 if (!tomoyo_correct_word(filename)) 294 return -EINVAL; 295 e.filename = tomoyo_get_name(filename); 296 if (!e.filename) 297 return -ENOMEM; 298 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 299 &tomoyo_policy_list 300 [TOMOYO_ID_GLOBALLY_READABLE], 301 tomoyo_same_globally_readable); 302 tomoyo_put_name(e.filename); 303 return error; 304} 305 306/** 307 * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. 308 * 309 * @filename: The filename to check. 310 * 311 * Returns true if any domain can open @filename for reading, false otherwise. 312 * 313 * Caller holds tomoyo_read_lock(). 314 */ 315static bool tomoyo_globally_readable_file(const struct tomoyo_path_info * 316 filename) 317{ 318 struct tomoyo_globally_readable_file_entry *ptr; 319 bool found = false; 320 321 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 322 [TOMOYO_ID_GLOBALLY_READABLE], head.list) { 323 if (!ptr->head.is_deleted && 324 tomoyo_path_matches_pattern(filename, ptr->filename)) { 325 found = true; 326 break; 327 } 328 } 329 return found; 330} 331 332/** 333 * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. 334 * 335 * @data: String to parse. 336 * @is_delete: True if it is a delete request. 337 * 338 * Returns 0 on success, negative value otherwise. 339 * 340 * Caller holds tomoyo_read_lock(). 341 */ 342int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) 343{ 344 return tomoyo_update_globally_readable_entry(data, is_delete); 345} 346 347/** 348 * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. 349 * 350 * @head: Pointer to "struct tomoyo_io_buffer". 351 * 352 * Returns true on success, false otherwise. 353 * 354 * Caller holds tomoyo_read_lock(). 355 */ 356bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) 357{ 358 struct list_head *pos; 359 bool done = true; 360 361 list_for_each_cookie(pos, head->read_var2, 362 &tomoyo_policy_list[TOMOYO_ID_GLOBALLY_READABLE]) { 363 struct tomoyo_globally_readable_file_entry *ptr; 364 ptr = list_entry(pos, 365 struct tomoyo_globally_readable_file_entry, 366 head.list); 367 if (ptr->head.is_deleted) 368 continue; 369 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", 370 ptr->filename->name); 371 if (!done) 372 break; 373 } 374 return done; 375} 376 377static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, 378 const struct tomoyo_acl_head *b) 379{ 380 return container_of(a, struct tomoyo_pattern_entry, head)->pattern == 381 container_of(b, struct tomoyo_pattern_entry, head)->pattern; 382} 383 384/** 385 * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. 386 * 387 * @pattern: Pathname pattern. 388 * @is_delete: True if it is a delete request. 389 * 390 * Returns 0 on success, negative value otherwise. 391 * 392 * Caller holds tomoyo_read_lock(). 393 */ 394static int tomoyo_update_file_pattern_entry(const char *pattern, 395 const bool is_delete) 396{ 397 struct tomoyo_pattern_entry e = { }; 398 int error; 399 400 if (!tomoyo_correct_word(pattern)) 401 return -EINVAL; 402 e.pattern = tomoyo_get_name(pattern); 403 if (!e.pattern) 404 return -ENOMEM; 405 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 406 &tomoyo_policy_list[TOMOYO_ID_PATTERN], 407 tomoyo_same_pattern); 408 tomoyo_put_name(e.pattern); 409 return error; 410} 411 412/** 413 * tomoyo_file_pattern - Get patterned pathname. 414 * 415 * @filename: The filename to find patterned pathname. 416 * 417 * Returns pointer to pathname pattern if matched, @filename otherwise. 418 * 419 * Caller holds tomoyo_read_lock(). 420 */ 421const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename) 422{ 423 struct tomoyo_pattern_entry *ptr; 424 const struct tomoyo_path_info *pattern = NULL; 425 426 list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN], 427 head.list) { 428 if (ptr->head.is_deleted) 429 continue; 430 if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 431 continue; 432 pattern = ptr->pattern; 433 if (tomoyo_strendswith(pattern->name, "/\\*")) { 434 /* Do nothing. Try to find the better match. */ 435 } else { 436 /* This would be the better match. Use this. */ 437 break; 438 } 439 } 440 if (pattern) 441 filename = pattern; 442 return filename->name; 443} 444 445/** 446 * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. 447 * 448 * @data: String to parse. 449 * @is_delete: True if it is a delete request. 450 * 451 * Returns 0 on success, negative value otherwise. 452 * 453 * Caller holds tomoyo_read_lock(). 454 */ 455int tomoyo_write_pattern_policy(char *data, const bool is_delete) 456{ 457 return tomoyo_update_file_pattern_entry(data, is_delete); 458} 459 460/** 461 * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. 462 * 463 * @head: Pointer to "struct tomoyo_io_buffer". 464 * 465 * Returns true on success, false otherwise. 466 * 467 * Caller holds tomoyo_read_lock(). 468 */ 469bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) 470{ 471 struct list_head *pos; 472 bool done = true; 473 474 list_for_each_cookie(pos, head->read_var2, 475 &tomoyo_policy_list[TOMOYO_ID_PATTERN]) { 476 struct tomoyo_pattern_entry *ptr; 477 ptr = list_entry(pos, struct tomoyo_pattern_entry, head.list); 478 if (ptr->head.is_deleted) 479 continue; 480 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN 481 "%s\n", ptr->pattern->name); 482 if (!done) 483 break; 484 } 485 return done; 486} 487 488static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, 489 const struct tomoyo_acl_head *b) 490{ 491 return container_of(a, struct tomoyo_no_rewrite_entry, head)->pattern 492 == container_of(b, struct tomoyo_no_rewrite_entry, head) 493 ->pattern; 494} 495 496/** 497 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. 498 * 499 * @pattern: Pathname pattern that are not rewritable by default. 500 * @is_delete: True if it is a delete request. 501 * 502 * Returns 0 on success, negative value otherwise. 503 * 504 * Caller holds tomoyo_read_lock(). 505 */ 506static int tomoyo_update_no_rewrite_entry(const char *pattern, 507 const bool is_delete) 508{ 509 struct tomoyo_no_rewrite_entry e = { }; 510 int error; 511 512 if (!tomoyo_correct_word(pattern)) 513 return -EINVAL; 514 e.pattern = tomoyo_get_name(pattern); 515 if (!e.pattern) 516 return -ENOMEM; 517 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, 518 &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], 519 tomoyo_same_no_rewrite); 520 tomoyo_put_name(e.pattern); 521 return error; 522} 523 524/** 525 * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. 526 * 527 * @filename: Filename to check. 528 * 529 * Returns true if @filename is specified by "deny_rewrite" directive, 530 * false otherwise. 531 * 532 * Caller holds tomoyo_read_lock(). 533 */ 534static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename) 535{ 536 struct tomoyo_no_rewrite_entry *ptr; 537 bool found = false; 538 539 list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], 540 head.list) { 541 if (ptr->head.is_deleted) 542 continue; 543 if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) 544 continue; 545 found = true; 546 break; 547 } 548 return found; 549} 550 551/** 552 * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. 553 * 554 * @data: String to parse. 555 * @is_delete: True if it is a delete request. 556 * 557 * Returns 0 on success, negative value otherwise. 558 * 559 * Caller holds tomoyo_read_lock(). 560 */ 561int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) 562{ 563 return tomoyo_update_no_rewrite_entry(data, is_delete); 564} 565 566/** 567 * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. 568 * 569 * @head: Pointer to "struct tomoyo_io_buffer". 570 * 571 * Returns true on success, false otherwise. 572 * 573 * Caller holds tomoyo_read_lock(). 574 */ 575bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) 576{ 577 struct list_head *pos; 578 bool done = true; 579 580 list_for_each_cookie(pos, head->read_var2, 581 &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE]) { 582 struct tomoyo_no_rewrite_entry *ptr; 583 ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, 584 head.list); 585 if (ptr->head.is_deleted) 586 continue; 587 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE 588 "%s\n", ptr->pattern->name); 589 if (!done) 590 break; 591 } 592 return done; 593} 594 595static bool tomoyo_check_path_acl(const struct tomoyo_request_info *r, 596 const struct tomoyo_acl_info *ptr) 597{ 598 const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), 599 head); 600 return (acl->perm & (1 << r->param.path.operation)) && 601 tomoyo_compare_name_union(r->param.path.filename, &acl->name); 602} 603 604static bool tomoyo_check_path_number_acl(const struct tomoyo_request_info *r, 605 const struct tomoyo_acl_info *ptr) 606{ 607 const struct tomoyo_path_number_acl *acl = 608 container_of(ptr, typeof(*acl), head); 609 return (acl->perm & (1 << r->param.path_number.operation)) && 610 tomoyo_compare_number_union(r->param.path_number.number, 611 &acl->number) && 612 tomoyo_compare_name_union(r->param.path_number.filename, 613 &acl->name); 614} 615 616static bool tomoyo_check_path2_acl(const struct tomoyo_request_info *r, 617 const struct tomoyo_acl_info *ptr) 618{ 619 const struct tomoyo_path2_acl *acl = 620 container_of(ptr, typeof(*acl), head); 621 return (acl->perm & (1 << r->param.path2.operation)) && 622 tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) 623 && tomoyo_compare_name_union(r->param.path2.filename2, 624 &acl->name2); 625} 626 627static bool tomoyo_check_mkdev_acl(const struct tomoyo_request_info *r, 628 const struct tomoyo_acl_info *ptr) 629{ 630 const struct tomoyo_mkdev_acl *acl = 631 container_of(ptr, typeof(*acl), head); 632 return (acl->perm & (1 << r->param.mkdev.operation)) && 633 tomoyo_compare_number_union(r->param.mkdev.mode, 634 &acl->mode) && 635 tomoyo_compare_number_union(r->param.mkdev.major, 636 &acl->major) && 637 tomoyo_compare_number_union(r->param.mkdev.minor, 638 &acl->minor) && 639 tomoyo_compare_name_union(r->param.mkdev.filename, 640 &acl->name); 641} 642 643static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, 644 const struct tomoyo_acl_info *b) 645{ 646 const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); 647 const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); 648 return tomoyo_same_acl_head(&p1->head, &p2->head) && 649 tomoyo_same_name_union(&p1->name, &p2->name); 650} 651 652static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, 653 struct tomoyo_acl_info *b, 654 const bool is_delete) 655{ 656 u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) 657 ->perm; 658 u16 perm = *a_perm; 659 const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; 660 if (is_delete) { 661 perm &= ~b_perm; 662 if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) 663 perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); 664 else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) 665 perm &= ~TOMOYO_RW_MASK; 666 } else { 667 perm |= b_perm; 668 if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) 669 perm |= (1 << TOMOYO_TYPE_READ_WRITE); 670 else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) 671 perm |= TOMOYO_RW_MASK; 672 } 673 *a_perm = perm; 674 return !perm; 675} 676 677/** 678 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. 679 * 680 * @type: Type of operation. 681 * @filename: Filename. 682 * @domain: Pointer to "struct tomoyo_domain_info". 683 * @is_delete: True if it is a delete request. 684 * 685 * Returns 0 on success, negative value otherwise. 686 * 687 * Caller holds tomoyo_read_lock(). 688 */ 689static int tomoyo_update_path_acl(const u8 type, const char *filename, 690 struct tomoyo_domain_info * const domain, 691 const bool is_delete) 692{ 693 struct tomoyo_path_acl e = { 694 .head.type = TOMOYO_TYPE_PATH_ACL, 695 .perm = 1 << type 696 }; 697 int error; 698 if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) 699 e.perm |= TOMOYO_RW_MASK; 700 if (!tomoyo_parse_name_union(filename, &e.name)) 701 return -EINVAL; 702 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 703 tomoyo_same_path_acl, 704 tomoyo_merge_path_acl); 705 tomoyo_put_name_union(&e.name); 706 return error; 707} 708 709static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, 710 const struct tomoyo_acl_info *b) 711{ 712 const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), 713 head); 714 const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), 715 head); 716 return tomoyo_same_acl_head(&p1->head, &p2->head) 717 && tomoyo_same_name_union(&p1->name, &p2->name) 718 && tomoyo_same_number_union(&p1->mode, &p2->mode) 719 && tomoyo_same_number_union(&p1->major, &p2->major) 720 && tomoyo_same_number_union(&p1->minor, &p2->minor); 721} 722 723static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, 724 struct tomoyo_acl_info *b, 725 const bool is_delete) 726{ 727 u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, 728 head)->perm; 729 u8 perm = *a_perm; 730 const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) 731 ->perm; 732 if (is_delete) 733 perm &= ~b_perm; 734 else 735 perm |= b_perm; 736 *a_perm = perm; 737 return !perm; 738} 739 740/** 741 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. 742 * 743 * @type: Type of operation. 744 * @filename: Filename. 745 * @mode: Create mode. 746 * @major: Device major number. 747 * @minor: Device minor number. 748 * @domain: Pointer to "struct tomoyo_domain_info". 749 * @is_delete: True if it is a delete request. 750 * 751 * Returns 0 on success, negative value otherwise. 752 * 753 * Caller holds tomoyo_read_lock(). 754 */ 755static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, 756 char *mode, char *major, char *minor, 757 struct tomoyo_domain_info * const 758 domain, const bool is_delete) 759{ 760 struct tomoyo_mkdev_acl e = { 761 .head.type = TOMOYO_TYPE_MKDEV_ACL, 762 .perm = 1 << type 763 }; 764 int error = is_delete ? -ENOENT : -ENOMEM; 765 if (!tomoyo_parse_name_union(filename, &e.name) || 766 !tomoyo_parse_number_union(mode, &e.mode) || 767 !tomoyo_parse_number_union(major, &e.major) || 768 !tomoyo_parse_number_union(minor, &e.minor)) 769 goto out; 770 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 771 tomoyo_same_mkdev_acl, 772 tomoyo_merge_mkdev_acl); 773 out: 774 tomoyo_put_name_union(&e.name); 775 tomoyo_put_number_union(&e.mode); 776 tomoyo_put_number_union(&e.major); 777 tomoyo_put_number_union(&e.minor); 778 return error; 779} 780 781static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, 782 const struct tomoyo_acl_info *b) 783{ 784 const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); 785 const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); 786 return tomoyo_same_acl_head(&p1->head, &p2->head) 787 && tomoyo_same_name_union(&p1->name1, &p2->name1) 788 && tomoyo_same_name_union(&p1->name2, &p2->name2); 789} 790 791static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, 792 struct tomoyo_acl_info *b, 793 const bool is_delete) 794{ 795 u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) 796 ->perm; 797 u8 perm = *a_perm; 798 const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; 799 if (is_delete) 800 perm &= ~b_perm; 801 else 802 perm |= b_perm; 803 *a_perm = perm; 804 return !perm; 805} 806 807/** 808 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. 809 * 810 * @type: Type of operation. 811 * @filename1: First filename. 812 * @filename2: Second filename. 813 * @domain: Pointer to "struct tomoyo_domain_info". 814 * @is_delete: True if it is a delete request. 815 * 816 * Returns 0 on success, negative value otherwise. 817 * 818 * Caller holds tomoyo_read_lock(). 819 */ 820static int tomoyo_update_path2_acl(const u8 type, const char *filename1, 821 const char *filename2, 822 struct tomoyo_domain_info * const domain, 823 const bool is_delete) 824{ 825 struct tomoyo_path2_acl e = { 826 .head.type = TOMOYO_TYPE_PATH2_ACL, 827 .perm = 1 << type 828 }; 829 int error = is_delete ? -ENOENT : -ENOMEM; 830 if (!tomoyo_parse_name_union(filename1, &e.name1) || 831 !tomoyo_parse_name_union(filename2, &e.name2)) 832 goto out; 833 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 834 tomoyo_same_path2_acl, 835 tomoyo_merge_path2_acl); 836 out: 837 tomoyo_put_name_union(&e.name1); 838 tomoyo_put_name_union(&e.name2); 839 return error; 840} 841 842/** 843 * tomoyo_path_permission - Check permission for single path operation. 844 * 845 * @r: Pointer to "struct tomoyo_request_info". 846 * @operation: Type of operation. 847 * @filename: Filename to check. 848 * 849 * Returns 0 on success, negative value otherwise. 850 * 851 * Caller holds tomoyo_read_lock(). 852 */ 853int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, 854 const struct tomoyo_path_info *filename) 855{ 856 int error; 857 858 next: 859 r->type = tomoyo_p2mac[operation]; 860 r->mode = tomoyo_get_mode(r->profile, r->type); 861 if (r->mode == TOMOYO_CONFIG_DISABLED) 862 return 0; 863 r->param_type = TOMOYO_TYPE_PATH_ACL; 864 r->param.path.filename = filename; 865 r->param.path.operation = operation; 866 do { 867 tomoyo_check_acl(r, tomoyo_check_path_acl); 868 if (!r->granted && operation == TOMOYO_TYPE_READ && 869 !r->domain->ignore_global_allow_read && 870 tomoyo_globally_readable_file(filename)) 871 r->granted = true; 872 error = tomoyo_audit_path_log(r); 873 /* 874 * Do not retry for execute request, for alias may have 875 * changed. 876 */ 877 } while (error == TOMOYO_RETRY_REQUEST && 878 operation != TOMOYO_TYPE_EXECUTE); 879 /* 880 * Since "allow_truncate" doesn't imply "allow_rewrite" permission, 881 * we need to check "allow_rewrite" permission if the filename is 882 * specified by "deny_rewrite" keyword. 883 */ 884 if (!error && operation == TOMOYO_TYPE_TRUNCATE && 885 tomoyo_no_rewrite_file(filename)) { 886 operation = TOMOYO_TYPE_REWRITE; 887 goto next; 888 } 889 return error; 890} 891 892static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, 893 const struct tomoyo_acl_info *b) 894{ 895 const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), 896 head); 897 const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), 898 head); 899 return tomoyo_same_acl_head(&p1->head, &p2->head) 900 && tomoyo_same_name_union(&p1->name, &p2->name) 901 && tomoyo_same_number_union(&p1->number, &p2->number); 902} 903 904static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, 905 struct tomoyo_acl_info *b, 906 const bool is_delete) 907{ 908 u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, 909 head)->perm; 910 u8 perm = *a_perm; 911 const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) 912 ->perm; 913 if (is_delete) 914 perm &= ~b_perm; 915 else 916 perm |= b_perm; 917 *a_perm = perm; 918 return !perm; 919} 920 921/** 922 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. 923 * 924 * @type: Type of operation. 925 * @filename: Filename. 926 * @number: Number. 927 * @domain: Pointer to "struct tomoyo_domain_info". 928 * @is_delete: True if it is a delete request. 929 * 930 * Returns 0 on success, negative value otherwise. 931 */ 932static int tomoyo_update_path_number_acl(const u8 type, const char *filename, 933 char *number, 934 struct tomoyo_domain_info * const 935 domain, 936 const bool is_delete) 937{ 938 struct tomoyo_path_number_acl e = { 939 .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, 940 .perm = 1 << type 941 }; 942 int error = is_delete ? -ENOENT : -ENOMEM; 943 if (!tomoyo_parse_name_union(filename, &e.name)) 944 return -EINVAL; 945 if (!tomoyo_parse_number_union(number, &e.number)) 946 goto out; 947 error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, 948 tomoyo_same_path_number_acl, 949 tomoyo_merge_path_number_acl); 950 out: 951 tomoyo_put_name_union(&e.name); 952 tomoyo_put_number_union(&e.number); 953 return error; 954} 955 956/** 957 * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". 958 * 959 * @type: Type of operation. 960 * @path: Pointer to "struct path". 961 * @number: Number. 962 * 963 * Returns 0 on success, negative value otherwise. 964 */ 965int tomoyo_path_number_perm(const u8 type, struct path *path, 966 unsigned long number) 967{ 968 struct tomoyo_request_info r; 969 int error = -ENOMEM; 970 struct tomoyo_path_info buf; 971 int idx; 972 973 if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) 974 == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) 975 return 0; 976 idx = tomoyo_read_lock(); 977 if (!tomoyo_get_realpath(&buf, path)) 978 goto out; 979 if (type == TOMOYO_TYPE_MKDIR) 980 tomoyo_add_slash(&buf); 981 r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; 982 r.param.path_number.operation = type; 983 r.param.path_number.filename = &buf; 984 r.param.path_number.number = number; 985 do { 986 tomoyo_check_acl(&r, tomoyo_check_path_number_acl); 987 error = tomoyo_audit_path_number_log(&r); 988 } while (error == TOMOYO_RETRY_REQUEST); 989 kfree(buf.name); 990 out: 991 tomoyo_read_unlock(idx); 992 if (r.mode != TOMOYO_CONFIG_ENFORCING) 993 error = 0; 994 return error; 995} 996 997/** 998 * tomoyo_check_open_permission - Check permission for "read" and "write". 999 * 1000 * @domain: Pointer to "struct tomoyo_domain_info". 1001 * @path: Pointer to "struct path". 1002 * @flag: Flags for open(). 1003 * 1004 * Returns 0 on success, negative value otherwise. 1005 */ 1006int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 1007 struct path *path, const int flag) 1008{ 1009 const u8 acc_mode = ACC_MODE(flag); 1010 int error = -ENOMEM; 1011 struct tomoyo_path_info buf; 1012 struct tomoyo_request_info r; 1013 int idx; 1014 1015 if (!path->mnt || 1016 (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) 1017 return 0; 1018 buf.name = NULL; 1019 r.mode = TOMOYO_CONFIG_DISABLED; 1020 idx = tomoyo_read_lock(); 1021 if (!tomoyo_get_realpath(&buf, path)) 1022 goto out; 1023 error = 0; 1024 /* 1025 * If the filename is specified by "deny_rewrite" keyword, 1026 * we need to check "allow_rewrite" permission when the filename is not 1027 * opened for append mode or the filename is truncated at open time. 1028 */ 1029 if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) 1030 && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) 1031 != TOMOYO_CONFIG_DISABLED) { 1032 if (!tomoyo_get_realpath(&buf, path)) { 1033 error = -ENOMEM; 1034 goto out; 1035 } 1036 if (tomoyo_no_rewrite_file(&buf)) 1037 error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, 1038 &buf); 1039 } 1040 if (!error && acc_mode && 1041 tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) 1042 != TOMOYO_CONFIG_DISABLED) { 1043 u8 operation; 1044 if (!buf.name && !tomoyo_get_realpath(&buf, path)) { 1045 error = -ENOMEM; 1046 goto out; 1047 } 1048 if (acc_mode == (MAY_READ | MAY_WRITE)) 1049 operation = TOMOYO_TYPE_READ_WRITE; 1050 else if (acc_mode == MAY_READ) 1051 operation = TOMOYO_TYPE_READ; 1052 else 1053 operation = TOMOYO_TYPE_WRITE; 1054 error = tomoyo_path_permission(&r, operation, &buf); 1055 } 1056 out: 1057 kfree(buf.name); 1058 tomoyo_read_unlock(idx); 1059 if (r.mode != TOMOYO_CONFIG_ENFORCING) 1060 error = 0; 1061 return error; 1062} 1063 1064/** 1065 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". 1066 * 1067 * @operation: Type of operation. 1068 * @path: Pointer to "struct path". 1069 * 1070 * Returns 0 on success, negative value otherwise. 1071 */ 1072int tomoyo_path_perm(const u8 operation, struct path *path) 1073{ 1074 int error = -ENOMEM; 1075 struct tomoyo_path_info buf; 1076 struct tomoyo_request_info r; 1077 int idx; 1078 1079 if (!path->mnt) 1080 return 0; 1081 if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) 1082 == TOMOYO_CONFIG_DISABLED) 1083 return 0; 1084 buf.name = NULL; 1085 idx = tomoyo_read_lock(); 1086 if (!tomoyo_get_realpath(&buf, path)) 1087 goto out; 1088 switch (operation) { 1089 case TOMOYO_TYPE_REWRITE: 1090 if (!tomoyo_no_rewrite_file(&buf)) { 1091 error = 0; 1092 goto out; 1093 } 1094 break; 1095 case TOMOYO_TYPE_RMDIR: 1096 case TOMOYO_TYPE_CHROOT: 1097 case TOMOYO_TYPE_UMOUNT: 1098 tomoyo_add_slash(&buf); 1099 break; 1100 } 1101 error = tomoyo_path_permission(&r, operation, &buf); 1102 out: 1103 kfree(buf.name); 1104 tomoyo_read_unlock(idx); 1105 if (r.mode != TOMOYO_CONFIG_ENFORCING) 1106 error = 0; 1107 return error; 1108} 1109 1110/** 1111 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". 1112 * 1113 * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) 1114 * @path: Pointer to "struct path". 1115 * @mode: Create mode. 1116 * @dev: Device number. 1117 * 1118 * Returns 0 on success, negative value otherwise. 1119 */ 1120int tomoyo_mkdev_perm(const u8 operation, struct path *path, 1121 const unsigned int mode, unsigned int dev) 1122{ 1123 struct tomoyo_request_info r; 1124 int error = -ENOMEM; 1125 struct tomoyo_path_info buf; 1126 int idx; 1127 1128 if (!path->mnt || 1129 tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) 1130 == TOMOYO_CONFIG_DISABLED) 1131 return 0; 1132 idx = tomoyo_read_lock(); 1133 error = -ENOMEM; 1134 if (tomoyo_get_realpath(&buf, path)) { 1135 dev = new_decode_dev(dev); 1136 r.param_type = TOMOYO_TYPE_MKDEV_ACL; 1137 r.param.mkdev.filename = &buf; 1138 r.param.mkdev.operation = operation; 1139 r.param.mkdev.mode = mode; 1140 r.param.mkdev.major = MAJOR(dev); 1141 r.param.mkdev.minor = MINOR(dev); 1142 tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); 1143 error = tomoyo_audit_mkdev_log(&r); 1144 kfree(buf.name); 1145 } 1146 tomoyo_read_unlock(idx); 1147 if (r.mode != TOMOYO_CONFIG_ENFORCING) 1148 error = 0; 1149 return error; 1150} 1151 1152/** 1153 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". 1154 * 1155 * @operation: Type of operation. 1156 * @path1: Pointer to "struct path". 1157 * @path2: Pointer to "struct path". 1158 * 1159 * Returns 0 on success, negative value otherwise. 1160 */ 1161int tomoyo_path2_perm(const u8 operation, struct path *path1, 1162 struct path *path2) 1163{ 1164 int error = -ENOMEM; 1165 struct tomoyo_path_info buf1; 1166 struct tomoyo_path_info buf2; 1167 struct tomoyo_request_info r; 1168 int idx; 1169 1170 if (!path1->mnt || !path2->mnt || 1171 tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) 1172 == TOMOYO_CONFIG_DISABLED) 1173 return 0; 1174 buf1.name = NULL; 1175 buf2.name = NULL; 1176 idx = tomoyo_read_lock(); 1177 if (!tomoyo_get_realpath(&buf1, path1) || 1178 !tomoyo_get_realpath(&buf2, path2)) 1179 goto out; 1180 switch (operation) { 1181 struct dentry *dentry; 1182 case TOMOYO_TYPE_RENAME: 1183 case TOMOYO_TYPE_LINK: 1184 dentry = path1->dentry; 1185 if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) 1186 break; 1187 /* fall through */ 1188 case TOMOYO_TYPE_PIVOT_ROOT: 1189 tomoyo_add_slash(&buf1); 1190 tomoyo_add_slash(&buf2); 1191 break; 1192 } 1193 r.param_type = TOMOYO_TYPE_PATH2_ACL; 1194 r.param.path2.operation = operation; 1195 r.param.path2.filename1 = &buf1; 1196 r.param.path2.filename2 = &buf2; 1197 do { 1198 tomoyo_check_acl(&r, tomoyo_check_path2_acl); 1199 error = tomoyo_audit_path2_log(&r); 1200 } while (error == TOMOYO_RETRY_REQUEST); 1201 out: 1202 kfree(buf1.name); 1203 kfree(buf2.name); 1204 tomoyo_read_unlock(idx); 1205 if (r.mode != TOMOYO_CONFIG_ENFORCING) 1206 error = 0; 1207 return error; 1208} 1209 1210/** 1211 * tomoyo_write_file_policy - Update file related list. 1212 * 1213 * @data: String to parse. 1214 * @domain: Pointer to "struct tomoyo_domain_info". 1215 * @is_delete: True if it is a delete request. 1216 * 1217 * Returns 0 on success, negative value otherwise. 1218 * 1219 * Caller holds tomoyo_read_lock(). 1220 */ 1221int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 1222 const bool is_delete) 1223{ 1224 char *w[5]; 1225 u8 type; 1226 if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) 1227 return -EINVAL; 1228 if (strncmp(w[0], "allow_", 6)) 1229 goto out; 1230 w[0] += 6; 1231 for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { 1232 if (strcmp(w[0], tomoyo_path_keyword[type])) 1233 continue; 1234 return tomoyo_update_path_acl(type, w[1], domain, is_delete); 1235 } 1236 if (!w[2][0]) 1237 goto out; 1238 for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { 1239 if (strcmp(w[0], tomoyo_path2_keyword[type])) 1240 continue; 1241 return tomoyo_update_path2_acl(type, w[1], w[2], domain, 1242 is_delete); 1243 } 1244 for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { 1245 if (strcmp(w[0], tomoyo_path_number_keyword[type])) 1246 continue; 1247 return tomoyo_update_path_number_acl(type, w[1], w[2], domain, 1248 is_delete); 1249 } 1250 if (!w[3][0] || !w[4][0]) 1251 goto out; 1252 for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { 1253 if (strcmp(w[0], tomoyo_mkdev_keyword[type])) 1254 continue; 1255 return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], 1256 w[4], domain, is_delete); 1257 } 1258 out: 1259 return -EINVAL; 1260} 1261