Skip to content

Commit 8c73851

Browse files
committed
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>
1 parent 04d8712 commit 8c73851

1 file changed

Lines changed: 52 additions & 64 deletions

File tree

net/ceph/osdmap.c

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -806,138 +806,126 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
806806
ceph_decode_need(p, end, len, bad);
807807
pool_end = *p + len;
808808

809+
ceph_decode_need(p, end, 4 + 4 + 4, bad);
809810
pi->type = ceph_decode_8(p);
810811
pi->size = ceph_decode_8(p);
811812
pi->crush_ruleset = ceph_decode_8(p);
812813
pi->object_hash = ceph_decode_8(p);
813-
814814
pi->pg_num = ceph_decode_32(p);
815815
pi->pgp_num = ceph_decode_32(p);
816816

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);
820819

821820
/* skip snaps */
822-
num = ceph_decode_32(p);
821+
ceph_decode_32_safe(p, end, num, bad);
823822
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);
828826
}
829827

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);
833830

831+
ceph_decode_need(p, end, 8 + 8 + 4, bad);
834832
*p += 8; /* skip auid */
835833
pi->flags = ceph_decode_64(p);
836834
*p += 4; /* skip crash_replay_interval */
837835

838836
if (ev >= 7)
839-
pi->min_size = ceph_decode_8(p);
837+
ceph_decode_8_safe(p, end, pi->min_size, bad);
840838
else
841839
pi->min_size = pi->size - pi->size / 2;
842840

843841
if (ev >= 8)
844-
*p += 8 + 8; /* skip quota_max_* */
842+
/* quota_max_* */
843+
ceph_decode_skip_n(p, end, 8 + 8, bad);
845844

846845
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);
850848

849+
ceph_decode_need(p, end, 8 + 1 + 8 + 8, bad);
851850
*p += 8; /* skip tier_of */
852851
*p += 1; /* skip cache_mode */
853-
854852
pi->read_tier = ceph_decode_64(p);
855853
pi->write_tier = ceph_decode_64(p);
856854
} else {
857855
pi->read_tier = -1;
858856
pi->write_tier = -1;
859857
}
860858

861-
if (ev >= 10) {
862-
/* skip properties */
863-
num = ceph_decode_32(p);
864-
while (num--) {
865-
len = ceph_decode_32(p);
866-
*p += len; /* key */
867-
len = ceph_decode_32(p);
868-
*p += len; /* val */
869-
}
870-
}
859+
if (ev >= 10)
860+
/* properties */
861+
ceph_decode_skip_map(p, end, string, string, bad);
871862

872863
if (ev >= 11) {
873-
/* skip hit_set_params */
874-
*p += 1 + 1; /* versions */
875-
len = ceph_decode_32(p);
876-
*p += len;
864+
/* hit_set_params (with versions) */
865+
ceph_decode_skip_n(p, end, 2, bad);
866+
ceph_decode_skip_string(p, end, bad);
877867

878-
*p += 4; /* skip hit_set_period */
879-
*p += 4; /* skip hit_set_count */
868+
/* hit_set_period, hit_set_count */
869+
ceph_decode_skip_n(p, end, 4 + 4, bad);
880870
}
881871

882872
if (ev >= 12)
883-
*p += 4; /* skip stripe_width */
873+
/* stripe_width */
874+
ceph_decode_skip_32(p, end, bad);
884875

885-
if (ev >= 13) {
886-
*p += 8; /* skip target_max_bytes */
887-
*p += 8; /* skip target_max_objects */
888-
*p += 4; /* skip cache_target_dirty_ratio_micro */
889-
*p += 4; /* skip cache_target_full_ratio_micro */
890-
*p += 4; /* skip cache_min_flush_age */
891-
*p += 4; /* skip cache_min_evict_age */
892-
}
876+
if (ev >= 13)
877+
/* target_max_*, cache_target_*, cache_min_* */
878+
ceph_decode_skip_n(p, end, 16 + 8 + 8, bad);
893879

894-
if (ev >= 14) {
895-
/* skip erasure_code_profile */
896-
len = ceph_decode_32(p);
897-
*p += len;
898-
}
880+
if (ev >= 14)
881+
/* erasure_code_profile */
882+
ceph_decode_skip_string(p, end, bad);
899883

900884
/*
901885
* last_force_op_resend_preluminous, will be overridden if the
902886
* map was encoded with RESEND_ON_SPLIT
903887
*/
904888
if (ev >= 15)
905-
pi->last_force_request_resend = ceph_decode_32(p);
889+
ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad);
906890
else
907891
pi->last_force_request_resend = 0;
908892

909893
if (ev >= 16)
910-
*p += 4; /* skip min_read_recency_for_promote */
894+
/* min_read_recency_for_promote */
895+
ceph_decode_skip_32(p, end, bad);
911896

912897
if (ev >= 17)
913-
*p += 8; /* skip expected_num_objects */
898+
/* expected_num_objects */
899+
ceph_decode_skip_64(p, end, bad);
914900

915901
if (ev >= 19)
916-
*p += 4; /* skip cache_target_dirty_high_ratio_micro */
902+
/* cache_target_dirty_high_ratio_micro */
903+
ceph_decode_skip_32(p, end, bad);
917904

918905
if (ev >= 20)
919-
*p += 4; /* skip min_write_recency_for_promote */
906+
/* min_write_recency_for_promote */
907+
ceph_decode_skip_32(p, end, bad);
920908

921909
if (ev >= 21)
922-
*p += 1; /* skip use_gmt_hitset */
910+
/* use_gmt_hitset */
911+
ceph_decode_skip_8(p, end, bad);
923912

924913
if (ev >= 22)
925-
*p += 1; /* skip fast_read */
914+
/* fast_read */
915+
ceph_decode_skip_8(p, end, bad);
926916

927-
if (ev >= 23) {
928-
*p += 4; /* skip hit_set_grade_decay_rate */
929-
*p += 4; /* skip hit_set_search_last_n */
930-
}
917+
if (ev >= 23)
918+
/* hit_set_grade_decay_rate, hit_set_search_last_n */
919+
ceph_decode_skip_n(p, end, 4 + 4, bad);
931920

932921
if (ev >= 24) {
933-
/* skip opts */
934-
*p += 1 + 1; /* versions */
935-
len = ceph_decode_32(p);
936-
*p += len;
922+
/* opts (with versions) */
923+
ceph_decode_skip_n(p, end, 2, bad);
924+
ceph_decode_skip_string(p, end, bad);
937925
}
938926

939927
if (ev >= 25)
940-
pi->last_force_request_resend = ceph_decode_32(p);
928+
ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad);
941929

942930
/* ignore the rest */
943931

0 commit comments

Comments
 (0)