Blame


1 0f5f58bb 2016-11-16 stephen.d package p9p
2 0f5f58bb 2016-11-16 stephen.d
3 0f5f58bb 2016-11-16 stephen.d import (
4 0f5f58bb 2016-11-16 stephen.d "bytes"
5 0f5f58bb 2016-11-16 stephen.d "context"
6 0f5f58bb 2016-11-16 stephen.d "encoding/binary"
7 0f5f58bb 2016-11-16 stephen.d "net"
8 0f5f58bb 2016-11-16 stephen.d "testing"
9 0f5f58bb 2016-11-16 stephen.d "time"
10 0f5f58bb 2016-11-16 stephen.d )
11 0f5f58bb 2016-11-16 stephen.d
12 0f5f58bb 2016-11-16 stephen.d // TestTwriteOverflow ensures that a Twrite message will have the data field
13 0f5f58bb 2016-11-16 stephen.d // truncated if the msize would be exceeded.
14 0f5f58bb 2016-11-16 stephen.d func TestTwriteOverflow(t *testing.T) {
15 0f5f58bb 2016-11-16 stephen.d const (
16 0f5f58bb 2016-11-16 stephen.d msize = 512
17 0f5f58bb 2016-11-16 stephen.d
18 0f5f58bb 2016-11-16 stephen.d // size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] | count = 0
19 0f5f58bb 2016-11-16 stephen.d overhead = 4 + 1 + 2 + 4 + 8 + 4
20 0f5f58bb 2016-11-16 stephen.d )
21 0f5f58bb 2016-11-16 stephen.d
22 0f5f58bb 2016-11-16 stephen.d var (
23 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
24 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
25 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
26 0f5f58bb 2016-11-16 stephen.d )
27 0f5f58bb 2016-11-16 stephen.d
28 0f5f58bb 2016-11-16 stephen.d for _, testcase := range []struct {
29 0f5f58bb 2016-11-16 stephen.d name string
30 0f5f58bb 2016-11-16 stephen.d overflow int // amount to overflow the message by.
31 0f5f58bb 2016-11-16 stephen.d }{
32 0f5f58bb 2016-11-16 stephen.d {
33 0f5f58bb 2016-11-16 stephen.d name: "BoundedOverflow",
34 0f5f58bb 2016-11-16 stephen.d overflow: msize / 2,
35 0f5f58bb 2016-11-16 stephen.d },
36 0f5f58bb 2016-11-16 stephen.d {
37 0f5f58bb 2016-11-16 stephen.d name: "LargeOverflow",
38 0f5f58bb 2016-11-16 stephen.d overflow: msize * 3,
39 0f5f58bb 2016-11-16 stephen.d },
40 0f5f58bb 2016-11-16 stephen.d {
41 0f5f58bb 2016-11-16 stephen.d name: "HeaderOverflow",
42 0f5f58bb 2016-11-16 stephen.d overflow: overhead,
43 0f5f58bb 2016-11-16 stephen.d },
44 0f5f58bb 2016-11-16 stephen.d {
45 0f5f58bb 2016-11-16 stephen.d name: "HeaderOffsetOverflow",
46 0f5f58bb 2016-11-16 stephen.d overflow: overhead - 1,
47 0f5f58bb 2016-11-16 stephen.d },
48 0f5f58bb 2016-11-16 stephen.d {
49 0f5f58bb 2016-11-16 stephen.d name: "OverflowByOne",
50 0f5f58bb 2016-11-16 stephen.d overflow: 1,
51 0f5f58bb 2016-11-16 stephen.d },
52 0f5f58bb 2016-11-16 stephen.d } {
53 0f5f58bb 2016-11-16 stephen.d
54 0f5f58bb 2016-11-16 stephen.d t.Run(testcase.name, func(t *testing.T) {
55 0f5f58bb 2016-11-16 stephen.d var (
56 0f5f58bb 2016-11-16 stephen.d fcall = overflowMessage(ch.(*channel).codec, msize, testcase.overflow)
57 0f5f58bb 2016-11-16 stephen.d data = fcall.Message.(MessageTwrite).Data
58 0f5f58bb 2016-11-16 stephen.d size uint32
59 0f5f58bb 2016-11-16 stephen.d )
60 0f5f58bb 2016-11-16 stephen.d
61 0f5f58bb 2016-11-16 stephen.d t.Logf("overflow: %v, len(data): %v, expected overflow: %v", testcase.overflow, len(data), overhead+len(data)-msize)
62 0f5f58bb 2016-11-16 stephen.d conn.buf.Reset()
63 0f5f58bb 2016-11-16 stephen.d if err := ch.WriteFcall(ctx, fcall); err != nil {
64 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
65 0f5f58bb 2016-11-16 stephen.d }
66 0f5f58bb 2016-11-16 stephen.d
67 0f5f58bb 2016-11-16 stephen.d if err := binary.Read(bytes.NewReader(conn.buf.Bytes()), binary.LittleEndian, &size); err != nil {
68 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
69 0f5f58bb 2016-11-16 stephen.d }
70 0f5f58bb 2016-11-16 stephen.d
71 0f5f58bb 2016-11-16 stephen.d if size != msize {
72 0f5f58bb 2016-11-16 stephen.d t.Fatalf("should have truncated size header: %d != %d", size, msize)
73 0f5f58bb 2016-11-16 stephen.d }
74 0f5f58bb 2016-11-16 stephen.d
75 0f5f58bb 2016-11-16 stephen.d if conn.buf.Len() != msize {
76 0f5f58bb 2016-11-16 stephen.d t.Fatalf("should have truncated message: conn.buf.Len(%v) != msize(%v)", conn.buf.Len(), msize)
77 0f5f58bb 2016-11-16 stephen.d }
78 0f5f58bb 2016-11-16 stephen.d })
79 0f5f58bb 2016-11-16 stephen.d }
80 0f5f58bb 2016-11-16 stephen.d
81 0f5f58bb 2016-11-16 stephen.d }
82 0f5f58bb 2016-11-16 stephen.d
83 0f5f58bb 2016-11-16 stephen.d // TestWriteOverflowError ensures that we return an error in cases when there
84 0f5f58bb 2016-11-16 stephen.d // will certainly be an overflow and it cannot be resolved.
85 0f5f58bb 2016-11-16 stephen.d func TestWriteOverflowError(t *testing.T) {
86 0f5f58bb 2016-11-16 stephen.d const (
87 0f5f58bb 2016-11-16 stephen.d msize = 4
88 0f5f58bb 2016-11-16 stephen.d overflowMSize = msize + 1
89 0f5f58bb 2016-11-16 stephen.d )
90 0f5f58bb 2016-11-16 stephen.d
91 0f5f58bb 2016-11-16 stephen.d var (
92 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
93 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
94 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
95 0f5f58bb 2016-11-16 stephen.d data = bytes.Repeat([]byte{'A'}, 4)
96 0f5f58bb 2016-11-16 stephen.d fcall = newFcall(1, MessageTwrite{
97 0f5f58bb 2016-11-16 stephen.d Data: data,
98 0f5f58bb 2016-11-16 stephen.d })
99 0f5f58bb 2016-11-16 stephen.d messageSize = 4 + ch.(*channel).codec.Size(fcall)
100 0f5f58bb 2016-11-16 stephen.d )
101 0f5f58bb 2016-11-16 stephen.d
102 0f5f58bb 2016-11-16 stephen.d err := ch.WriteFcall(ctx, fcall)
103 0f5f58bb 2016-11-16 stephen.d if err == nil {
104 0f5f58bb 2016-11-16 stephen.d t.Fatal("error expected when overflowing message")
105 0f5f58bb 2016-11-16 stephen.d }
106 0f5f58bb 2016-11-16 stephen.d
107 0f5f58bb 2016-11-16 stephen.d if Overflow(err) != messageSize-msize {
108 0f5f58bb 2016-11-16 stephen.d t.Fatalf("overflow should reflect messageSize and msize, %d != %d", Overflow(err), messageSize-msize)
109 0f5f58bb 2016-11-16 stephen.d }
110 0f5f58bb 2016-11-16 stephen.d }
111 0f5f58bb 2016-11-16 stephen.d
112 0f5f58bb 2016-11-16 stephen.d // TestReadOverflow ensures that messages coming over a network connection do
113 0f5f58bb 2016-11-16 stephen.d // not overflow the msize. Invalid messages will cause `ReadFcall` to return an
114 0f5f58bb 2016-11-16 stephen.d // Overflow error.
115 0f5f58bb 2016-11-16 stephen.d func TestReadFcallOverflow(t *testing.T) {
116 0f5f58bb 2016-11-16 stephen.d const (
117 0f5f58bb 2016-11-16 stephen.d msize = 256
118 0f5f58bb 2016-11-16 stephen.d )
119 0f5f58bb 2016-11-16 stephen.d
120 0f5f58bb 2016-11-16 stephen.d var (
121 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
122 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
123 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
124 0f5f58bb 2016-11-16 stephen.d codec = ch.(*channel).codec
125 0f5f58bb 2016-11-16 stephen.d )
126 0f5f58bb 2016-11-16 stephen.d
127 0f5f58bb 2016-11-16 stephen.d for _, testcase := range []struct {
128 0f5f58bb 2016-11-16 stephen.d name string
129 0f5f58bb 2016-11-16 stephen.d overflow int
130 0f5f58bb 2016-11-16 stephen.d }{
131 0f5f58bb 2016-11-16 stephen.d {
132 0f5f58bb 2016-11-16 stephen.d name: "OverflowByOne",
133 0f5f58bb 2016-11-16 stephen.d overflow: 1,
134 0f5f58bb 2016-11-16 stephen.d },
135 0f5f58bb 2016-11-16 stephen.d {
136 0f5f58bb 2016-11-16 stephen.d name: "HeaderOverflow",
137 0f5f58bb 2016-11-16 stephen.d overflow: overheadMessage(codec, MessageTwrite{}),
138 0f5f58bb 2016-11-16 stephen.d },
139 0f5f58bb 2016-11-16 stephen.d {
140 0f5f58bb 2016-11-16 stephen.d name: "HeaderOffsetOverflow",
141 0f5f58bb 2016-11-16 stephen.d overflow: overheadMessage(codec, MessageTwrite{}) - 1,
142 0f5f58bb 2016-11-16 stephen.d },
143 0f5f58bb 2016-11-16 stephen.d } {
144 0f5f58bb 2016-11-16 stephen.d t.Run(testcase.name, func(t *testing.T) {
145 0f5f58bb 2016-11-16 stephen.d fcall := overflowMessage(codec, msize, testcase.overflow)
146 0f5f58bb 2016-11-16 stephen.d
147 0f5f58bb 2016-11-16 stephen.d // prepare the raw message
148 0f5f58bb 2016-11-16 stephen.d p, err := ch.(*channel).codec.Marshal(fcall)
149 0f5f58bb 2016-11-16 stephen.d if err != nil {
150 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
151 0f5f58bb 2016-11-16 stephen.d }
152 0f5f58bb 2016-11-16 stephen.d
153 0f5f58bb 2016-11-16 stephen.d // "send" the message into the buffer
154 0f5f58bb 2016-11-16 stephen.d // this message is crafted to overflow the read buffer.
155 0f5f58bb 2016-11-16 stephen.d if err := sendmsg(&conn.buf, p); err != nil {
156 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
157 0f5f58bb 2016-11-16 stephen.d }
158 0f5f58bb 2016-11-16 stephen.d
159 0f5f58bb 2016-11-16 stephen.d var incoming Fcall
160 0f5f58bb 2016-11-16 stephen.d err = ch.ReadFcall(ctx, &incoming)
161 0f5f58bb 2016-11-16 stephen.d if err == nil {
162 0f5f58bb 2016-11-16 stephen.d t.Fatal("expected error on fcall")
163 0f5f58bb 2016-11-16 stephen.d }
164 0f5f58bb 2016-11-16 stephen.d
165 0f5f58bb 2016-11-16 stephen.d // sanity check to ensure our test code has the right overflow
166 0f5f58bb 2016-11-16 stephen.d if testcase.overflow != ch.(*channel).msgmsize(fcall)-msize {
167 0f5f58bb 2016-11-16 stephen.d t.Fatalf("overflow calculation incorrect: %v != %v", testcase.overflow, ch.(*channel).msgmsize(fcall)-msize)
168 0f5f58bb 2016-11-16 stephen.d }
169 0f5f58bb 2016-11-16 stephen.d
170 0f5f58bb 2016-11-16 stephen.d if Overflow(err) != testcase.overflow {
171 0f5f58bb 2016-11-16 stephen.d t.Fatalf("unexpected overflow on error: %v !=%v", Overflow(err), testcase.overflow)
172 0f5f58bb 2016-11-16 stephen.d }
173 0f5f58bb 2016-11-16 stephen.d })
174 0f5f58bb 2016-11-16 stephen.d }
175 0f5f58bb 2016-11-16 stephen.d }
176 0f5f58bb 2016-11-16 stephen.d
177 0f5f58bb 2016-11-16 stephen.d // TestTreadRewrite ensures that messages that whose response would overflow
178 0f5f58bb 2016-11-16 stephen.d // the msize will have be adjusted before sending.
179 0f5f58bb 2016-11-16 stephen.d func TestTreadRewrite(t *testing.T) {
180 0f5f58bb 2016-11-16 stephen.d const (
181 0f5f58bb 2016-11-16 stephen.d msize = 256
182 0f5f58bb 2016-11-16 stephen.d overflowMSize = msize + 1
183 0f5f58bb 2016-11-16 stephen.d )
184 0f5f58bb 2016-11-16 stephen.d
185 0f5f58bb 2016-11-16 stephen.d var (
186 0f5f58bb 2016-11-16 stephen.d ctx = context.Background()
187 0f5f58bb 2016-11-16 stephen.d conn = &mockConn{}
188 0f5f58bb 2016-11-16 stephen.d ch = NewChannel(conn, msize)
189 0f5f58bb 2016-11-16 stephen.d buf = make([]byte, overflowMSize)
190 0f5f58bb 2016-11-16 stephen.d // data = bytes.Repeat([]byte{'A'}, overflowMSize)
191 0f5f58bb 2016-11-16 stephen.d fcall = newFcall(1, MessageTread{
192 0f5f58bb 2016-11-16 stephen.d Count: overflowMSize,
193 0f5f58bb 2016-11-16 stephen.d })
194 0f5f58bb 2016-11-16 stephen.d responseMSize = ch.(*channel).msgmsize(newFcall(1, MessageRread{
195 0f5f58bb 2016-11-16 stephen.d Data: buf,
196 0f5f58bb 2016-11-16 stephen.d }))
197 0f5f58bb 2016-11-16 stephen.d )
198 0f5f58bb 2016-11-16 stephen.d
199 0f5f58bb 2016-11-16 stephen.d if err := ch.WriteFcall(ctx, fcall); err != nil {
200 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
201 0f5f58bb 2016-11-16 stephen.d }
202 0f5f58bb 2016-11-16 stephen.d
203 0f5f58bb 2016-11-16 stephen.d // just read the message off the buffer
204 0f5f58bb 2016-11-16 stephen.d n, err := readmsg(&conn.buf, buf)
205 0f5f58bb 2016-11-16 stephen.d if err != nil {
206 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
207 0f5f58bb 2016-11-16 stephen.d }
208 0f5f58bb 2016-11-16 stephen.d
209 0f5f58bb 2016-11-16 stephen.d *fcall = Fcall{}
210 0f5f58bb 2016-11-16 stephen.d if err := ch.(*channel).codec.Unmarshal(buf[:n], fcall); err != nil {
211 0f5f58bb 2016-11-16 stephen.d t.Fatal(err)
212 0f5f58bb 2016-11-16 stephen.d }
213 0f5f58bb 2016-11-16 stephen.d
214 0f5f58bb 2016-11-16 stephen.d tread, ok := fcall.Message.(MessageTread)
215 0f5f58bb 2016-11-16 stephen.d if !ok {
216 0f5f58bb 2016-11-16 stephen.d t.Fatalf("unexpected message: %v", fcall)
217 0f5f58bb 2016-11-16 stephen.d }
218 0f5f58bb 2016-11-16 stephen.d
219 0f5f58bb 2016-11-16 stephen.d if tread.Count != overflowMSize-(uint32(responseMSize)-msize) {
220 0f5f58bb 2016-11-16 stephen.d t.Fatalf("count not rewritten: %v != %v", tread.Count, overflowMSize-(uint32(responseMSize)-msize))
221 0f5f58bb 2016-11-16 stephen.d }
222 0f5f58bb 2016-11-16 stephen.d }
223 0f5f58bb 2016-11-16 stephen.d
224 0f5f58bb 2016-11-16 stephen.d type mockConn struct {
225 0f5f58bb 2016-11-16 stephen.d net.Conn
226 0f5f58bb 2016-11-16 stephen.d buf bytes.Buffer
227 0f5f58bb 2016-11-16 stephen.d }
228 0f5f58bb 2016-11-16 stephen.d
229 0f5f58bb 2016-11-16 stephen.d func (m mockConn) SetWriteDeadline(t time.Time) error { return nil }
230 0f5f58bb 2016-11-16 stephen.d func (m mockConn) SetReadDeadline(t time.Time) error { return nil }
231 0f5f58bb 2016-11-16 stephen.d
232 0f5f58bb 2016-11-16 stephen.d func (m *mockConn) Write(p []byte) (int, error) {
233 0f5f58bb 2016-11-16 stephen.d return m.buf.Write(p)
234 0f5f58bb 2016-11-16 stephen.d }
235 0f5f58bb 2016-11-16 stephen.d
236 0f5f58bb 2016-11-16 stephen.d func (m *mockConn) Read(p []byte) (int, error) {
237 0f5f58bb 2016-11-16 stephen.d return m.buf.Read(p)
238 0f5f58bb 2016-11-16 stephen.d }
239 0f5f58bb 2016-11-16 stephen.d
240 0f5f58bb 2016-11-16 stephen.d func overheadMessage(codec Codec, msg Message) int {
241 0f5f58bb 2016-11-16 stephen.d return 4 + codec.Size(newFcall(1, msg))
242 0f5f58bb 2016-11-16 stephen.d }
243 0f5f58bb 2016-11-16 stephen.d
244 0f5f58bb 2016-11-16 stephen.d // overflowMessage returns message that overflows the msize by overflow bytes,
245 0f5f58bb 2016-11-16 stephen.d // returning the message size and the fcall.
246 0f5f58bb 2016-11-16 stephen.d func overflowMessage(codec Codec, msize, overflow int) *Fcall {
247 0f5f58bb 2016-11-16 stephen.d var (
248 0f5f58bb 2016-11-16 stephen.d overhead = overheadMessage(codec, MessageTwrite{})
249 0f5f58bb 2016-11-16 stephen.d data = bytes.Repeat([]byte{'A'}, (msize-overhead)+overflow)
250 0f5f58bb 2016-11-16 stephen.d fcall = newFcall(1, MessageTwrite{
251 0f5f58bb 2016-11-16 stephen.d Data: data,
252 0f5f58bb 2016-11-16 stephen.d })
253 0f5f58bb 2016-11-16 stephen.d )
254 0f5f58bb 2016-11-16 stephen.d
255 0f5f58bb 2016-11-16 stephen.d return fcall
256 0f5f58bb 2016-11-16 stephen.d }