diff options
author | Vasily Averin <vvs@sw.ru> | 2007-07-17 07:04:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-17 13:23:06 -0400 |
commit | 1725d71d992f5947bdd5b4f9a30fe8a05571fe66 (patch) | |
tree | 3f75479254b5ce59fd9e47a4603c2e01e1c946e3 | |
parent | 2bf68a3699601bd3e53b4efce7f2d780e243aa35 (diff) |
i2o_cfg_passthru cleanup
This patch fixes a number of issues in i2o_cfg_passthru{,32}:
- i2o_msg_get_wait() return vaile is not checked;
- i2o_message memory leaks on error paths;
- infinite loop to sg_list_cleanup in passthru32
It's important issue because of i2o_cfg_passthru is used by raidutils for
monitorig controllers state, and in case of memory shortage it leads to the
node crash or disk IO stall.
[akpm@linux-foundation.org: fix null-ptr deref]
Signed-off-by: Vasily Averin <vvs@sw.ru>
Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Markus Lidel <Markus.Lidel@shadowconnect.com>
Acked-by: Kirill Korotaev <dev@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/message/i2o/i2o_config.c | 62 |
1 files changed, 38 insertions, 24 deletions
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c index 8ba275a12773..84e046e94f5f 100644 --- a/drivers/message/i2o/i2o_config.c +++ b/drivers/message/i2o/i2o_config.c | |||
@@ -554,8 +554,6 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
554 | return -ENXIO; | 554 | return -ENXIO; |
555 | } | 555 | } |
556 | 556 | ||
557 | msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); | ||
558 | |||
559 | sb = c->status_block.virt; | 557 | sb = c->status_block.virt; |
560 | 558 | ||
561 | if (get_user(size, &user_msg[0])) { | 559 | if (get_user(size, &user_msg[0])) { |
@@ -573,24 +571,30 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
573 | 571 | ||
574 | size <<= 2; // Convert to bytes | 572 | size <<= 2; // Convert to bytes |
575 | 573 | ||
574 | msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); | ||
575 | if (IS_ERR(msg)) | ||
576 | return PTR_ERR(msg); | ||
577 | |||
578 | rcode = -EFAULT; | ||
576 | /* Copy in the user's I2O command */ | 579 | /* Copy in the user's I2O command */ |
577 | if (copy_from_user(msg, user_msg, size)) { | 580 | if (copy_from_user(msg, user_msg, size)) { |
578 | osm_warn("unable to copy user message\n"); | 581 | osm_warn("unable to copy user message\n"); |
579 | return -EFAULT; | 582 | goto out; |
580 | } | 583 | } |
581 | i2o_dump_message(msg); | 584 | i2o_dump_message(msg); |
582 | 585 | ||
583 | if (get_user(reply_size, &user_reply[0]) < 0) | 586 | if (get_user(reply_size, &user_reply[0]) < 0) |
584 | return -EFAULT; | 587 | goto out; |
585 | 588 | ||
586 | reply_size >>= 16; | 589 | reply_size >>= 16; |
587 | reply_size <<= 2; | 590 | reply_size <<= 2; |
588 | 591 | ||
592 | rcode = -ENOMEM; | ||
589 | reply = kzalloc(reply_size, GFP_KERNEL); | 593 | reply = kzalloc(reply_size, GFP_KERNEL); |
590 | if (!reply) { | 594 | if (!reply) { |
591 | printk(KERN_WARNING "%s: Could not allocate reply buffer\n", | 595 | printk(KERN_WARNING "%s: Could not allocate reply buffer\n", |
592 | c->name); | 596 | c->name); |
593 | return -ENOMEM; | 597 | goto out; |
594 | } | 598 | } |
595 | 599 | ||
596 | sg_offset = (msg->u.head[0] >> 4) & 0x0f; | 600 | sg_offset = (msg->u.head[0] >> 4) & 0x0f; |
@@ -661,13 +665,14 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
661 | } | 665 | } |
662 | 666 | ||
663 | rcode = i2o_msg_post_wait(c, msg, 60); | 667 | rcode = i2o_msg_post_wait(c, msg, 60); |
668 | msg = NULL; | ||
664 | if (rcode) { | 669 | if (rcode) { |
665 | reply[4] = ((u32) rcode) << 24; | 670 | reply[4] = ((u32) rcode) << 24; |
666 | goto sg_list_cleanup; | 671 | goto sg_list_cleanup; |
667 | } | 672 | } |
668 | 673 | ||
669 | if (sg_offset) { | 674 | if (sg_offset) { |
670 | u32 msg[I2O_OUTBOUND_MSG_FRAME_SIZE]; | 675 | u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE]; |
671 | /* Copy back the Scatter Gather buffers back to user space */ | 676 | /* Copy back the Scatter Gather buffers back to user space */ |
672 | u32 j; | 677 | u32 j; |
673 | // TODO 64bit fix | 678 | // TODO 64bit fix |
@@ -675,7 +680,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
675 | int sg_size; | 680 | int sg_size; |
676 | 681 | ||
677 | // re-acquire the original message to handle correctly the sg copy operation | 682 | // re-acquire the original message to handle correctly the sg copy operation |
678 | memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4); | 683 | memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4); |
679 | // get user msg size in u32s | 684 | // get user msg size in u32s |
680 | if (get_user(size, &user_msg[0])) { | 685 | if (get_user(size, &user_msg[0])) { |
681 | rcode = -EFAULT; | 686 | rcode = -EFAULT; |
@@ -684,7 +689,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
684 | size = size >> 16; | 689 | size = size >> 16; |
685 | size *= 4; | 690 | size *= 4; |
686 | /* Copy in the user's I2O command */ | 691 | /* Copy in the user's I2O command */ |
687 | if (copy_from_user(msg, user_msg, size)) { | 692 | if (copy_from_user(rmsg, user_msg, size)) { |
688 | rcode = -EFAULT; | 693 | rcode = -EFAULT; |
689 | goto sg_list_cleanup; | 694 | goto sg_list_cleanup; |
690 | } | 695 | } |
@@ -692,7 +697,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
692 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); | 697 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); |
693 | 698 | ||
694 | // TODO 64bit fix | 699 | // TODO 64bit fix |
695 | sg = (struct sg_simple_element *)(msg + sg_offset); | 700 | sg = (struct sg_simple_element *)(rmsg + sg_offset); |
696 | for (j = 0; j < sg_count; j++) { | 701 | for (j = 0; j < sg_count; j++) { |
697 | /* Copy out the SG list to user's buffer if necessary */ | 702 | /* Copy out the SG list to user's buffer if necessary */ |
698 | if (! | 703 | if (! |
@@ -714,7 +719,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
714 | } | 719 | } |
715 | } | 720 | } |
716 | 721 | ||
717 | sg_list_cleanup: | 722 | sg_list_cleanup: |
718 | /* Copy back the reply to user space */ | 723 | /* Copy back the reply to user space */ |
719 | if (reply_size) { | 724 | if (reply_size) { |
720 | // we wrote our own values for context - now restore the user supplied ones | 725 | // we wrote our own values for context - now restore the user supplied ones |
@@ -723,7 +728,6 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
723 | "%s: Could not copy message context FROM user\n", | 728 | "%s: Could not copy message context FROM user\n", |
724 | c->name); | 729 | c->name); |
725 | rcode = -EFAULT; | 730 | rcode = -EFAULT; |
726 | goto sg_list_cleanup; | ||
727 | } | 731 | } |
728 | if (copy_to_user(user_reply, reply, reply_size)) { | 732 | if (copy_to_user(user_reply, reply, reply_size)) { |
729 | printk(KERN_WARNING | 733 | printk(KERN_WARNING |
@@ -731,12 +735,14 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, | |||
731 | rcode = -EFAULT; | 735 | rcode = -EFAULT; |
732 | } | 736 | } |
733 | } | 737 | } |
734 | |||
735 | for (i = 0; i < sg_index; i++) | 738 | for (i = 0; i < sg_index; i++) |
736 | i2o_dma_free(&c->pdev->dev, &sg_list[i]); | 739 | i2o_dma_free(&c->pdev->dev, &sg_list[i]); |
737 | 740 | ||
738 | cleanup: | 741 | cleanup: |
739 | kfree(reply); | 742 | kfree(reply); |
743 | out: | ||
744 | if (msg) | ||
745 | i2o_msg_nop(c, msg); | ||
740 | return rcode; | 746 | return rcode; |
741 | } | 747 | } |
742 | 748 | ||
@@ -793,8 +799,6 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
793 | return -ENXIO; | 799 | return -ENXIO; |
794 | } | 800 | } |
795 | 801 | ||
796 | msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); | ||
797 | |||
798 | sb = c->status_block.virt; | 802 | sb = c->status_block.virt; |
799 | 803 | ||
800 | if (get_user(size, &user_msg[0])) | 804 | if (get_user(size, &user_msg[0])) |
@@ -810,12 +814,17 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
810 | 814 | ||
811 | size <<= 2; // Convert to bytes | 815 | size <<= 2; // Convert to bytes |
812 | 816 | ||
817 | msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); | ||
818 | if (IS_ERR(msg)) | ||
819 | return PTR_ERR(msg); | ||
820 | |||
821 | rcode = -EFAULT; | ||
813 | /* Copy in the user's I2O command */ | 822 | /* Copy in the user's I2O command */ |
814 | if (copy_from_user(msg, user_msg, size)) | 823 | if (copy_from_user(msg, user_msg, size)) |
815 | return -EFAULT; | 824 | goto out; |
816 | 825 | ||
817 | if (get_user(reply_size, &user_reply[0]) < 0) | 826 | if (get_user(reply_size, &user_reply[0]) < 0) |
818 | return -EFAULT; | 827 | goto out; |
819 | 828 | ||
820 | reply_size >>= 16; | 829 | reply_size >>= 16; |
821 | reply_size <<= 2; | 830 | reply_size <<= 2; |
@@ -824,7 +833,8 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
824 | if (!reply) { | 833 | if (!reply) { |
825 | printk(KERN_WARNING "%s: Could not allocate reply buffer\n", | 834 | printk(KERN_WARNING "%s: Could not allocate reply buffer\n", |
826 | c->name); | 835 | c->name); |
827 | return -ENOMEM; | 836 | rcode = -ENOMEM; |
837 | goto out; | ||
828 | } | 838 | } |
829 | 839 | ||
830 | sg_offset = (msg->u.head[0] >> 4) & 0x0f; | 840 | sg_offset = (msg->u.head[0] >> 4) & 0x0f; |
@@ -891,13 +901,14 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
891 | } | 901 | } |
892 | 902 | ||
893 | rcode = i2o_msg_post_wait(c, msg, 60); | 903 | rcode = i2o_msg_post_wait(c, msg, 60); |
904 | msg = NULL; | ||
894 | if (rcode) { | 905 | if (rcode) { |
895 | reply[4] = ((u32) rcode) << 24; | 906 | reply[4] = ((u32) rcode) << 24; |
896 | goto sg_list_cleanup; | 907 | goto sg_list_cleanup; |
897 | } | 908 | } |
898 | 909 | ||
899 | if (sg_offset) { | 910 | if (sg_offset) { |
900 | u32 msg[128]; | 911 | u32 rmsg[128]; |
901 | /* Copy back the Scatter Gather buffers back to user space */ | 912 | /* Copy back the Scatter Gather buffers back to user space */ |
902 | u32 j; | 913 | u32 j; |
903 | // TODO 64bit fix | 914 | // TODO 64bit fix |
@@ -905,7 +916,7 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
905 | int sg_size; | 916 | int sg_size; |
906 | 917 | ||
907 | // re-acquire the original message to handle correctly the sg copy operation | 918 | // re-acquire the original message to handle correctly the sg copy operation |
908 | memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4); | 919 | memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4); |
909 | // get user msg size in u32s | 920 | // get user msg size in u32s |
910 | if (get_user(size, &user_msg[0])) { | 921 | if (get_user(size, &user_msg[0])) { |
911 | rcode = -EFAULT; | 922 | rcode = -EFAULT; |
@@ -914,7 +925,7 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
914 | size = size >> 16; | 925 | size = size >> 16; |
915 | size *= 4; | 926 | size *= 4; |
916 | /* Copy in the user's I2O command */ | 927 | /* Copy in the user's I2O command */ |
917 | if (copy_from_user(msg, user_msg, size)) { | 928 | if (copy_from_user(rmsg, user_msg, size)) { |
918 | rcode = -EFAULT; | 929 | rcode = -EFAULT; |
919 | goto sg_list_cleanup; | 930 | goto sg_list_cleanup; |
920 | } | 931 | } |
@@ -922,7 +933,7 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
922 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); | 933 | (size - sg_offset * 4) / sizeof(struct sg_simple_element); |
923 | 934 | ||
924 | // TODO 64bit fix | 935 | // TODO 64bit fix |
925 | sg = (struct sg_simple_element *)(msg + sg_offset); | 936 | sg = (struct sg_simple_element *)(rmsg + sg_offset); |
926 | for (j = 0; j < sg_count; j++) { | 937 | for (j = 0; j < sg_count; j++) { |
927 | /* Copy out the SG list to user's buffer if necessary */ | 938 | /* Copy out the SG list to user's buffer if necessary */ |
928 | if (! | 939 | if (! |
@@ -944,7 +955,7 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
944 | } | 955 | } |
945 | } | 956 | } |
946 | 957 | ||
947 | sg_list_cleanup: | 958 | sg_list_cleanup: |
948 | /* Copy back the reply to user space */ | 959 | /* Copy back the reply to user space */ |
949 | if (reply_size) { | 960 | if (reply_size) { |
950 | // we wrote our own values for context - now restore the user supplied ones | 961 | // we wrote our own values for context - now restore the user supplied ones |
@@ -964,8 +975,11 @@ static int i2o_cfg_passthru(unsigned long arg) | |||
964 | for (i = 0; i < sg_index; i++) | 975 | for (i = 0; i < sg_index; i++) |
965 | kfree(sg_list[i]); | 976 | kfree(sg_list[i]); |
966 | 977 | ||
967 | cleanup: | 978 | cleanup: |
968 | kfree(reply); | 979 | kfree(reply); |
980 | out: | ||
981 | if (msg) | ||
982 | i2o_msg_nop(c, msg); | ||
969 | return rcode; | 983 | return rcode; |
970 | } | 984 | } |
971 | #endif | 985 | #endif |