]> git.tdb.fi Git - gldbg.git/blob - source/packet.c
Protect against giving invalid pointers to writev
[gldbg.git] / source / packet.c
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/uio.h>
11 #include <unistd.h>
12 #include "packet.h"
13 #include "tmpalloc.h"
14
15 struct GlOutPacket
16 {
17         char *ptr;
18         unsigned length;
19         struct iovec *vec;
20 };
21
22 struct GlInPacket
23 {
24         const char *ptr;
25         unsigned length;
26         unsigned chunk;
27 };
28
29 typedef struct GlOutPacket GlOutPacket;
30 typedef struct GlInPacket GlInPacket;
31
32 struct GlPacket
33 {
34         union
35         {
36                 GlOutPacket out;
37                 GlInPacket in;
38         };
39 };
40
41 // XXX Should make this stuff truly re-entrant
42 static char *out_buffer = NULL;
43 static struct iovec *iovecs = NULL;
44 static GlPacket packet;
45 static char *in_buffer = NULL;
46 static unsigned in_fill = 0;
47 static unsigned in_offset = 0;
48
49 static void next_vec(GlPacket *pkt)
50 {
51         GlOutPacket *out = &pkt->out;
52
53         if(out->ptr!=out->vec->iov_base)
54         {
55                 out->vec->iov_len = out->ptr-(char *)out->vec->iov_base;
56                 out->length += out->vec->iov_len;
57                 ++out->vec;
58                 out->vec->iov_base = out->ptr;
59         }
60 }
61
62 static void reset(GlPacket *pkt)
63 {
64         GlOutPacket *out = &pkt->out;
65
66         out->ptr = out_buffer;
67         out->vec = iovecs;
68         out->vec->iov_base = out->ptr;
69         out->length = 0;
70 }
71
72 GlPacket *packet_begin(unsigned short func)
73 {
74         GlPacket *pkt;
75
76         if(!out_buffer)
77                 out_buffer = (char *)malloc(1024);
78         if(!iovecs)
79                 iovecs = (struct iovec *)malloc(16*sizeof(struct iovec));
80
81         pkt = &packet;
82         reset(pkt);
83
84         packet_write_int(pkt, 0);
85         packet_write_short(pkt, func);
86
87         return pkt;
88 }
89
90 void packet_send_partial(GlPacket *pkt, int fd)
91 {
92         GlOutPacket *out = &pkt->out;
93
94         out->length |= 0x80000000;
95         packet_send(pkt, fd);
96
97         reset(pkt);
98
99         packet_write_int(pkt, 0);
100 }
101
102 void packet_send(GlPacket *pkt, int fd)
103 {
104         GlOutPacket *out = &pkt->out;
105         struct iovec *v;
106
107         next_vec(pkt);
108         out->ptr = out_buffer;
109         packet_write_int(pkt, out->length);
110
111         for(v=iovecs; v!=out->vec; )
112         {
113                 int ret;
114
115                 ret = writev(fd, v, out->vec-v);
116                 if(ret<0)
117                         return;
118
119                 while(v!=out->vec && (unsigned)ret>=v->iov_len)
120                 {
121                         ret -= v->iov_len;
122                         ++v;
123                 }
124
125                 if(v!=out->vec)
126                 {
127                         v->iov_base += ret;
128                         v->iov_len -= ret;
129                 }
130         }
131 }
132
133 static void write_raw(GlPacket *pkt, const char *ptr, unsigned size, int byteswap)
134 {
135         GlOutPacket *out = &pkt->out;
136         unsigned i;
137
138 #if __BYTE_ORDER == __LITTLE_ENDIAN
139         if(byteswap)
140         {
141                 ptr += size;
142                 for(i=0; i<size; ++i)
143                         *out->ptr++ = *--ptr;
144         }
145         else
146 #endif
147         {
148                 for(i=0; i<size; ++i)
149                         *out->ptr++ = *ptr++;
150         }
151 }
152
153 void packet_write_char(GlPacket *pkt, char v)
154 {
155         GlOutPacket *out = &pkt->out;
156         *out->ptr++ = v;
157 }
158
159 void packet_write_short(GlPacket *pkt, short v)
160 {
161         write_raw(pkt, (char *)&v, sizeof(short), 1);
162 }
163
164 void packet_write_int(GlPacket *pkt, int v)
165 {
166         write_raw(pkt, (char *)&v, sizeof(int), 1);
167 }
168
169 void packet_write_long(GlPacket *pkt, long v)
170 {
171         write_raw(pkt, (char *)&v, sizeof(long), 1);
172 }
173
174 void packet_write_long_long(GlPacket *pkt, long long v)
175 {
176         write_raw(pkt, (char *)&v, sizeof(long long), 1);
177 }
178
179 void packet_write_float(GlPacket *pkt, float v)
180 {
181         write_raw(pkt, (char *)&v, sizeof(float), 1);
182 }
183
184 void packet_write_double(GlPacket *pkt, double v)
185 {
186         write_raw(pkt, (char *)&v, sizeof(double), 1);
187 }
188
189 void packet_write_pointer(GlPacket *pkt, const void *p)
190 {
191         write_raw(pkt, (char *)&p, sizeof(void *), 1);
192 }
193
194 void packet_write_data(GlPacket *pkt, const void *data, unsigned size)
195 {
196         if(!data)
197                 packet_write_int(pkt, 0);
198         else if((unsigned long)data<0x100000)
199         {
200                 packet_write_int(pkt, ~0);
201                 packet_write_pointer(pkt, data);
202         }
203         else
204         {
205                 GlOutPacket *out = &pkt->out;
206
207                 packet_write_int(pkt, size);
208                 next_vec(pkt);
209                 out->vec->iov_base = (void *)data;
210                 out->vec->iov_len = size;
211                 out->length += size;
212                 ++out->vec;
213                 out->vec->iov_base = out->ptr;
214         }
215 }
216
217 void packet_write_string(GlPacket *pkt, const char *s)
218 {
219         packet_write_data(pkt, s, strlen(s)+1);
220 }
221
222 void packet_write_string_array(GlPacket *pkt, const char **sa, unsigned size)
223 {
224         unsigned i;
225         size /= sizeof(const char *);
226         packet_write_int(pkt, size);
227         for(i=0; i<size; ++i)
228                 packet_write_string(pkt, sa[i]);
229 }
230
231 GlPacket *packet_receive_str(const char *data, unsigned *len)
232 {
233         const char *end = data+*len;
234         GlPacket *pkt;
235         GlInPacket *in;
236
237         if(*len<sizeof(int)+sizeof(short))
238                 return 0;
239
240         pkt = &packet;
241         in = &pkt->in;
242         in->ptr = data;
243         in->chunk = *len;
244
245         packet_read_int(pkt, (int *)&in->chunk);
246
247         if(in->chunk&0x80000000)
248         {
249                 in->chunk &= 0x7FFFFFFF;
250                 in->length = in->chunk;
251
252                 while(1)
253                 {
254                         if(end<in->ptr+in->length+sizeof(int))
255                                 return NULL;
256
257                         GlPacket p;
258                         p.in.ptr = in->ptr+in->length;
259                         p.in.chunk = p.in.length = end-p.in.ptr;
260
261                         unsigned chunk;
262                         packet_read_int(&p, (int *)&chunk);
263
264                         in->length += chunk&0x7FFFFFFF;
265                         if(!(chunk&0x80000000))
266                                 break;
267                 }
268         }
269         else
270                 in->length = in->chunk;
271
272         if(end<in->ptr+in->length)
273                 return NULL;
274
275         *len = in->ptr+in->length-data;
276
277         return pkt;
278 }
279
280 GlPacket *packet_receive(int fd)
281 {
282         int ret;
283         fd_set fds;
284         struct timeval tv = { 0, 0 };
285
286         FD_ZERO(&fds);
287         FD_SET(fd, &fds);
288         ret = select(fd+1, &fds, NULL, NULL, &tv);
289         if(ret>0)
290         {
291                 if(!in_buffer)
292                         in_buffer = (char *)malloc(1024);
293
294                 if(in_offset)
295                 {
296                         memmove(in_buffer, in_buffer+in_offset, in_fill-in_offset);
297                         in_fill -= in_offset;
298                         in_offset = 0;
299                 }
300
301                 ret = read(fd, in_buffer+in_fill, 1024-in_fill);
302                 if(ret>0)
303                         in_fill += ret;
304         }
305
306         if(ret>0 || in_fill>in_offset)
307         {
308                 GlPacket *pkt;
309                 unsigned pkt_length;
310
311                 pkt_length = in_fill;
312                 pkt = packet_receive_str(in_buffer+in_offset, &pkt_length);
313                 if(pkt)
314                         in_offset += pkt_length;
315
316                 return pkt;
317         }
318
319         return NULL;
320 }
321
322 static void next_chunk(GlPacket *pkt)
323 {
324         GlInPacket *in = &pkt->in;
325
326         if(in->length==0)
327                 return;
328
329         in->chunk = in->length;
330         packet_read_int(pkt, (int *)&in->chunk);
331         in->chunk &= 0x7FFFFFFF;
332 }
333
334 static void read_raw(GlPacket *pkt, char *ptr, unsigned size, int byteswap)
335 {
336         GlInPacket *in = &pkt->in;
337
338         if(in->chunk==0)
339                 next_chunk(pkt);
340
341         if(in->chunk>=size)
342         {
343                 unsigned i;
344
345 #if __BYTE_ORDER == __LITTLE_ENDIAN
346                 if(byteswap)
347                 {
348                         ptr += size;
349                         for(i=0; i<size; ++i)
350                                 *--ptr = *in->ptr++;
351                 }
352                 else
353 #endif
354                 {
355                         for(i=0; i<size; ++i)
356                                 *ptr++ = *in->ptr++;
357                 }
358
359                 in->length -= size;
360                 in->chunk -= size;
361         }
362         else
363         {
364                 memset(ptr, 0, size);
365                 in->length -= in->chunk;
366                 in->chunk = 0;
367         }
368 }
369
370 void packet_read_char(GlPacket *pkt, char *v)
371 {
372         read_raw(pkt, v, 1, 0);
373 }
374
375 void packet_read_short(GlPacket *pkt, short *v)
376 {
377         read_raw(pkt, (char *)v, sizeof(short), 1);
378 }
379
380 void packet_read_int(GlPacket *pkt, int *v)
381 {
382         read_raw(pkt, (char *)v, sizeof(int), 1);
383 }
384
385 void packet_read_long(GlPacket *pkt, long *v)
386 {
387         read_raw(pkt, (char *)v, sizeof(long), 1);
388 }
389
390 void packet_read_long_long(GlPacket *pkt, long long *v)
391 {
392         read_raw(pkt, (char *)v, sizeof(long long), 1);
393 }
394
395 void packet_read_float(GlPacket *pkt, float *v)
396 {
397         read_raw(pkt, (char *)v, sizeof(float), 1);
398 }
399
400 void packet_read_double(GlPacket *pkt, double *v)
401 {
402         read_raw(pkt, (char *)v, sizeof(double), 1);
403 }
404
405 void packet_read_pointer(GlPacket *pkt, const void **v)
406 {
407         read_raw(pkt, (char *)v, sizeof(const void *), 1);
408 }
409
410 void packet_read_data(GlPacket *pkt, const void **v)
411 {
412         GlInPacket *in = &pkt->in;
413         int vlen;
414
415         packet_read_int(pkt, &vlen);
416         if(vlen==~0)
417                 packet_read_pointer(pkt, v);
418         else if(vlen)
419         {
420                 *v = in->ptr;
421                 in->ptr += vlen;
422                 in->chunk -= vlen;
423                 in->length -= vlen;
424         }
425         else
426                 *v = NULL;
427 }
428
429 void packet_read_string(GlPacket *pkt, const char **v)
430 {
431         packet_read_data(pkt, (const void **)v);
432 }
433
434 void packet_read_string_array(GlPacket *pkt, const char ***v)
435 {
436         int count;
437         int i;
438         packet_read_int(pkt, &count);
439         *v = (const char **)tmpalloc(count*sizeof(const char *));
440         for(i=0; i<count; ++i)
441                 packet_read_string(pkt, *v+i);
442 }