comparison tests/test-parseindex.t @ 25810:82d6a35cf432

parsers: fix buffer overflow by invalid parent revision read from revlog If revlog file is corrupted, it can have parent pointing to invalid revision. So we should validate it before updating nothead[], phases[], seen[], etc. Otherwise it would cause segfault at best. We could use "rev" instead of "maxrev" as upper bound, but I think the explicit "maxrev" can clarify that we just want to avoid possible buffer overflow vulnerability.
author Yuya Nishihara <yuya@tcha.org>
date Thu, 16 Jul 2015 23:36:08 +0900
parents f2719b387380
children 1619563959b3
comparison
equal deleted inserted replaced
25809:ebb5bb9bc32e 25810:82d6a35cf432
57 2 revisions: 57 2 revisions:
58 7c31755bf9b5 58 7c31755bf9b5
59 26333235a41c 59 26333235a41c
60 60
61 $ cd .. 61 $ cd ..
62
63 Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
64
65 $ mkdir invalidparent
66 $ cd invalidparent
67
68 $ hg clone --pull -q --config phases.publish=False ../a limit
69 $ hg clone --pull -q --config phases.publish=False ../a segv
70 $ rm -R limit/.hg/cache segv/.hg/cache
71
72 $ python <<EOF
73 > data = open("limit/.hg/store/00changelog.i", "rb").read()
74 > for n, p in [('limit', '\0\0\0\x02'), ('segv', '\0\x01\0\0')]:
75 > # corrupt p1 at rev0 and p2 at rev1
76 > d = data[:24] + p + data[28:127 + 28] + p + data[127 + 32:]
77 > open(n + "/.hg/store/00changelog.i", "wb").write(d)
78 > EOF
79
80 $ hg debugindex -f1 limit/.hg/store/00changelog.i
81 rev flag offset length size base link p1 p2 nodeid
82 0 0000 0 63 62 0 0 2 -1 7c31755bf9b5
83 1 0000 63 66 65 1 1 0 2 26333235a41c
84 $ hg debugindex -f1 segv/.hg/store/00changelog.i
85 rev flag offset length size base link p1 p2 nodeid
86 0 0000 0 63 62 0 0 65536 -1 7c31755bf9b5
87 1 0000 63 66 65 1 1 0 65536 26333235a41c
88
89 $ cat <<EOF > test.py
90 > import sys
91 > from mercurial import changelog, scmutil
92 > cl = changelog.changelog(scmutil.vfs(sys.argv[1]))
93 > n0, n1 = cl.node(0), cl.node(1)
94 > ops = [
95 > ('compute_phases_map_sets', lambda: cl.computephases([[0], []])),
96 > ('index_headrevs', lambda: cl.headrevs()),
97 > ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
98 > ('find_deepest', lambda: cl.ancestor(n0, n1)),
99 > ]
100 > for l, f in ops:
101 > print l + ':',
102 > try:
103 > f()
104 > print 'uncaught buffer overflow?'
105 > except ValueError, inst:
106 > print inst
107 > EOF
108
109 $ python test.py limit/.hg/store
110 compute_phases_map_sets: parent out of range
111 index_headrevs: parent out of range
112 find_gca_candidates: parent out of range
113 find_deepest: parent out of range
114 $ python test.py segv/.hg/store
115 compute_phases_map_sets: parent out of range
116 index_headrevs: parent out of range
117 find_gca_candidates: parent out of range
118 find_deepest: parent out of range
119
120 $ cd ..