condition.c revision 2ca9bf453bdd478bcb6c01aa2d0bd4c2f4350563
1/* 2 * security/tomoyo/condition.c 3 * 4 * Copyright (C) 2005-2011 NTT DATA CORPORATION 5 */ 6 7#include "common.h" 8#include <linux/slab.h> 9 10/* List of "struct tomoyo_condition". */ 11LIST_HEAD(tomoyo_condition_list); 12 13/** 14 * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition". 15 * 16 * @file: Pointer to "struct file". 17 * @ptr: Pointer to "struct tomoyo_name_union". 18 * @match: True if "exec.realpath=", false if "exec.realpath!=". 19 * 20 * Returns true on success, false otherwise. 21 */ 22static bool tomoyo_scan_exec_realpath(struct file *file, 23 const struct tomoyo_name_union *ptr, 24 const bool match) 25{ 26 bool result; 27 struct tomoyo_path_info exe; 28 if (!file) 29 return false; 30 exe.name = tomoyo_realpath_from_path(&file->f_path); 31 if (!exe.name) 32 return false; 33 tomoyo_fill_path_info(&exe); 34 result = tomoyo_compare_name_union(&exe, ptr); 35 kfree(exe.name); 36 return result == match; 37} 38 39/** 40 * tomoyo_get_dqword - tomoyo_get_name() for a quoted string. 41 * 42 * @start: String to save. 43 * 44 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. 45 */ 46static const struct tomoyo_path_info *tomoyo_get_dqword(char *start) 47{ 48 char *cp = start + strlen(start) - 1; 49 if (cp == start || *start++ != '"' || *cp != '"') 50 return NULL; 51 *cp = '\0'; 52 if (*start && !tomoyo_correct_word(start)) 53 return NULL; 54 return tomoyo_get_name(start); 55} 56 57/** 58 * tomoyo_parse_name_union_quoted - Parse a quoted word. 59 * 60 * @param: Pointer to "struct tomoyo_acl_param". 61 * @ptr: Pointer to "struct tomoyo_name_union". 62 * 63 * Returns true on success, false otherwise. 64 */ 65static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param, 66 struct tomoyo_name_union *ptr) 67{ 68 char *filename = param->data; 69 if (*filename == '@') 70 return tomoyo_parse_name_union(param, ptr); 71 ptr->filename = tomoyo_get_dqword(filename); 72 return ptr->filename != NULL; 73} 74 75/** 76 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry. 77 * 78 * @a: Pointer to "struct tomoyo_condition". 79 * @b: Pointer to "struct tomoyo_condition". 80 * 81 * Returns true if @a == @b, false otherwise. 82 */ 83static inline bool tomoyo_same_condition(const struct tomoyo_condition *a, 84 const struct tomoyo_condition *b) 85{ 86 return a->size == b->size && a->condc == b->condc && 87 a->numbers_count == b->numbers_count && 88 a->names_count == b->names_count && 89 !memcmp(a + 1, b + 1, a->size - sizeof(*a)); 90} 91 92/** 93 * tomoyo_condition_type - Get condition type. 94 * 95 * @word: Keyword string. 96 * 97 * Returns one of values in "enum tomoyo_conditions_index" on success, 98 * TOMOYO_MAX_CONDITION_KEYWORD otherwise. 99 */ 100static u8 tomoyo_condition_type(const char *word) 101{ 102 u8 i; 103 for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) { 104 if (!strcmp(word, tomoyo_condition_keyword[i])) 105 break; 106 } 107 return i; 108} 109 110/* Define this to enable debug mode. */ 111/* #define DEBUG_CONDITION */ 112 113#ifdef DEBUG_CONDITION 114#define dprintk printk 115#else 116#define dprintk(...) do { } while (0) 117#endif 118 119/** 120 * tomoyo_commit_condition - Commit "struct tomoyo_condition". 121 * 122 * @entry: Pointer to "struct tomoyo_condition". 123 * 124 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. 125 * 126 * This function merges duplicated entries. This function returns NULL if 127 * @entry is not duplicated but memory quota for policy has exceeded. 128 */ 129static struct tomoyo_condition *tomoyo_commit_condition 130(struct tomoyo_condition *entry) 131{ 132 struct tomoyo_condition *ptr; 133 bool found = false; 134 if (mutex_lock_interruptible(&tomoyo_policy_lock)) { 135 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); 136 ptr = NULL; 137 found = true; 138 goto out; 139 } 140 list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) { 141 if (!tomoyo_same_condition(ptr, entry)) 142 continue; 143 /* Same entry found. Share this entry. */ 144 atomic_inc(&ptr->head.users); 145 found = true; 146 break; 147 } 148 if (!found) { 149 if (tomoyo_memory_ok(entry)) { 150 atomic_set(&entry->head.users, 1); 151 list_add_rcu(&entry->head.list, 152 &tomoyo_condition_list); 153 } else { 154 found = true; 155 ptr = NULL; 156 } 157 } 158 mutex_unlock(&tomoyo_policy_lock); 159out: 160 if (found) { 161 tomoyo_del_condition(&entry->head.list); 162 kfree(entry); 163 entry = ptr; 164 } 165 return entry; 166} 167 168/** 169 * tomoyo_get_condition - Parse condition part. 170 * 171 * @param: Pointer to "struct tomoyo_acl_param". 172 * 173 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise. 174 */ 175struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param) 176{ 177 struct tomoyo_condition *entry = NULL; 178 struct tomoyo_condition_element *condp = NULL; 179 struct tomoyo_number_union *numbers_p = NULL; 180 struct tomoyo_name_union *names_p = NULL; 181 struct tomoyo_condition e = { }; 182 char * const start_of_string = param->data; 183 char * const end_of_string = start_of_string + strlen(start_of_string); 184 char *pos; 185rerun: 186 pos = start_of_string; 187 while (1) { 188 u8 left = -1; 189 u8 right = -1; 190 char *left_word = pos; 191 char *cp; 192 char *right_word; 193 bool is_not; 194 if (!*left_word) 195 break; 196 /* 197 * Since left-hand condition does not allow use of "path_group" 198 * or "number_group" and environment variable's names do not 199 * accept '=', it is guaranteed that the original line consists 200 * of one or more repetition of $left$operator$right blocks 201 * where "$left is free from '=' and ' '" and "$operator is 202 * either '=' or '!='" and "$right is free from ' '". 203 * Therefore, we can reconstruct the original line at the end 204 * of dry run even if we overwrite $operator with '\0'. 205 */ 206 cp = strchr(pos, ' '); 207 if (cp) { 208 *cp = '\0'; /* Will restore later. */ 209 pos = cp + 1; 210 } else { 211 pos = ""; 212 } 213 right_word = strchr(left_word, '='); 214 if (!right_word || right_word == left_word) 215 goto out; 216 is_not = *(right_word - 1) == '!'; 217 if (is_not) 218 *(right_word++ - 1) = '\0'; /* Will restore later. */ 219 else if (*(right_word + 1) != '=') 220 *right_word++ = '\0'; /* Will restore later. */ 221 else 222 goto out; 223 dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word, 224 is_not ? "!" : "", right_word); 225 left = tomoyo_condition_type(left_word); 226 dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word, 227 left); 228 if (left == TOMOYO_MAX_CONDITION_KEYWORD) { 229 if (!numbers_p) { 230 e.numbers_count++; 231 } else { 232 e.numbers_count--; 233 left = TOMOYO_NUMBER_UNION; 234 param->data = left_word; 235 if (*left_word == '@' || 236 !tomoyo_parse_number_union(param, 237 numbers_p++)) 238 goto out; 239 } 240 } 241 if (!condp) 242 e.condc++; 243 else 244 e.condc--; 245 if (left == TOMOYO_EXEC_REALPATH || 246 left == TOMOYO_SYMLINK_TARGET) { 247 if (!names_p) { 248 e.names_count++; 249 } else { 250 e.names_count--; 251 right = TOMOYO_NAME_UNION; 252 param->data = right_word; 253 if (!tomoyo_parse_name_union_quoted(param, 254 names_p++)) 255 goto out; 256 } 257 goto store_value; 258 } 259 right = tomoyo_condition_type(right_word); 260 if (right == TOMOYO_MAX_CONDITION_KEYWORD) { 261 if (!numbers_p) { 262 e.numbers_count++; 263 } else { 264 e.numbers_count--; 265 right = TOMOYO_NUMBER_UNION; 266 param->data = right_word; 267 if (!tomoyo_parse_number_union(param, 268 numbers_p++)) 269 goto out; 270 } 271 } 272store_value: 273 if (!condp) { 274 dprintk(KERN_WARNING "%u: dry_run left=%u right=%u " 275 "match=%u\n", __LINE__, left, right, !is_not); 276 continue; 277 } 278 condp->left = left; 279 condp->right = right; 280 condp->equals = !is_not; 281 dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n", 282 __LINE__, condp->left, condp->right, 283 condp->equals); 284 condp++; 285 } 286 dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u\n", 287 __LINE__, e.condc, e.numbers_count, e.names_count); 288 if (entry) { 289 BUG_ON(e.names_count | e.numbers_count | e.condc); 290 return tomoyo_commit_condition(entry); 291 } 292 e.size = sizeof(*entry) 293 + e.condc * sizeof(struct tomoyo_condition_element) 294 + e.numbers_count * sizeof(struct tomoyo_number_union) 295 + e.names_count * sizeof(struct tomoyo_name_union); 296 entry = kzalloc(e.size, GFP_NOFS); 297 if (!entry) 298 return NULL; 299 *entry = e; 300 condp = (struct tomoyo_condition_element *) (entry + 1); 301 numbers_p = (struct tomoyo_number_union *) (condp + e.condc); 302 names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count); 303 { 304 bool flag = false; 305 for (pos = start_of_string; pos < end_of_string; pos++) { 306 if (*pos) 307 continue; 308 if (flag) /* Restore " ". */ 309 *pos = ' '; 310 else if (*(pos + 1) == '=') /* Restore "!=". */ 311 *pos = '!'; 312 else /* Restore "=". */ 313 *pos = '='; 314 flag = !flag; 315 } 316 } 317 goto rerun; 318out: 319 dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__); 320 if (entry) { 321 tomoyo_del_condition(&entry->head.list); 322 kfree(entry); 323 } 324 return NULL; 325} 326 327/** 328 * tomoyo_get_attributes - Revalidate "struct inode". 329 * 330 * @obj: Pointer to "struct tomoyo_obj_info". 331 * 332 * Returns nothing. 333 */ 334void tomoyo_get_attributes(struct tomoyo_obj_info *obj) 335{ 336 u8 i; 337 struct dentry *dentry = NULL; 338 339 for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) { 340 struct inode *inode; 341 switch (i) { 342 case TOMOYO_PATH1: 343 dentry = obj->path1.dentry; 344 if (!dentry) 345 continue; 346 break; 347 case TOMOYO_PATH2: 348 dentry = obj->path2.dentry; 349 if (!dentry) 350 continue; 351 break; 352 default: 353 if (!dentry) 354 continue; 355 dentry = dget_parent(dentry); 356 break; 357 } 358 inode = dentry->d_inode; 359 if (inode) { 360 struct tomoyo_mini_stat *stat = &obj->stat[i]; 361 stat->uid = inode->i_uid; 362 stat->gid = inode->i_gid; 363 stat->ino = inode->i_ino; 364 stat->mode = inode->i_mode; 365 stat->dev = inode->i_sb->s_dev; 366 stat->rdev = inode->i_rdev; 367 obj->stat_valid[i] = true; 368 } 369 if (i & 1) /* i == TOMOYO_PATH1_PARENT || 370 i == TOMOYO_PATH2_PARENT */ 371 dput(dentry); 372 } 373} 374 375/** 376 * tomoyo_condition - Check condition part. 377 * 378 * @r: Pointer to "struct tomoyo_request_info". 379 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL. 380 * 381 * Returns true on success, false otherwise. 382 * 383 * Caller holds tomoyo_read_lock(). 384 */ 385bool tomoyo_condition(struct tomoyo_request_info *r, 386 const struct tomoyo_condition *cond) 387{ 388 u32 i; 389 unsigned long min_v[2] = { 0, 0 }; 390 unsigned long max_v[2] = { 0, 0 }; 391 const struct tomoyo_condition_element *condp; 392 const struct tomoyo_number_union *numbers_p; 393 const struct tomoyo_name_union *names_p; 394 struct tomoyo_obj_info *obj; 395 u16 condc; 396 if (!cond) 397 return true; 398 condc = cond->condc; 399 obj = r->obj; 400 condp = (struct tomoyo_condition_element *) (cond + 1); 401 numbers_p = (const struct tomoyo_number_union *) (condp + condc); 402 names_p = (const struct tomoyo_name_union *) 403 (numbers_p + cond->numbers_count); 404 for (i = 0; i < condc; i++) { 405 const bool match = condp->equals; 406 const u8 left = condp->left; 407 const u8 right = condp->right; 408 bool is_bitop[2] = { false, false }; 409 u8 j; 410 condp++; 411 /* Check string expressions. */ 412 if (right == TOMOYO_NAME_UNION) { 413 const struct tomoyo_name_union *ptr = names_p++; 414 switch (left) { 415 struct tomoyo_path_info *symlink; 416 struct tomoyo_execve *ee; 417 struct file *file; 418 case TOMOYO_SYMLINK_TARGET: 419 symlink = obj ? obj->symlink_target : NULL; 420 if (!symlink || 421 !tomoyo_compare_name_union(symlink, ptr) 422 == match) 423 goto out; 424 break; 425 case TOMOYO_EXEC_REALPATH: 426 ee = r->ee; 427 file = ee ? ee->bprm->file : NULL; 428 if (!tomoyo_scan_exec_realpath(file, ptr, 429 match)) 430 goto out; 431 break; 432 } 433 continue; 434 } 435 /* Check numeric or bit-op expressions. */ 436 for (j = 0; j < 2; j++) { 437 const u8 index = j ? right : left; 438 unsigned long value = 0; 439 switch (index) { 440 case TOMOYO_TASK_UID: 441 value = current_uid(); 442 break; 443 case TOMOYO_TASK_EUID: 444 value = current_euid(); 445 break; 446 case TOMOYO_TASK_SUID: 447 value = current_suid(); 448 break; 449 case TOMOYO_TASK_FSUID: 450 value = current_fsuid(); 451 break; 452 case TOMOYO_TASK_GID: 453 value = current_gid(); 454 break; 455 case TOMOYO_TASK_EGID: 456 value = current_egid(); 457 break; 458 case TOMOYO_TASK_SGID: 459 value = current_sgid(); 460 break; 461 case TOMOYO_TASK_FSGID: 462 value = current_fsgid(); 463 break; 464 case TOMOYO_TASK_PID: 465 value = tomoyo_sys_getpid(); 466 break; 467 case TOMOYO_TASK_PPID: 468 value = tomoyo_sys_getppid(); 469 break; 470 case TOMOYO_TYPE_IS_SOCKET: 471 value = S_IFSOCK; 472 break; 473 case TOMOYO_TYPE_IS_SYMLINK: 474 value = S_IFLNK; 475 break; 476 case TOMOYO_TYPE_IS_FILE: 477 value = S_IFREG; 478 break; 479 case TOMOYO_TYPE_IS_BLOCK_DEV: 480 value = S_IFBLK; 481 break; 482 case TOMOYO_TYPE_IS_DIRECTORY: 483 value = S_IFDIR; 484 break; 485 case TOMOYO_TYPE_IS_CHAR_DEV: 486 value = S_IFCHR; 487 break; 488 case TOMOYO_TYPE_IS_FIFO: 489 value = S_IFIFO; 490 break; 491 case TOMOYO_MODE_SETUID: 492 value = S_ISUID; 493 break; 494 case TOMOYO_MODE_SETGID: 495 value = S_ISGID; 496 break; 497 case TOMOYO_MODE_STICKY: 498 value = S_ISVTX; 499 break; 500 case TOMOYO_MODE_OWNER_READ: 501 value = S_IRUSR; 502 break; 503 case TOMOYO_MODE_OWNER_WRITE: 504 value = S_IWUSR; 505 break; 506 case TOMOYO_MODE_OWNER_EXECUTE: 507 value = S_IXUSR; 508 break; 509 case TOMOYO_MODE_GROUP_READ: 510 value = S_IRGRP; 511 break; 512 case TOMOYO_MODE_GROUP_WRITE: 513 value = S_IWGRP; 514 break; 515 case TOMOYO_MODE_GROUP_EXECUTE: 516 value = S_IXGRP; 517 break; 518 case TOMOYO_MODE_OTHERS_READ: 519 value = S_IROTH; 520 break; 521 case TOMOYO_MODE_OTHERS_WRITE: 522 value = S_IWOTH; 523 break; 524 case TOMOYO_MODE_OTHERS_EXECUTE: 525 value = S_IXOTH; 526 break; 527 case TOMOYO_NUMBER_UNION: 528 /* Fetch values later. */ 529 break; 530 default: 531 if (!obj) 532 goto out; 533 if (!obj->validate_done) { 534 tomoyo_get_attributes(obj); 535 obj->validate_done = true; 536 } 537 { 538 u8 stat_index; 539 struct tomoyo_mini_stat *stat; 540 switch (index) { 541 case TOMOYO_PATH1_UID: 542 case TOMOYO_PATH1_GID: 543 case TOMOYO_PATH1_INO: 544 case TOMOYO_PATH1_MAJOR: 545 case TOMOYO_PATH1_MINOR: 546 case TOMOYO_PATH1_TYPE: 547 case TOMOYO_PATH1_DEV_MAJOR: 548 case TOMOYO_PATH1_DEV_MINOR: 549 case TOMOYO_PATH1_PERM: 550 stat_index = TOMOYO_PATH1; 551 break; 552 case TOMOYO_PATH2_UID: 553 case TOMOYO_PATH2_GID: 554 case TOMOYO_PATH2_INO: 555 case TOMOYO_PATH2_MAJOR: 556 case TOMOYO_PATH2_MINOR: 557 case TOMOYO_PATH2_TYPE: 558 case TOMOYO_PATH2_DEV_MAJOR: 559 case TOMOYO_PATH2_DEV_MINOR: 560 case TOMOYO_PATH2_PERM: 561 stat_index = TOMOYO_PATH2; 562 break; 563 case TOMOYO_PATH1_PARENT_UID: 564 case TOMOYO_PATH1_PARENT_GID: 565 case TOMOYO_PATH1_PARENT_INO: 566 case TOMOYO_PATH1_PARENT_PERM: 567 stat_index = 568 TOMOYO_PATH1_PARENT; 569 break; 570 case TOMOYO_PATH2_PARENT_UID: 571 case TOMOYO_PATH2_PARENT_GID: 572 case TOMOYO_PATH2_PARENT_INO: 573 case TOMOYO_PATH2_PARENT_PERM: 574 stat_index = 575 TOMOYO_PATH2_PARENT; 576 break; 577 default: 578 goto out; 579 } 580 if (!obj->stat_valid[stat_index]) 581 goto out; 582 stat = &obj->stat[stat_index]; 583 switch (index) { 584 case TOMOYO_PATH1_UID: 585 case TOMOYO_PATH2_UID: 586 case TOMOYO_PATH1_PARENT_UID: 587 case TOMOYO_PATH2_PARENT_UID: 588 value = stat->uid; 589 break; 590 case TOMOYO_PATH1_GID: 591 case TOMOYO_PATH2_GID: 592 case TOMOYO_PATH1_PARENT_GID: 593 case TOMOYO_PATH2_PARENT_GID: 594 value = stat->gid; 595 break; 596 case TOMOYO_PATH1_INO: 597 case TOMOYO_PATH2_INO: 598 case TOMOYO_PATH1_PARENT_INO: 599 case TOMOYO_PATH2_PARENT_INO: 600 value = stat->ino; 601 break; 602 case TOMOYO_PATH1_MAJOR: 603 case TOMOYO_PATH2_MAJOR: 604 value = MAJOR(stat->dev); 605 break; 606 case TOMOYO_PATH1_MINOR: 607 case TOMOYO_PATH2_MINOR: 608 value = MINOR(stat->dev); 609 break; 610 case TOMOYO_PATH1_TYPE: 611 case TOMOYO_PATH2_TYPE: 612 value = stat->mode & S_IFMT; 613 break; 614 case TOMOYO_PATH1_DEV_MAJOR: 615 case TOMOYO_PATH2_DEV_MAJOR: 616 value = MAJOR(stat->rdev); 617 break; 618 case TOMOYO_PATH1_DEV_MINOR: 619 case TOMOYO_PATH2_DEV_MINOR: 620 value = MINOR(stat->rdev); 621 break; 622 case TOMOYO_PATH1_PERM: 623 case TOMOYO_PATH2_PERM: 624 case TOMOYO_PATH1_PARENT_PERM: 625 case TOMOYO_PATH2_PARENT_PERM: 626 value = stat->mode & S_IALLUGO; 627 break; 628 } 629 } 630 break; 631 } 632 max_v[j] = value; 633 min_v[j] = value; 634 switch (index) { 635 case TOMOYO_MODE_SETUID: 636 case TOMOYO_MODE_SETGID: 637 case TOMOYO_MODE_STICKY: 638 case TOMOYO_MODE_OWNER_READ: 639 case TOMOYO_MODE_OWNER_WRITE: 640 case TOMOYO_MODE_OWNER_EXECUTE: 641 case TOMOYO_MODE_GROUP_READ: 642 case TOMOYO_MODE_GROUP_WRITE: 643 case TOMOYO_MODE_GROUP_EXECUTE: 644 case TOMOYO_MODE_OTHERS_READ: 645 case TOMOYO_MODE_OTHERS_WRITE: 646 case TOMOYO_MODE_OTHERS_EXECUTE: 647 is_bitop[j] = true; 648 } 649 } 650 if (left == TOMOYO_NUMBER_UNION) { 651 /* Fetch values now. */ 652 const struct tomoyo_number_union *ptr = numbers_p++; 653 min_v[0] = ptr->values[0]; 654 max_v[0] = ptr->values[1]; 655 } 656 if (right == TOMOYO_NUMBER_UNION) { 657 /* Fetch values now. */ 658 const struct tomoyo_number_union *ptr = numbers_p++; 659 if (ptr->group) { 660 if (tomoyo_number_matches_group(min_v[0], 661 max_v[0], 662 ptr->group) 663 == match) 664 continue; 665 } else { 666 if ((min_v[0] <= ptr->values[1] && 667 max_v[0] >= ptr->values[0]) == match) 668 continue; 669 } 670 goto out; 671 } 672 /* 673 * Bit operation is valid only when counterpart value 674 * represents permission. 675 */ 676 if (is_bitop[0] && is_bitop[1]) { 677 goto out; 678 } else if (is_bitop[0]) { 679 switch (right) { 680 case TOMOYO_PATH1_PERM: 681 case TOMOYO_PATH1_PARENT_PERM: 682 case TOMOYO_PATH2_PERM: 683 case TOMOYO_PATH2_PARENT_PERM: 684 if (!(max_v[0] & max_v[1]) == !match) 685 continue; 686 } 687 goto out; 688 } else if (is_bitop[1]) { 689 switch (left) { 690 case TOMOYO_PATH1_PERM: 691 case TOMOYO_PATH1_PARENT_PERM: 692 case TOMOYO_PATH2_PERM: 693 case TOMOYO_PATH2_PARENT_PERM: 694 if (!(max_v[0] & max_v[1]) == !match) 695 continue; 696 } 697 goto out; 698 } 699 /* Normal value range comparison. */ 700 if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match) 701 continue; 702out: 703 return false; 704 } 705 return true; 706} 707