Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 595dfe6

Browse files
authored
Merge pull request #492 from ajnavarro/fix/panic-in-invalid-delta
packfile: Avoid panics patching corrupted deltas.
2 parents f0fb843 + 4f713d1 commit 595dfe6

File tree

2 files changed

+85
-16
lines changed

2 files changed

+85
-16
lines changed

plumbing/format/packfile/delta_test.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package packfile
22

33
import (
4-
"fmt"
54
"math/rand"
65

76
. "gopkg.in/check.v1"
@@ -86,9 +85,28 @@ func (s *DeltaSuite) TestAddDelta(c *C) {
8685
baseBuf := genBytes(t.base)
8786
targetBuf := genBytes(t.target)
8887
delta := DiffDelta(baseBuf, targetBuf)
89-
result := PatchDelta(baseBuf, delta)
88+
result, err := PatchDelta(baseBuf, delta)
9089

91-
c.Log(fmt.Printf("Executing test case: %s\n", t.description))
90+
c.Log("Executing test case:", t.description)
91+
c.Assert(err, IsNil)
9292
c.Assert(result, DeepEquals, targetBuf)
9393
}
9494
}
95+
96+
func (s *DeltaSuite) TestIncompleteDelta(c *C) {
97+
for _, t := range s.testCases {
98+
c.Log("Incomplete delta on:", t.description)
99+
baseBuf := genBytes(t.base)
100+
targetBuf := genBytes(t.target)
101+
delta := DiffDelta(baseBuf, targetBuf)
102+
delta = delta[:len(delta)-2]
103+
result, err := PatchDelta(baseBuf, delta)
104+
c.Assert(err, NotNil)
105+
c.Assert(result, IsNil)
106+
}
107+
108+
// check nil input too
109+
result, err := PatchDelta(nil, nil)
110+
c.Assert(err, NotNil)
111+
c.Assert(result, IsNil)
112+
}

plumbing/format/packfile/patch_delta.go

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package packfile
22

33
import (
4+
"errors"
45
"io/ioutil"
56

67
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -30,7 +31,11 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error {
3031
return err
3132
}
3233

33-
dst := PatchDelta(src, delta)
34+
dst, err := PatchDelta(src, delta)
35+
if err != nil {
36+
return err
37+
}
38+
3439
target.SetSize(int64(len(dst)))
3540

3641
if _, err := w.Write(dst); err != nil {
@@ -40,15 +45,22 @@ func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) error {
4045
return nil
4146
}
4247

48+
var (
49+
ErrInvalidDelta = errors.New("invalid delta")
50+
ErrDeltaCmd = errors.New("wrong delta command")
51+
)
52+
4353
// PatchDelta returns the result of applying the modification deltas in delta to src.
44-
func PatchDelta(src, delta []byte) []byte {
54+
// An error will be returned if delta is corrupted (ErrDeltaLen) or an action command
55+
// is not copy from source or copy from delta (ErrDeltaCmd).
56+
func PatchDelta(src, delta []byte) ([]byte, error) {
4557
if len(delta) < deltaSizeMin {
46-
return nil
58+
return nil, ErrInvalidDelta
4759
}
4860

4961
srcSz, delta := decodeLEB128(delta)
5062
if srcSz != uint(len(src)) {
51-
return nil
63+
return nil, ErrInvalidDelta
5264
}
5365

5466
targetSz, delta := decodeLEB128(delta)
@@ -57,12 +69,25 @@ func PatchDelta(src, delta []byte) []byte {
5769
var dest []byte
5870
var cmd byte
5971
for {
72+
if len(delta) == 0 {
73+
return nil, ErrInvalidDelta
74+
}
75+
6076
cmd = delta[0]
6177
delta = delta[1:]
6278
if isCopyFromSrc(cmd) {
6379
var offset, sz uint
64-
offset, delta = decodeOffset(cmd, delta)
65-
sz, delta = decodeSize(cmd, delta)
80+
var err error
81+
offset, delta, err = decodeOffset(cmd, delta)
82+
if err != nil {
83+
return nil, err
84+
}
85+
86+
sz, delta, err = decodeSize(cmd, delta)
87+
if err != nil {
88+
return nil, err
89+
}
90+
6691
if invalidSize(sz, targetSz) ||
6792
invalidOffsetSize(offset, sz, srcSz) {
6893
break
@@ -72,21 +97,26 @@ func PatchDelta(src, delta []byte) []byte {
7297
} else if isCopyFromDelta(cmd) {
7398
sz := uint(cmd) // cmd is the size itself
7499
if invalidSize(sz, targetSz) {
75-
break
100+
return nil, ErrInvalidDelta
101+
}
102+
103+
if uint(len(delta)) < sz {
104+
return nil, ErrInvalidDelta
76105
}
106+
77107
dest = append(dest, delta[0:sz]...)
78108
remainingTargetSz -= sz
79109
delta = delta[sz:]
80110
} else {
81-
return nil
111+
return nil, ErrDeltaCmd
82112
}
83113

84114
if remainingTargetSz <= 0 {
85115
break
86116
}
87117
}
88118

89-
return dest
119+
return dest, nil
90120
}
91121

92122
// Decodes a number encoded as an unsigned LEB128 at the start of some
@@ -124,47 +154,68 @@ func isCopyFromDelta(cmd byte) bool {
124154
return (cmd&0x80) == 0 && cmd != 0
125155
}
126156

127-
func decodeOffset(cmd byte, delta []byte) (uint, []byte) {
157+
func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) {
128158
var offset uint
129159
if (cmd & 0x01) != 0 {
160+
if len(delta) == 0 {
161+
return 0, nil, ErrInvalidDelta
162+
}
130163
offset = uint(delta[0])
131164
delta = delta[1:]
132165
}
133166
if (cmd & 0x02) != 0 {
167+
if len(delta) == 0 {
168+
return 0, nil, ErrInvalidDelta
169+
}
134170
offset |= uint(delta[0]) << 8
135171
delta = delta[1:]
136172
}
137173
if (cmd & 0x04) != 0 {
174+
if len(delta) == 0 {
175+
return 0, nil, ErrInvalidDelta
176+
}
138177
offset |= uint(delta[0]) << 16
139178
delta = delta[1:]
140179
}
141180
if (cmd & 0x08) != 0 {
181+
if len(delta) == 0 {
182+
return 0, nil, ErrInvalidDelta
183+
}
142184
offset |= uint(delta[0]) << 24
143185
delta = delta[1:]
144186
}
145187

146-
return offset, delta
188+
return offset, delta, nil
147189
}
148190

149-
func decodeSize(cmd byte, delta []byte) (uint, []byte) {
191+
func decodeSize(cmd byte, delta []byte) (uint, []byte, error) {
150192
var sz uint
151193
if (cmd & 0x10) != 0 {
194+
if len(delta) == 0 {
195+
return 0, nil, ErrInvalidDelta
196+
}
152197
sz = uint(delta[0])
153198
delta = delta[1:]
154199
}
155200
if (cmd & 0x20) != 0 {
201+
if len(delta) == 0 {
202+
return 0, nil, ErrInvalidDelta
203+
}
156204
sz |= uint(delta[0]) << 8
157205
delta = delta[1:]
158206
}
159207
if (cmd & 0x40) != 0 {
208+
if len(delta) == 0 {
209+
return 0, nil, ErrInvalidDelta
210+
}
160211
sz |= uint(delta[0]) << 16
161212
delta = delta[1:]
162213
}
163214
if sz == 0 {
164215
sz = 0x10000
165216
}
166217

167-
return sz, delta
218+
return sz, delta, nil
168219
}
169220

170221
func invalidSize(sz, targetSz uint) bool {

0 commit comments

Comments
 (0)