Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
og-rek
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
og-rek
Commits
e25dfe7a
Commit
e25dfe7a
authored
Feb 28, 2017
by
Kamil Kisiel
Committed by
GitHub
Feb 28, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #28 from navytux/fix1
decoder: Stack overflow handling fixes
parents
be94c890
2a013587
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
94 additions
and
15 deletions
+94
-15
ogorek.go
ogorek.go
+79
-15
ogorek_test.go
ogorek_test.go
+15
-0
No files found.
ogorek.go
View file @
e25dfe7a
...
@@ -86,6 +86,7 @@ const (
...
@@ -86,6 +86,7 @@ const (
var
errNotImplemented
=
errors
.
New
(
"unimplemented opcode"
)
var
errNotImplemented
=
errors
.
New
(
"unimplemented opcode"
)
var
ErrInvalidPickleVersion
=
errors
.
New
(
"invalid pickle version"
)
var
ErrInvalidPickleVersion
=
errors
.
New
(
"invalid pickle version"
)
var
errNoMarker
=
errors
.
New
(
"no marker in stack"
)
var
errNoMarker
=
errors
.
New
(
"no marker in stack"
)
var
errStackUnderflow
=
errors
.
New
(
"pickle: stack underflow"
)
type
OpcodeError
struct
{
type
OpcodeError
struct
{
Key
byte
Key
byte
...
@@ -141,11 +142,11 @@ loop:
...
@@ -141,11 +142,11 @@ loop:
case
opStop
:
case
opStop
:
break
loop
break
loop
case
opPop
:
case
opPop
:
d
.
pop
()
_
,
err
=
d
.
pop
()
case
opPopMark
:
case
opPopMark
:
d
.
popMark
()
d
.
popMark
()
case
opDup
:
case
opDup
:
d
.
dup
()
err
=
d
.
dup
()
case
opFloat
:
case
opFloat
:
err
=
d
.
loadFloat
()
err
=
d
.
loadFloat
()
case
opInt
:
case
opInt
:
...
@@ -257,7 +258,7 @@ loop:
...
@@ -257,7 +258,7 @@ loop:
return
nil
,
err
return
nil
,
err
}
}
}
}
return
d
.
pop
()
,
nil
return
d
.
pop
()
}
}
func
(
d
*
Decoder
)
readLine
()
([]
byte
,
error
)
{
func
(
d
*
Decoder
)
readLine
()
([]
byte
,
error
)
{
...
@@ -285,11 +286,10 @@ func (d *Decoder) mark() {
...
@@ -285,11 +286,10 @@ func (d *Decoder) mark() {
// Return the position of the topmost marker
// Return the position of the topmost marker
func
(
d
*
Decoder
)
marker
()
(
int
,
error
)
{
func
(
d
*
Decoder
)
marker
()
(
int
,
error
)
{
m
:=
mark
{}
m
:=
mark
{}
var
k
int
for
k
:=
len
(
d
.
stack
)
-
1
;
k
>=
0
;
k
--
{
for
k
=
len
(
d
.
stack
)
-
1
;
d
.
stack
[
k
]
!=
m
&&
k
>
0
;
k
--
{
if
d
.
stack
[
k
]
==
m
{
}
return
k
,
nil
if
k
>=
0
{
}
return
k
,
nil
}
}
return
0
,
errNoMarker
return
0
,
errNoMarker
}
}
...
@@ -300,10 +300,23 @@ func (d *Decoder) push(v interface{}) {
...
@@ -300,10 +300,23 @@ func (d *Decoder) push(v interface{}) {
}
}
// Pop a value
// Pop a value
func
(
d
*
Decoder
)
pop
()
interface
{}
{
// The returned error is errStackUnderflow if decoder stack is empty
func
(
d
*
Decoder
)
pop
()
(
interface
{},
error
)
{
ln
:=
len
(
d
.
stack
)
-
1
ln
:=
len
(
d
.
stack
)
-
1
if
ln
<
0
{
return
nil
,
errStackUnderflow
}
v
:=
d
.
stack
[
ln
]
v
:=
d
.
stack
[
ln
]
d
.
stack
=
d
.
stack
[
:
ln
]
d
.
stack
=
d
.
stack
[
:
ln
]
return
v
,
nil
}
// Pop a value (when you know for sure decoder stack is not empty)
func
(
d
*
Decoder
)
xpop
()
interface
{}
{
v
,
err
:=
d
.
pop
()
if
err
!=
nil
{
panic
(
err
)
}
return
v
return
v
}
}
...
@@ -313,8 +326,12 @@ func (d *Decoder) popMark() error {
...
@@ -313,8 +326,12 @@ func (d *Decoder) popMark() error {
}
}
// Duplicate the top stack item
// Duplicate the top stack item
func
(
d
*
Decoder
)
dup
()
{
func
(
d
*
Decoder
)
dup
()
error
{
if
len
(
d
.
stack
)
<
1
{
return
errStackUnderflow
}
d
.
stack
=
append
(
d
.
stack
,
d
.
stack
[
len
(
d
.
stack
)
-
1
])
d
.
stack
=
append
(
d
.
stack
,
d
.
stack
[
len
(
d
.
stack
)
-
1
])
return
nil
}
}
// Push a float
// Push a float
...
@@ -385,6 +402,9 @@ func (d *Decoder) loadLong() error {
...
@@ -385,6 +402,9 @@ func (d *Decoder) loadLong() error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
len
(
line
)
<
1
{
return
io
.
ErrUnexpectedEOF
}
v
:=
new
(
big
.
Int
)
v
:=
new
(
big
.
Int
)
v
.
SetString
(
string
(
line
[
:
len
(
line
)
-
1
]),
10
)
v
.
SetString
(
string
(
line
[
:
len
(
line
)
-
1
]),
10
)
d
.
push
(
v
)
d
.
push
(
v
)
...
@@ -448,8 +468,19 @@ type Call struct {
...
@@ -448,8 +468,19 @@ type Call struct {
}
}
func
(
d
*
Decoder
)
reduce
()
error
{
func
(
d
*
Decoder
)
reduce
()
error
{
args
:=
d
.
pop
()
.
([]
interface
{})
if
len
(
d
.
stack
)
<
2
{
class
:=
d
.
pop
()
.
(
Class
)
return
errStackUnderflow
}
xargs
:=
d
.
xpop
()
xclass
:=
d
.
xpop
()
args
,
ok
:=
xargs
.
([]
interface
{})
if
!
ok
{
return
fmt
.
Errorf
(
"pickle: reduce: invalid args: %T"
,
xargs
)
}
class
,
ok
:=
xclass
.
(
Class
)
if
!
ok
{
return
fmt
.
Errorf
(
"pickle: reduce: invalid class: %T"
,
xclass
)
}
d
.
stack
=
append
(
d
.
stack
,
Call
{
Callable
:
class
,
Args
:
args
})
d
.
stack
=
append
(
d
.
stack
,
Call
{
Callable
:
class
,
Args
:
args
})
return
nil
return
nil
}
}
...
@@ -572,7 +603,10 @@ func (d *Decoder) loadBinUnicode() error {
...
@@ -572,7 +603,10 @@ func (d *Decoder) loadBinUnicode() error {
}
}
func
(
d
*
Decoder
)
loadAppend
()
error
{
func
(
d
*
Decoder
)
loadAppend
()
error
{
v
:=
d
.
pop
()
if
len
(
d
.
stack
)
<
2
{
return
errStackUnderflow
}
v
:=
d
.
xpop
()
l
:=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
l
:=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
switch
l
.
(
type
)
{
switch
l
.
(
type
)
{
case
[]
interface
{}
:
case
[]
interface
{}
:
...
@@ -631,6 +665,9 @@ func (d *Decoder) loadAppends() error {
...
@@ -631,6 +665,9 @@ func (d *Decoder) loadAppends() error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
k
<
1
{
return
errStackUnderflow
}
l
:=
d
.
stack
[
k
-
1
]
l
:=
d
.
stack
[
k
-
1
]
switch
l
.
(
type
)
{
switch
l
.
(
type
)
{
...
@@ -708,6 +745,9 @@ func (d *Decoder) loadTuple() error {
...
@@ -708,6 +745,9 @@ func (d *Decoder) loadTuple() error {
}
}
func
(
d
*
Decoder
)
loadTuple1
()
error
{
func
(
d
*
Decoder
)
loadTuple1
()
error
{
if
len
(
d
.
stack
)
<
1
{
return
errStackUnderflow
}
k
:=
len
(
d
.
stack
)
-
1
k
:=
len
(
d
.
stack
)
-
1
v
:=
append
([]
interface
{}{},
d
.
stack
[
k
:
]
...
)
v
:=
append
([]
interface
{}{},
d
.
stack
[
k
:
]
...
)
d
.
stack
=
append
(
d
.
stack
[
:
k
],
v
)
d
.
stack
=
append
(
d
.
stack
[
:
k
],
v
)
...
@@ -715,6 +755,9 @@ func (d *Decoder) loadTuple1() error {
...
@@ -715,6 +755,9 @@ func (d *Decoder) loadTuple1() error {
}
}
func
(
d
*
Decoder
)
loadTuple2
()
error
{
func
(
d
*
Decoder
)
loadTuple2
()
error
{
if
len
(
d
.
stack
)
<
2
{
return
errStackUnderflow
}
k
:=
len
(
d
.
stack
)
-
2
k
:=
len
(
d
.
stack
)
-
2
v
:=
append
([]
interface
{}{},
d
.
stack
[
k
:
]
...
)
v
:=
append
([]
interface
{}{},
d
.
stack
[
k
:
]
...
)
d
.
stack
=
append
(
d
.
stack
[
:
k
],
v
)
d
.
stack
=
append
(
d
.
stack
[
:
k
],
v
)
...
@@ -722,6 +765,9 @@ func (d *Decoder) loadTuple2() error {
...
@@ -722,6 +765,9 @@ func (d *Decoder) loadTuple2() error {
}
}
func
(
d
*
Decoder
)
loadTuple3
()
error
{
func
(
d
*
Decoder
)
loadTuple3
()
error
{
if
len
(
d
.
stack
)
<
3
{
return
errStackUnderflow
}
k
:=
len
(
d
.
stack
)
-
3
k
:=
len
(
d
.
stack
)
-
3
v
:=
append
([]
interface
{}{},
d
.
stack
[
k
:
]
...
)
v
:=
append
([]
interface
{}{},
d
.
stack
[
k
:
]
...
)
d
.
stack
=
append
(
d
.
stack
[
:
k
],
v
)
d
.
stack
=
append
(
d
.
stack
[
:
k
],
v
)
...
@@ -737,11 +783,17 @@ func (d *Decoder) loadPut() error {
...
@@ -737,11 +783,17 @@ func (d *Decoder) loadPut() error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
len
(
d
.
stack
)
<
1
{
return
errStackUnderflow
}
d
.
memo
[
string
(
line
)]
=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
d
.
memo
[
string
(
line
)]
=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
return
nil
return
nil
}
}
func
(
d
*
Decoder
)
binPut
()
error
{
func
(
d
*
Decoder
)
binPut
()
error
{
if
len
(
d
.
stack
)
<
1
{
return
errStackUnderflow
}
b
,
err
:=
d
.
r
.
ReadByte
()
b
,
err
:=
d
.
r
.
ReadByte
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -752,6 +804,9 @@ func (d *Decoder) binPut() error {
...
@@ -752,6 +804,9 @@ func (d *Decoder) binPut() error {
}
}
func
(
d
*
Decoder
)
longBinPut
()
error
{
func
(
d
*
Decoder
)
longBinPut
()
error
{
if
len
(
d
.
stack
)
<
1
{
return
errStackUnderflow
}
var
b
[
4
]
byte
var
b
[
4
]
byte
_
,
err
:=
io
.
ReadFull
(
d
.
r
,
b
[
:
])
_
,
err
:=
io
.
ReadFull
(
d
.
r
,
b
[
:
])
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -763,8 +818,11 @@ func (d *Decoder) longBinPut() error {
...
@@ -763,8 +818,11 @@ func (d *Decoder) longBinPut() error {
}
}
func
(
d
*
Decoder
)
loadSetItem
()
error
{
func
(
d
*
Decoder
)
loadSetItem
()
error
{
v
:=
d
.
pop
()
if
len
(
d
.
stack
)
<
3
{
k
:=
d
.
pop
()
return
errStackUnderflow
}
v
:=
d
.
xpop
()
k
:=
d
.
xpop
()
m
:=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
m
:=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
switch
m
.
(
type
)
{
switch
m
.
(
type
)
{
case
map
[
interface
{}]
interface
{}
:
case
map
[
interface
{}]
interface
{}
:
...
@@ -781,6 +839,9 @@ func (d *Decoder) loadSetItems() error {
...
@@ -781,6 +839,9 @@ func (d *Decoder) loadSetItems() error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
if
k
<
1
{
return
errStackUnderflow
}
l
:=
d
.
stack
[
k
-
1
]
l
:=
d
.
stack
[
k
-
1
]
switch
m
:=
l
.
(
type
)
{
switch
m
:=
l
.
(
type
)
{
...
@@ -833,6 +894,9 @@ func (d *Decoder) loadShortBinUnicode() error {
...
@@ -833,6 +894,9 @@ func (d *Decoder) loadShortBinUnicode() error {
}
}
func
(
d
*
Decoder
)
loadMemoize
()
error
{
func
(
d
*
Decoder
)
loadMemoize
()
error
{
if
len
(
d
.
stack
)
<
1
{
return
errStackUnderflow
}
d
.
memo
[
strconv
.
Itoa
(
len
(
d
.
memo
))]
=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
d
.
memo
[
strconv
.
Itoa
(
len
(
d
.
memo
))]
=
d
.
stack
[
len
(
d
.
stack
)
-
1
]
return
nil
return
nil
}
}
...
...
ogorek_test.go
View file @
e25dfe7a
...
@@ -100,6 +100,21 @@ func TestDecode(t *testing.T) {
...
@@ -100,6 +100,21 @@ func TestDecode(t *testing.T) {
t
.
Errorf
(
"%s: no ErrUnexpectedEOF on [:%d] truncated stream: v = %#v err = %#v"
,
test
.
name
,
l
,
v
,
err
)
t
.
Errorf
(
"%s: no ErrUnexpectedEOF on [:%d] truncated stream: v = %#v err = %#v"
,
test
.
name
,
l
,
v
,
err
)
}
}
}
}
// by using input with omitted prefix we can test how code handles pickle stack overflow:
// it must not panic
for
i
:=
0
;
i
<
len
(
test
.
input
);
i
++
{
buf
:=
bytes
.
NewBufferString
(
test
.
input
[
i
:
])
dec
:=
NewDecoder
(
buf
)
func
()
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
t
.
Errorf
(
"%s: panic on input[%d:]: %v"
,
test
.
name
,
i
,
r
)
}
}()
dec
.
Decode
()
}()
}
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment