Improve File I/O overflow detection in gdbserver (PR server/23198)
[deliverable/binutils-gdb.git] / gdb / gdbserver / hostio.c
CommitLineData
a6b151f1 1/* Host file transfer support for gdbserver.
e2882c85 2 Copyright (C) 2007-2018 Free Software Foundation, Inc.
a6b151f1
DJ
3
4 Contributed by CodeSourcery.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
32de4b9d 10 the Free Software Foundation; either version 3 of the License, or
a6b151f1
DJ
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
32de4b9d 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
a6b151f1
DJ
20
21#include "server.h"
22#include "gdb/fileio.h"
533b0600 23#include "hostio.h"
a6b151f1 24
a6b151f1
DJ
25#include <fcntl.h>
26#include <limits.h>
27#include <unistd.h>
aa9e327f
GB
28#include <sys/types.h>
29#include <sys/stat.h>
7823a941 30#include "fileio.h"
a6b151f1
DJ
31
32extern int remote_debug;
33
34struct fd_list
35{
36 int fd;
37 struct fd_list *next;
38};
39
40static struct fd_list *open_fds;
41
42static int
43safe_fromhex (char a, int *nibble)
44{
45 if (a >= '0' && a <= '9')
46 *nibble = a - '0';
47 else if (a >= 'a' && a <= 'f')
48 *nibble = a - 'a' + 10;
49 else if (a >= 'A' && a <= 'F')
50 *nibble = a - 'A' + 10;
51 else
52 return -1;
53
54 return 0;
55}
56
d5749ee7
PA
57/* Filenames are hex encoded, so the maximum we can handle is half the
58 packet buffer size. Cap to PATH_MAX, if it is shorter. */
59#if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1))
60# define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1)
61#else
62# define HOSTIO_PATH_MAX PATH_MAX
63#endif
64
a6b151f1
DJ
65static int
66require_filename (char **pp, char *filename)
67{
68 int count;
69 char *p;
70
71 p = *pp;
72 count = 0;
73
74 while (*p && *p != ',')
75 {
76 int nib1, nib2;
77
78 /* Don't allow overflow. */
d5749ee7 79 if (count >= HOSTIO_PATH_MAX - 1)
a6b151f1
DJ
80 return -1;
81
82 if (safe_fromhex (p[0], &nib1)
83 || safe_fromhex (p[1], &nib2))
84 return -1;
85
86 filename[count++] = nib1 * 16 + nib2;
87 p += 2;
88 }
89
90 filename[count] = '\0';
91 *pp = p;
92 return 0;
93}
94
95static int
96require_int (char **pp, int *value)
97{
98 char *p;
81e25b7c 99 int count, firstdigit;
a6b151f1
DJ
100
101 p = *pp;
102 *value = 0;
103 count = 0;
81e25b7c 104 firstdigit = -1;
a6b151f1
DJ
105
106 while (*p && *p != ',')
107 {
108 int nib;
109
81e25b7c 110 if (safe_fromhex (p[0], &nib))
a6b151f1
DJ
111 return -1;
112
81e25b7c
EK
113 if (firstdigit == -1)
114 firstdigit = nib;
115
116 /* Don't allow overflow. */
117 if (count >= 8 || (count == 7 && firstdigit >= 0x8))
a6b151f1 118 return -1;
81e25b7c 119
a6b151f1
DJ
120 *value = *value * 16 + nib;
121 p++;
122 count++;
123 }
124
125 *pp = p;
126 return 0;
127}
128
129static int
130require_data (char *p, int p_len, char **data, int *data_len)
131{
132 int input_index, output_index, escaped;
133
224c3ddb 134 *data = (char *) xmalloc (p_len);
a6b151f1
DJ
135
136 output_index = 0;
137 escaped = 0;
138 for (input_index = 0; input_index < p_len; input_index++)
139 {
140 char b = p[input_index];
141
142 if (escaped)
143 {
144 (*data)[output_index++] = b ^ 0x20;
145 escaped = 0;
146 }
147 else if (b == '}')
148 escaped = 1;
149 else
150 (*data)[output_index++] = b;
151 }
152
153 if (escaped)
9130f83e 154 {
8040bd49 155 free (*data);
9130f83e
MS
156 return -1;
157 }
a6b151f1
DJ
158
159 *data_len = output_index;
160 return 0;
161}
162
163static int
164require_comma (char **pp)
165{
166 if (**pp == ',')
167 {
168 (*pp)++;
169 return 0;
170 }
171 else
172 return -1;
173}
174
175static int
176require_end (char *p)
177{
178 if (*p == '\0')
179 return 0;
180 else
181 return -1;
182}
183
184static int
185require_valid_fd (int fd)
186{
187 struct fd_list *fd_ptr;
188
189 for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
190 if (fd_ptr->fd == fd)
191 return 0;
192
193 return -1;
194}
195
59a016f0
PA
196/* Fill in own_buf with the last hostio error packet, however it
197 suitable for the target. */
a6b151f1 198static void
59a016f0 199hostio_error (char *own_buf)
a6b151f1 200{
59a016f0 201 the_target->hostio_last_error (own_buf);
a6b151f1
DJ
202}
203
204static void
205hostio_packet_error (char *own_buf)
206{
59a016f0 207 sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
a6b151f1
DJ
208}
209
210static void
211hostio_reply (char *own_buf, int result)
212{
213 sprintf (own_buf, "F%x", result);
214}
215
216static int
217hostio_reply_with_data (char *own_buf, char *buffer, int len,
218 int *new_packet_len)
219{
220 int input_index, output_index, out_maxlen;
221
222 sprintf (own_buf, "F%x;", len);
223 output_index = strlen (own_buf);
224
225 out_maxlen = PBUFSIZ;
226
227 for (input_index = 0; input_index < len; input_index++)
228 {
229 char b = buffer[input_index];
230
231 if (b == '$' || b == '#' || b == '}' || b == '*')
232 {
233 /* These must be escaped. */
234 if (output_index + 2 > out_maxlen)
235 break;
236 own_buf[output_index++] = '}';
237 own_buf[output_index++] = b ^ 0x20;
238 }
239 else
240 {
241 if (output_index + 1 > out_maxlen)
242 break;
243 own_buf[output_index++] = b;
244 }
245 }
246
247 *new_packet_len = output_index;
248 return input_index;
249}
250
14d2069a
GB
251/* Process ID of inferior whose filesystem hostio functions
252 that take FILENAME arguments will use. Zero means to use
253 our own filesystem. */
254
255static int hostio_fs_pid;
256
257/* See hostio.h. */
258
259void
260hostio_handle_new_gdb_connection (void)
261{
262 hostio_fs_pid = 0;
263}
264
265/* Handle a "vFile:setfs:" packet. */
266
267static void
268handle_setfs (char *own_buf)
269{
270 char *p;
271 int pid;
272
273 /* If the target doesn't have any of the in-filesystem-of methods
274 then there's no point in GDB sending "vFile:setfs:" packets. We
275 reply with an empty packet (i.e. we pretend we don't understand
276 "vFile:setfs:") and that should stop GDB sending any more. */
277 if (the_target->multifs_open == NULL
278 && the_target->multifs_unlink == NULL
279 && the_target->multifs_readlink == NULL)
280 {
281 own_buf[0] = '\0';
282 return;
283 }
284
285 p = own_buf + strlen ("vFile:setfs:");
286
287 if (require_int (&p, &pid)
288 || pid < 0
289 || require_end (p))
290 {
291 hostio_packet_error (own_buf);
292 return;
293 }
294
295 hostio_fs_pid = pid;
296
297 hostio_reply (own_buf, 0);
298}
299
a6b151f1
DJ
300static void
301handle_open (char *own_buf)
302{
d5749ee7 303 char filename[HOSTIO_PATH_MAX];
a6b151f1 304 char *p;
3ac2e371
GB
305 int fileio_flags, fileio_mode, flags, fd;
306 mode_t mode;
a6b151f1
DJ
307 struct fd_list *new_fd;
308
309 p = own_buf + strlen ("vFile:open:");
310
311 if (require_filename (&p, filename)
312 || require_comma (&p)
313 || require_int (&p, &fileio_flags)
314 || require_comma (&p)
3ac2e371 315 || require_int (&p, &fileio_mode)
a6b151f1 316 || require_end (p)
3ac2e371
GB
317 || fileio_to_host_openflags (fileio_flags, &flags)
318 || fileio_to_host_mode (fileio_mode, &mode))
a6b151f1
DJ
319 {
320 hostio_packet_error (own_buf);
321 return;
322 }
323
324 /* We do not need to convert MODE, since the fileio protocol
325 uses the standard values. */
14d2069a
GB
326 if (hostio_fs_pid != 0 && the_target->multifs_open != NULL)
327 fd = the_target->multifs_open (hostio_fs_pid, filename,
328 flags, mode);
329 else
330 fd = open (filename, flags, mode);
a6b151f1
DJ
331
332 if (fd == -1)
333 {
59a016f0 334 hostio_error (own_buf);
a6b151f1
DJ
335 return;
336 }
337
338 /* Record the new file descriptor. */
8d749320 339 new_fd = XNEW (struct fd_list);
a6b151f1
DJ
340 new_fd->fd = fd;
341 new_fd->next = open_fds;
342 open_fds = new_fd;
343
344 hostio_reply (own_buf, fd);
345}
346
347static void
348handle_pread (char *own_buf, int *new_packet_len)
349{
350 int fd, ret, len, offset, bytes_sent;
351 char *p, *data;
45face3b 352 static int max_reply_size = -1;
a6b151f1
DJ
353
354 p = own_buf + strlen ("vFile:pread:");
355
356 if (require_int (&p, &fd)
357 || require_comma (&p)
358 || require_valid_fd (fd)
359 || require_int (&p, &len)
360 || require_comma (&p)
361 || require_int (&p, &offset)
362 || require_end (p))
363 {
364 hostio_packet_error (own_buf);
365 return;
366 }
367
45face3b
GB
368 /* Do not attempt to read more than the maximum number of bytes
369 hostio_reply_with_data can fit in a packet. We may still read
370 too much because of escaping, but this is handled below. */
371 if (max_reply_size == -1)
372 {
373 sprintf (own_buf, "F%x;", PBUFSIZ);
374 max_reply_size = PBUFSIZ - strlen (own_buf);
375 }
376 if (len > max_reply_size)
377 len = max_reply_size;
378
224c3ddb 379 data = (char *) xmalloc (len);
4e799345 380#ifdef HAVE_PREAD
a6b151f1 381 ret = pread (fd, data, len, offset);
4e799345 382#else
7c3270ae 383 ret = -1;
4e799345 384#endif
7c3270ae
UW
385 /* If we have no pread or it failed for this file, use lseek/read. */
386 if (ret == -1)
387 {
388 ret = lseek (fd, offset, SEEK_SET);
389 if (ret != -1)
390 ret = read (fd, data, len);
391 }
a6b151f1
DJ
392
393 if (ret == -1)
394 {
59a016f0 395 hostio_error (own_buf);
a6b151f1
DJ
396 free (data);
397 return;
398 }
399
400 bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
401
402 /* If we were using read, and the data did not all fit in the reply,
403 we would have to back up using lseek here. With pread it does
404 not matter. But we still have a problem; the return value in the
405 packet might be wrong, so we must fix it. This time it will
406 definitely fit. */
407 if (bytes_sent < ret)
408 bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
409 new_packet_len);
410
411 free (data);
412}
413
414static void
415handle_pwrite (char *own_buf, int packet_len)
416{
417 int fd, ret, len, offset;
418 char *p, *data;
419
420 p = own_buf + strlen ("vFile:pwrite:");
421
422 if (require_int (&p, &fd)
423 || require_comma (&p)
424 || require_valid_fd (fd)
425 || require_int (&p, &offset)
426 || require_comma (&p)
427 || require_data (p, packet_len - (p - own_buf), &data, &len))
428 {
429 hostio_packet_error (own_buf);
430 return;
431 }
432
4e799345 433#ifdef HAVE_PWRITE
a6b151f1 434 ret = pwrite (fd, data, len, offset);
4e799345 435#else
7c3270ae 436 ret = -1;
4e799345 437#endif
7c3270ae
UW
438 /* If we have no pwrite or it failed for this file, use lseek/write. */
439 if (ret == -1)
440 {
441 ret = lseek (fd, offset, SEEK_SET);
442 if (ret != -1)
443 ret = write (fd, data, len);
444 }
a6b151f1
DJ
445
446 if (ret == -1)
447 {
59a016f0 448 hostio_error (own_buf);
a6b151f1
DJ
449 free (data);
450 return;
451 }
452
453 hostio_reply (own_buf, ret);
454 free (data);
455}
456
aa9e327f
GB
457static void
458handle_fstat (char *own_buf, int *new_packet_len)
459{
460 int fd, bytes_sent;
461 char *p;
462 struct stat st;
463 struct fio_stat fst;
464
465 p = own_buf + strlen ("vFile:fstat:");
466
467 if (require_int (&p, &fd)
468 || require_valid_fd (fd)
469 || require_end (p))
470 {
471 hostio_packet_error (own_buf);
472 return;
473 }
474
475 if (fstat (fd, &st) == -1)
476 {
477 hostio_error (own_buf);
478 return;
479 }
480
7823a941 481 host_to_fileio_stat (&st, &fst);
aa9e327f
GB
482
483 bytes_sent = hostio_reply_with_data (own_buf,
484 (char *) &fst, sizeof (fst),
485 new_packet_len);
486
487 /* If the response does not fit into a single packet, do not attempt
488 to return a partial response, but simply fail. */
489 if (bytes_sent < sizeof (fst))
490 write_enn (own_buf);
491}
492
a6b151f1
DJ
493static void
494handle_close (char *own_buf)
495{
496 int fd, ret;
497 char *p;
498 struct fd_list **open_fd_p, *old_fd;
499
500 p = own_buf + strlen ("vFile:close:");
501
502 if (require_int (&p, &fd)
503 || require_valid_fd (fd)
504 || require_end (p))
505 {
506 hostio_packet_error (own_buf);
507 return;
508 }
509
510 ret = close (fd);
511
512 if (ret == -1)
513 {
59a016f0 514 hostio_error (own_buf);
a6b151f1
DJ
515 return;
516 }
517
518 open_fd_p = &open_fds;
588eebee
MS
519 /* We know that fd is in the list, thanks to require_valid_fd. */
520 while ((*open_fd_p)->fd != fd)
a6b151f1
DJ
521 open_fd_p = &(*open_fd_p)->next;
522
523 old_fd = *open_fd_p;
524 *open_fd_p = (*open_fd_p)->next;
525 free (old_fd);
526
527 hostio_reply (own_buf, ret);
528}
529
530static void
531handle_unlink (char *own_buf)
532{
d5749ee7 533 char filename[HOSTIO_PATH_MAX];
a6b151f1
DJ
534 char *p;
535 int ret;
536
537 p = own_buf + strlen ("vFile:unlink:");
538
539 if (require_filename (&p, filename)
540 || require_end (p))
541 {
542 hostio_packet_error (own_buf);
543 return;
544 }
545
14d2069a
GB
546 if (hostio_fs_pid != 0 && the_target->multifs_unlink != NULL)
547 ret = the_target->multifs_unlink (hostio_fs_pid, filename);
548 else
549 ret = unlink (filename);
a6b151f1
DJ
550
551 if (ret == -1)
552 {
59a016f0 553 hostio_error (own_buf);
a6b151f1
DJ
554 return;
555 }
556
557 hostio_reply (own_buf, ret);
558}
559
b9e7b9c3
UW
560static void
561handle_readlink (char *own_buf, int *new_packet_len)
562{
d5749ee7 563 char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
b9e7b9c3
UW
564 char *p;
565 int ret, bytes_sent;
566
567 p = own_buf + strlen ("vFile:readlink:");
568
569 if (require_filename (&p, filename)
570 || require_end (p))
571 {
572 hostio_packet_error (own_buf);
573 return;
574 }
575
14d2069a
GB
576 if (hostio_fs_pid != 0 && the_target->multifs_readlink != NULL)
577 ret = the_target->multifs_readlink (hostio_fs_pid, filename,
578 linkname,
579 sizeof (linkname) - 1);
580 else
581 ret = readlink (filename, linkname, sizeof (linkname) - 1);
582
b9e7b9c3
UW
583 if (ret == -1)
584 {
585 hostio_error (own_buf);
586 return;
587 }
588
589 bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
590
591 /* If the response does not fit into a single packet, do not attempt
592 to return a partial response, but simply fail. */
593 if (bytes_sent < ret)
594 sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
595}
596
a6b151f1
DJ
597/* Handle all the 'F' file transfer packets. */
598
599int
600handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
601{
61012eef 602 if (startswith (own_buf, "vFile:open:"))
a6b151f1 603 handle_open (own_buf);
61012eef 604 else if (startswith (own_buf, "vFile:pread:"))
a6b151f1 605 handle_pread (own_buf, new_packet_len);
61012eef 606 else if (startswith (own_buf, "vFile:pwrite:"))
a6b151f1 607 handle_pwrite (own_buf, packet_len);
aa9e327f
GB
608 else if (startswith (own_buf, "vFile:fstat:"))
609 handle_fstat (own_buf, new_packet_len);
61012eef 610 else if (startswith (own_buf, "vFile:close:"))
a6b151f1 611 handle_close (own_buf);
61012eef 612 else if (startswith (own_buf, "vFile:unlink:"))
a6b151f1 613 handle_unlink (own_buf);
61012eef 614 else if (startswith (own_buf, "vFile:readlink:"))
b9e7b9c3 615 handle_readlink (own_buf, new_packet_len);
14d2069a
GB
616 else if (startswith (own_buf, "vFile:setfs:"))
617 handle_setfs (own_buf);
a6b151f1
DJ
618 else
619 return 0;
620
621 return 1;
622}
This page took 0.880228 seconds and 4 git commands to generate.