Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

orangefs: clean up debugfs

We recently refactored the Orangefs debugfs code.
The refactor seemed to trigger dan.carpenter@oracle.com's
static tester to find a possible double-free in the code.

While designing the fix we saw a condition under which the
buffer being freed could also be overflowed.

We also realized how to rebuild the related debugfs file's
"contents" (a string) without deleting and re-creating the file.

This fix should eliminate the possible double-free, the
potential overflow and improve code readability.

Signed-off-by: Mike Marshall <hubcap@omnibond.com>
Signed-off-by: Martin Brandenburg <martin@omnibond.com>

+68 -85
+64 -83
fs/orangefs/orangefs-debugfs.c
··· 141 141 */ 142 142 static DEFINE_MUTEX(orangefs_debug_lock); 143 143 144 + /* Used to protect data in ORANGEFS_KMOD_DEBUG_HELP_FILE */ 145 + static DEFINE_MUTEX(orangefs_help_file_lock); 146 + 144 147 /* 145 148 * initialize kmod debug operations, create orangefs debugfs dir and 146 149 * ORANGEFS_KMOD_DEBUG_HELP_FILE. ··· 292 289 293 290 gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_start: start\n"); 294 291 292 + mutex_lock(&orangefs_help_file_lock); 293 + 295 294 if (*pos == 0) 296 295 payload = m->private; 297 296 ··· 310 305 static void help_stop(struct seq_file *m, void *p) 311 306 { 312 307 gossip_debug(GOSSIP_DEBUGFS_DEBUG, "help_stop: start\n"); 308 + mutex_unlock(&orangefs_help_file_lock); 313 309 } 314 310 315 311 static int help_show(struct seq_file *m, void *v) ··· 616 610 * /sys/kernel/debug/orangefs/debug-help can be catted to 617 611 * see all the available kernel and client debug keywords. 618 612 * 619 - * When the kernel boots, we have no idea what keywords the 613 + * When orangefs.ko initializes, we have no idea what keywords the 620 614 * client supports, nor their associated masks. 621 615 * 622 - * We pass through this function once at boot and stamp a 616 + * We pass through this function once at module-load and stamp a 623 617 * boilerplate "we don't know" message for the client in the 624 618 * debug-help file. We pass through here again when the client 625 619 * starts and then we can fill out the debug-help file fully. 626 620 * 627 621 * The client might be restarted any number of times between 628 - * reboots, we only build the debug-help file the first time. 622 + * module reloads, we only build the debug-help file the first time. 629 623 */ 630 624 int orangefs_prepare_debugfs_help_string(int at_boot) 631 625 { 632 - int rc = -EINVAL; 633 - int i; 634 - int byte_count = 0; 635 626 char *client_title = "Client Debug Keywords:\n"; 636 627 char *kernel_title = "Kernel Debug Keywords:\n"; 628 + size_t string_size = DEBUG_HELP_STRING_SIZE; 629 + size_t result_size; 630 + size_t i; 631 + char *new; 632 + int rc = -EINVAL; 637 633 638 634 gossip_debug(GOSSIP_UTILS_DEBUG, "%s: start\n", __func__); 639 635 640 - if (at_boot) { 641 - byte_count += strlen(HELP_STRING_UNINITIALIZED); 636 + if (at_boot) 642 637 client_title = HELP_STRING_UNINITIALIZED; 643 - } else { 644 - /* 638 + 639 + /* build a new debug_help_string. */ 640 + new = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL); 641 + if (!new) { 642 + rc = -ENOMEM; 643 + goto out; 644 + } 645 + 646 + /* 647 + * strlcat(dst, src, size) will append at most 648 + * "size - strlen(dst) - 1" bytes of src onto dst, 649 + * null terminating the result, and return the total 650 + * length of the string it tried to create. 651 + * 652 + * We'll just plow through here building our new debug 653 + * help string and let strlcat take care of assuring that 654 + * dst doesn't overflow. 655 + */ 656 + strlcat(new, client_title, string_size); 657 + 658 + if (!at_boot) { 659 + 660 + /* 645 661 * fill the client keyword/mask array and remember 646 662 * how many elements there were. 647 663 */ ··· 672 644 if (cdm_element_count <= 0) 673 645 goto out; 674 646 675 - /* Count the bytes destined for debug_help_string. */ 676 - byte_count += strlen(client_title); 677 - 678 647 for (i = 0; i < cdm_element_count; i++) { 679 - byte_count += strlen(cdm_array[i].keyword + 2); 680 - if (byte_count >= DEBUG_HELP_STRING_SIZE) { 681 - pr_info("%s: overflow 1!\n", __func__); 682 - goto out; 683 - } 648 + strlcat(new, "\t", string_size); 649 + strlcat(new, cdm_array[i].keyword, string_size); 650 + strlcat(new, "\n", string_size); 684 651 } 685 - 686 - gossip_debug(GOSSIP_UTILS_DEBUG, 687 - "%s: cdm_element_count:%d:\n", 688 - __func__, 689 - cdm_element_count); 690 652 } 691 653 692 - byte_count += strlen(kernel_title); 654 + strlcat(new, "\n", string_size); 655 + strlcat(new, kernel_title, string_size); 656 + 693 657 for (i = 0; i < num_kmod_keyword_mask_map; i++) { 694 - byte_count += 695 - strlen(s_kmod_keyword_mask_map[i].keyword + 2); 696 - if (byte_count >= DEBUG_HELP_STRING_SIZE) { 697 - pr_info("%s: overflow 2!\n", __func__); 698 - goto out; 699 - } 658 + strlcat(new, "\t", string_size); 659 + strlcat(new, s_kmod_keyword_mask_map[i].keyword, string_size); 660 + result_size = strlcat(new, "\n", string_size); 700 661 } 701 662 702 - /* build debug_help_string. */ 703 - debug_help_string = kzalloc(DEBUG_HELP_STRING_SIZE, GFP_KERNEL); 704 - if (!debug_help_string) { 705 - rc = -ENOMEM; 663 + /* See if we tried to put too many bytes into "new"... */ 664 + if (result_size >= string_size) { 665 + kfree(new); 706 666 goto out; 707 667 } 708 668 709 - strcat(debug_help_string, client_title); 710 - 711 - if (!at_boot) { 712 - for (i = 0; i < cdm_element_count; i++) { 713 - strcat(debug_help_string, "\t"); 714 - strcat(debug_help_string, cdm_array[i].keyword); 715 - strcat(debug_help_string, "\n"); 716 - } 717 - } 718 - 719 - strcat(debug_help_string, "\n"); 720 - strcat(debug_help_string, kernel_title); 721 - 722 - for (i = 0; i < num_kmod_keyword_mask_map; i++) { 723 - strcat(debug_help_string, "\t"); 724 - strcat(debug_help_string, s_kmod_keyword_mask_map[i].keyword); 725 - strcat(debug_help_string, "\n"); 669 + if (at_boot) { 670 + debug_help_string = new; 671 + } else { 672 + mutex_lock(&orangefs_help_file_lock); 673 + memset(debug_help_string, 0, DEBUG_HELP_STRING_SIZE); 674 + strlcat(debug_help_string, new, string_size); 675 + mutex_unlock(&orangefs_help_file_lock); 726 676 } 727 677 728 678 rc = 0; 729 679 730 - out: 731 - 732 - return rc; 680 + out: return rc; 733 681 734 682 } 735 683 ··· 963 959 ret = copy_from_user(&client_debug_array_string, 964 960 (void __user *)arg, 965 961 ORANGEFS_MAX_DEBUG_STRING_LEN); 966 - if (ret != 0) 962 + 963 + if (ret != 0) { 964 + pr_info("%s: CLIENT_STRING: copy_from_user failed\n", 965 + __func__); 967 966 return -EIO; 967 + } 968 968 969 969 /* 970 970 * The real client-core makes an effort to ensure ··· 983 975 client_debug_array_string[ORANGEFS_MAX_DEBUG_STRING_LEN - 1] = 984 976 '\0'; 985 977 986 - if (ret != 0) { 987 - pr_info("%s: CLIENT_STRING: copy_from_user failed\n", 988 - __func__); 989 - return -EIO; 990 - } 991 - 992 978 pr_info("%s: client debug array string has been received.\n", 993 979 __func__); 994 980 995 981 if (!help_string_initialized) { 996 982 997 - /* Free the "we don't know yet" default string... */ 998 - kfree(debug_help_string); 999 - 1000 - /* build a proper debug help string */ 983 + /* Build a proper debug help string. */ 1001 984 if (orangefs_prepare_debugfs_help_string(0)) { 1002 985 gossip_err("%s: no debug help string \n", 1003 986 __func__); 1004 987 return -EIO; 1005 988 } 1006 989 1007 - /* Replace the boilerplate boot-time debug-help file. */ 1008 - debugfs_remove(help_file_dentry); 1009 - 1010 - help_file_dentry = 1011 - debugfs_create_file( 1012 - ORANGEFS_KMOD_DEBUG_HELP_FILE, 1013 - 0444, 1014 - debug_dir, 1015 - debug_help_string, 1016 - &debug_help_fops); 1017 - 1018 - if (!help_file_dentry) { 1019 - gossip_err("%s: debugfs_create_file failed for" 1020 - " :%s:!\n", 1021 - __func__, 1022 - ORANGEFS_KMOD_DEBUG_HELP_FILE); 1023 - return -EIO; 1024 - } 1025 990 } 1026 991 1027 992 debug_mask_to_string(&client_debug_mask, 1);
+4 -2
fs/orangefs/orangefs-mod.c
··· 124 124 * unknown at boot time. 125 125 * 126 126 * orangefs_prepare_debugfs_help_string will be used again 127 - * later to rebuild the debug-help file after the client starts 127 + * later to rebuild the debug-help-string after the client starts 128 128 * and passes along the needed info. The argument signifies 129 129 * which time orangefs_prepare_debugfs_help_string is being 130 130 * called. ··· 152 152 153 153 ret = register_filesystem(&orangefs_fs_type); 154 154 if (ret == 0) { 155 - pr_info("orangefs: module version %s loaded\n", ORANGEFS_VERSION); 155 + pr_info("%s: module version %s loaded\n", 156 + __func__, 157 + ORANGEFS_VERSION); 156 158 ret = 0; 157 159 goto out; 158 160 }