diff options
author | Gary E. Miller <gem@rellim.com> | 2018-07-14 12:17:35 -0700 |
---|---|---|
committer | Gary E. Miller <gem@rellim.com> | 2018-07-14 12:17:35 -0700 |
commit | 6bba8b329fc7687b15863d30471d5af402467802 (patch) | |
tree | 10975c312ee76bf58c4f66b6997e07c4f5e5e4c3 /libgps_sock.c | |
parent | 692427a17aeb54d69826def759cc1f1da605ba33 (diff) | |
download | gpsd-6bba8b329fc7687b15863d30471d5af402467802.tar.gz |
gps_read(): fix some nasty buffer overruns and corruptions.
Now pass an optional message buffer to gps_read(). Finally
the JSON display in cgps works.
Thanks to Virgin Orbit for their support fixing this bug.
Diffstat (limited to 'libgps_sock.c')
-rw-r--r-- | libgps_sock.c | 57 |
1 files changed, 39 insertions, 18 deletions
diff --git a/libgps_sock.c b/libgps_sock.c index c4303da5..63635234 100644 --- a/libgps_sock.c +++ b/libgps_sock.c @@ -178,23 +178,27 @@ int gps_sock_close(struct gps_data_t *gpsdata) #endif } -int gps_sock_read(struct gps_data_t *gpsdata) +int gps_sock_read(struct gps_data_t *gpsdata, char *message, int message_len) /* wait for and read data being streamed from the daemon */ { char *eol; ssize_t response_length; int status = -1; + errno = 0; gpsdata->set &= ~PACKET_SET; + + /* scan to find end of message (\n), or end of buffer */ for (eol = PRIVATE(gpsdata)->buffer; - *eol != '\n' && eol < PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting; eol++) - continue; - if (*eol != '\n') - eol = NULL; + eol < (PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting); + eol++) { + if ('\n' == *eol) + break; + } - errno = 0; + if (*eol != '\n') { + /* no full message found, try to fill buffer */ - if (eol == NULL) { #ifndef USE_QT /* read data: return -1 if no data waiting or buffered, 0 otherwise */ status = (int)recv(gpsdata->gps_fd, @@ -210,11 +214,13 @@ int gps_sock_read(struct gps_data_t *gpsdata) #ifdef HAVE_WINSOCK2_H int wserr = WSAGetLastError(); #endif /* HAVE_WINSOCK2_H */ + /* if we just received data from the socket, it's in the buffer */ if (status > -1) PRIVATE(gpsdata)->waiting += status; - /* buffer is empty - implies no data was read */ + if (PRIVATE(gpsdata)->waiting == 0) { + /* buffer is empty - implies no data was read */ /* * If we received 0 bytes, other side of socket is closing. * Return -1 as end-of-data indication. @@ -237,23 +243,37 @@ int gps_sock_read(struct gps_data_t *gpsdata) else return -1; } - /* there's buffered data waiting to be returned */ + + /* there's new buffered data waiting, check for full message */ for (eol = PRIVATE(gpsdata)->buffer; - *eol != '\n' && eol < PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting; eol++) - continue; + eol < (PRIVATE(gpsdata)->buffer + PRIVATE(gpsdata)->waiting); + eol++) { + if ('\n' == *eol) + break; + } if (*eol != '\n') - eol = NULL; - if (eol == NULL) + /* still no full message, give up for now */ return 0; } - assert(eol != NULL); + /* eol now points to trailing \n in a full message */ *eol = '\0'; - response_length = eol - PRIVATE(gpsdata)->buffer + 1; + if (NULL != message) { + strlcpy(message, PRIVATE(gpsdata)->buffer, message_len); + } gpsdata->online = timestamp(); + /* unpack the JSON message */ status = gps_unpack(PRIVATE(gpsdata)->buffer, gpsdata); - memmove(PRIVATE(gpsdata)->buffer, - PRIVATE(gpsdata)->buffer + response_length, PRIVATE(gpsdata)->waiting - response_length); + + response_length = eol - PRIVATE(gpsdata)->buffer + 1; + if (0 == (PRIVATE(gpsdata)->waiting - response_length)) { + /* no waiting data, clear the buffer, just in case */ + *PRIVATE(gpsdata)->buffer = '\0'; + } else { + memmove(PRIVATE(gpsdata)->buffer, + PRIVATE(gpsdata)->buffer + response_length, + PRIVATE(gpsdata)->waiting - response_length); + } PRIVATE(gpsdata)->waiting -= response_length; gpsdata->set |= PACKET_SET; @@ -292,6 +312,7 @@ int gps_unpack(char *buf, struct gps_data_t *gpsdata) const char *gps_sock_data(const struct gps_data_t *gpsdata) /* return the contents of the client data buffer */ { + /* no length data, so pretty useless... */ return PRIVATE(gpsdata)->buffer; } @@ -384,7 +405,7 @@ int gps_sock_mainloop(struct gps_data_t *gpsdata, int timeout, if (!gps_waiting(gpsdata, timeout)) { return -1; } else { - int status = gps_read(gpsdata); + int status = gps_read(gpsdata, NULL, 0); if (status == -1) return -1; |