libceph: make decode_pool() more resilient against corrupted osdmaps

If the osdmap is (maliciously) corrupted such that the encoded length
of ceph_pg_pool envelope is less than what is expected for a particular
encoding version, out-of-bounds reads may ensue because the only bounds
check that is there is based on that length value.

This patch adds explicit bounds checks for each field that is decoded
or skipped.

Cc: stable@vger.kernel.org
Reported-by: ziming zhang <ezrakiez@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Tested-by: ziming zhang <ezrakiez@gmail.com>

Changed files
+52 -64
net
ceph
+52 -64
net/ceph/osdmap.c
··· 806 806 ceph_decode_need(p, end, len, bad); 807 807 pool_end = *p + len; 808 808 809 + ceph_decode_need(p, end, 4 + 4 + 4, bad); 809 810 pi->type = ceph_decode_8(p); 810 811 pi->size = ceph_decode_8(p); 811 812 pi->crush_ruleset = ceph_decode_8(p); 812 813 pi->object_hash = ceph_decode_8(p); 813 - 814 814 pi->pg_num = ceph_decode_32(p); 815 815 pi->pgp_num = ceph_decode_32(p); 816 816 817 - *p += 4 + 4; /* skip lpg* */ 818 - *p += 4; /* skip last_change */ 819 - *p += 8 + 4; /* skip snap_seq, snap_epoch */ 817 + /* lpg*, last_change, snap_seq, snap_epoch */ 818 + ceph_decode_skip_n(p, end, 8 + 4 + 8 + 4, bad); 820 819 821 820 /* skip snaps */ 822 - num = ceph_decode_32(p); 821 + ceph_decode_32_safe(p, end, num, bad); 823 822 while (num--) { 824 - *p += 8; /* snapid key */ 825 - *p += 1 + 1; /* versions */ 826 - len = ceph_decode_32(p); 827 - *p += len; 823 + /* snapid key, pool snap (with versions) */ 824 + ceph_decode_skip_n(p, end, 8 + 2, bad); 825 + ceph_decode_skip_string(p, end, bad); 828 826 } 829 827 830 - /* skip removed_snaps */ 831 - num = ceph_decode_32(p); 832 - *p += num * (8 + 8); 828 + /* removed_snaps */ 829 + ceph_decode_skip_map(p, end, 64, 64, bad); 833 830 831 + ceph_decode_need(p, end, 8 + 8 + 4, bad); 834 832 *p += 8; /* skip auid */ 835 833 pi->flags = ceph_decode_64(p); 836 834 *p += 4; /* skip crash_replay_interval */ 837 835 838 836 if (ev >= 7) 839 - pi->min_size = ceph_decode_8(p); 837 + ceph_decode_8_safe(p, end, pi->min_size, bad); 840 838 else 841 839 pi->min_size = pi->size - pi->size / 2; 842 840 843 841 if (ev >= 8) 844 - *p += 8 + 8; /* skip quota_max_* */ 842 + /* quota_max_* */ 843 + ceph_decode_skip_n(p, end, 8 + 8, bad); 845 844 846 845 if (ev >= 9) { 847 - /* skip tiers */ 848 - num = ceph_decode_32(p); 849 - *p += num * 8; 846 + /* tiers */ 847 + ceph_decode_skip_set(p, end, 64, bad); 850 848 849 + ceph_decode_need(p, end, 8 + 1 + 8 + 8, bad); 851 850 *p += 8; /* skip tier_of */ 852 851 *p += 1; /* skip cache_mode */ 853 - 854 852 pi->read_tier = ceph_decode_64(p); 855 853 pi->write_tier = ceph_decode_64(p); 856 854 } else { ··· 856 858 pi->write_tier = -1; 857 859 } 858 860 859 - if (ev >= 10) { 860 - /* skip properties */ 861 - num = ceph_decode_32(p); 862 - while (num--) { 863 - len = ceph_decode_32(p); 864 - *p += len; /* key */ 865 - len = ceph_decode_32(p); 866 - *p += len; /* val */ 867 - } 868 - } 861 + if (ev >= 10) 862 + /* properties */ 863 + ceph_decode_skip_map(p, end, string, string, bad); 869 864 870 865 if (ev >= 11) { 871 - /* skip hit_set_params */ 872 - *p += 1 + 1; /* versions */ 873 - len = ceph_decode_32(p); 874 - *p += len; 866 + /* hit_set_params (with versions) */ 867 + ceph_decode_skip_n(p, end, 2, bad); 868 + ceph_decode_skip_string(p, end, bad); 875 869 876 - *p += 4; /* skip hit_set_period */ 877 - *p += 4; /* skip hit_set_count */ 870 + /* hit_set_period, hit_set_count */ 871 + ceph_decode_skip_n(p, end, 4 + 4, bad); 878 872 } 879 873 880 874 if (ev >= 12) 881 - *p += 4; /* skip stripe_width */ 875 + /* stripe_width */ 876 + ceph_decode_skip_32(p, end, bad); 882 877 883 - if (ev >= 13) { 884 - *p += 8; /* skip target_max_bytes */ 885 - *p += 8; /* skip target_max_objects */ 886 - *p += 4; /* skip cache_target_dirty_ratio_micro */ 887 - *p += 4; /* skip cache_target_full_ratio_micro */ 888 - *p += 4; /* skip cache_min_flush_age */ 889 - *p += 4; /* skip cache_min_evict_age */ 890 - } 878 + if (ev >= 13) 879 + /* target_max_*, cache_target_*, cache_min_* */ 880 + ceph_decode_skip_n(p, end, 16 + 8 + 8, bad); 891 881 892 - if (ev >= 14) { 893 - /* skip erasure_code_profile */ 894 - len = ceph_decode_32(p); 895 - *p += len; 896 - } 882 + if (ev >= 14) 883 + /* erasure_code_profile */ 884 + ceph_decode_skip_string(p, end, bad); 897 885 898 886 /* 899 887 * last_force_op_resend_preluminous, will be overridden if the 900 888 * map was encoded with RESEND_ON_SPLIT 901 889 */ 902 890 if (ev >= 15) 903 - pi->last_force_request_resend = ceph_decode_32(p); 891 + ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad); 904 892 else 905 893 pi->last_force_request_resend = 0; 906 894 907 895 if (ev >= 16) 908 - *p += 4; /* skip min_read_recency_for_promote */ 896 + /* min_read_recency_for_promote */ 897 + ceph_decode_skip_32(p, end, bad); 909 898 910 899 if (ev >= 17) 911 - *p += 8; /* skip expected_num_objects */ 900 + /* expected_num_objects */ 901 + ceph_decode_skip_64(p, end, bad); 912 902 913 903 if (ev >= 19) 914 - *p += 4; /* skip cache_target_dirty_high_ratio_micro */ 904 + /* cache_target_dirty_high_ratio_micro */ 905 + ceph_decode_skip_32(p, end, bad); 915 906 916 907 if (ev >= 20) 917 - *p += 4; /* skip min_write_recency_for_promote */ 908 + /* min_write_recency_for_promote */ 909 + ceph_decode_skip_32(p, end, bad); 918 910 919 911 if (ev >= 21) 920 - *p += 1; /* skip use_gmt_hitset */ 912 + /* use_gmt_hitset */ 913 + ceph_decode_skip_8(p, end, bad); 921 914 922 915 if (ev >= 22) 923 - *p += 1; /* skip fast_read */ 916 + /* fast_read */ 917 + ceph_decode_skip_8(p, end, bad); 924 918 925 - if (ev >= 23) { 926 - *p += 4; /* skip hit_set_grade_decay_rate */ 927 - *p += 4; /* skip hit_set_search_last_n */ 928 - } 919 + if (ev >= 23) 920 + /* hit_set_grade_decay_rate, hit_set_search_last_n */ 921 + ceph_decode_skip_n(p, end, 4 + 4, bad); 929 922 930 923 if (ev >= 24) { 931 - /* skip opts */ 932 - *p += 1 + 1; /* versions */ 933 - len = ceph_decode_32(p); 934 - *p += len; 924 + /* opts (with versions) */ 925 + ceph_decode_skip_n(p, end, 2, bad); 926 + ceph_decode_skip_string(p, end, bad); 935 927 } 936 928 937 929 if (ev >= 25) 938 - pi->last_force_request_resend = ceph_decode_32(p); 930 + ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad); 939 931 940 932 /* ignore the rest */ 941 933