From 1d275900eb3316312b673c86cf71f4b1c739c452 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 12 May 2016 14:17:35 +0200 Subject: [PATCH] Prevent Buffer Overflow and Added FlashStringHelper for text and binary (#26) * Prevent buffer overflow on received data * pass to 7 char to avoid save to flash by SDK * return _contentLength, avoid array reparse to know len * Added FlashStringHelper for text and binary * Added FlashStringHelper also to AsyncWebSocketClient * Added PROGMEM doc * Corrected binary was sending PSTR as text, addded len * Server calls client method and code as asked @me-no-dev * server calls client method and code as asked by @me-no-dev * Changed Code presentation --- README.md | 44 ++++++++++------ .../ESP32_AsyncFSBrowser.ino | 38 ++++++++------ .../ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino | 40 +++++++++------ src/AsyncJson.h | 3 +- src/AsyncWebSocket.cpp | 50 +++++++++++++++++++ src/AsyncWebSocket.h | 6 +++ 6 files changed, 134 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 0390a54..ab1be91 100644 --- a/README.md +++ b/README.md @@ -464,36 +464,48 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp ### Methods for sending data to a socket client ```cpp + + + //Server methods AsyncWebSocket ws("/ws"); //printf to a client -ws.printf([client id], [arguments...]) +ws.printf([client id], [arguments...]); //printf to all clients -ws.printfAll([arguments...]) +ws.printfAll([arguments...]); //send text to a client -ws.text([client id], [(char*)text]) -ws.text([client id], [text], [len]) +ws.text([client id], [(char*)text]); +ws.text([client id], [text], [len]); +const char flash_text[] PROGMEM = "Text to send" +ws.text([client id], [PSTR("text")]); +ws.text([client id], [FPSTR(flash_text)]); //send text to all clients -ws.textAll([(char*text]) -ws.textAll([text], [len]) +ws.textAll([(char*text]); +ws.textAll([text], [len]); //send binary to a client -ws.binary([client id], [(char*)binary]) -ws.binary([client id], [binary], [len]) +ws.binary([client id], [(char*)binary]); +ws.binary([client id], [binary], [len]); +const uint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 }; +ws.binary([client id], [flash_binary], [len]); //send binary to all clients -ws.binaryAll([(char*binary]) -ws.binaryAll([binary], [len]) +ws.binaryAll([(char*binary]); +ws.binaryAll([binary], [len]); //client methods AsyncWebSocketClient * client; //printf to a client -client->printf([arguments...]) +client->printf([arguments...]); //send text to a client -client->text([(char*)text]) -client->text([text], [len]) +client->text([(char*)text]); +client->text([text], [len]); +const char flash_text[] PROGMEM = "Text to send"; +client->text([PSTR("text")]); +client->text([FPSTR(flash_text)]); //send binary to a client -client->binary([(char*)binary]) -client->binary([binary], [len]) - +client->binary([(char*)binary]); +client->binary([binary], [len]); +const uint8_t flash_binary[] PROGMEM = { 0x01, 0x02, 0x03, 0x04 }; +client->binary([flash_binary], [len]); ``` diff --git a/examples/ESP32_AsyncFSBrowser/ESP32_AsyncFSBrowser.ino b/examples/ESP32_AsyncFSBrowser/ESP32_AsyncFSBrowser.ino index 4726664..614ba69 100644 --- a/examples/ESP32_AsyncFSBrowser/ESP32_AsyncFSBrowser.ino +++ b/examples/ESP32_AsyncFSBrowser/ESP32_AsyncFSBrowser.ino @@ -125,18 +125,22 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp os_printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); } else if(type == WS_EVT_DATA){ AwsFrameInfo * info = (AwsFrameInfo*)arg; + String msg = ""; if(info->final && info->index == 0 && info->len == len){ //the whole message is in a single frame and we got all of it's data os_printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); if(info->opcode == WS_TEXT){ - data[len] = 0; - os_printf("%s\n", (char*)data); - } else { - for(size_t i=0; i < info->len; i++){ - os_printf("%02x ", data[i]); + for(size_t i=0; i < info->len; i++) { + msg += (char) data[i]; + } + } else { + char buff[3]; + for(size_t i=0; i < info->len; i++) { + sprintf(buff, "%02x ", (uint8_t) data[i]); + msg += buff ; } - os_printf("\n"); } + os_printf("%s\n",msg.c_str()); if(info->opcode == WS_TEXT) client->text("I got your text message"); else @@ -150,15 +154,19 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp } os_printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len); - if(info->message_opcode == WS_TEXT){ - data[len] = 0; - os_printf("%s\n", (char*)data); - } else { - for(size_t i=0; i < len; i++){ - os_printf("%02x ", data[i]); + if(info->opcode == WS_TEXT){ + for(size_t i=0; i < info->len; i++) { + msg += (char) data[i]; + } + } else { + char buff[3]; + for(size_t i=0; i < info->len; i++) { + sprintf(buff, "%02x ", (uint8_t) data[i]); + msg += buff ; } - os_printf("\n"); } + os_printf("%s\n",msg.c_str()); + if((info->index + len) == info->len){ os_printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); @@ -174,8 +182,8 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp } } -const char* ssid = "**********"; -const char* password = "************"; +const char* ssid = "*******"; +const char* password = "*******"; const char* http_username = "admin"; const char* http_password = "admin"; diff --git a/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino b/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino index 4470241..ba0ba6b 100644 --- a/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino +++ b/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino @@ -128,18 +128,24 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp os_printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); } else if(type == WS_EVT_DATA){ AwsFrameInfo * info = (AwsFrameInfo*)arg; + String msg = ""; if(info->final && info->index == 0 && info->len == len){ //the whole message is in a single frame and we got all of it's data os_printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); + if(info->opcode == WS_TEXT){ - data[len] = 0; - os_printf("%s\n", (char*)data); - } else { - for(size_t i=0; i < info->len; i++){ - os_printf("%02x ", data[i]); + for(size_t i=0; i < info->len; i++) { + msg += (char) data[i]; + } + } else { + char buff[3]; + for(size_t i=0; i < info->len; i++) { + sprintf(buff, "%02x ", (uint8_t) data[i]); + msg += buff ; } - os_printf("\n"); } + os_printf("%s\n",msg.c_str()); + if(info->opcode == WS_TEXT) client->text("I got your text message"); else @@ -153,15 +159,19 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp } os_printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len); - if(info->message_opcode == WS_TEXT){ - data[len] = 0; - os_printf("%s\n", (char*)data); - } else { - for(size_t i=0; i < len; i++){ - os_printf("%02x ", data[i]); + + if(info->opcode == WS_TEXT){ + for(size_t i=0; i < info->len; i++) { + msg += (char) data[i]; + } + } else { + char buff[3]; + for(size_t i=0; i < info->len; i++) { + sprintf(buff, "%02x ", (uint8_t) data[i]); + msg += buff ; } - os_printf("\n"); } + os_printf("%s\n",msg.c_str()); if((info->index + len) == info->len){ os_printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); @@ -178,8 +188,8 @@ void onEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp } -const char* ssid = "**********"; -const char* password = "************"; +const char* ssid = "*******"; +const char* password = "*******"; const char* http_username = "admin"; const char* http_password = "admin"; diff --git a/src/AsyncJson.h b/src/AsyncJson.h index 633f00c..4ff1ff6 100644 --- a/src/AsyncJson.h +++ b/src/AsyncJson.h @@ -66,9 +66,10 @@ class AsyncJsonResponse: public AsyncAbstractResponse { ~AsyncJsonResponse() {} JsonVariant & getRoot() { return _root; } bool _sourceValid() { return _isValid; } - void setLength() { + size_t setLength() { _contentLength = _root.measureLength(); if (_contentLength) { _isValid = true; } + return _contentLength; } size_t _fillBuffer(uint8_t *data, size_t len){ diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp index 8754bae..469ceef 100644 --- a/src/AsyncWebSocket.cpp +++ b/src/AsyncWebSocket.cpp @@ -504,6 +504,21 @@ void AsyncWebSocketClient::text(char * message){ void AsyncWebSocketClient::text(String &message){ text(message.c_str(), message.length()); } +void AsyncWebSocketClient::text(const __FlashStringHelper *data){ + PGM_P p = reinterpret_cast(data); + size_t n = 0; + while (1) { + if (pgm_read_byte(p+n) == 0) break; + n += 1; + } + char * message = (char*) malloc(n+1); + if(message){ + for(size_t b=0; b(data); + char * message = (char*) malloc(len); + if(message){ + for(size_t b=0; btext(message); +} void AsyncWebSocket::textAll(const char * message){ textAll(message, strlen(message)); } @@ -740,6 +769,14 @@ void AsyncWebSocket::textAll(char * message){ void AsyncWebSocket::textAll(String &message){ textAll(message.c_str(), message.length()); } +void AsyncWebSocket::textAll(const __FlashStringHelper *message){ + AsyncWebSocketClient * c = _clients; + while(c != NULL){ + if(c->status() == WS_CONNECTED) + c->text(message); + c = c->next; + } +} void AsyncWebSocket::binary(uint32_t id, const char * message){ binary(id, message, strlen(message)); } @@ -752,6 +789,11 @@ void AsyncWebSocket::binary(uint32_t id, char * message){ void AsyncWebSocket::binary(uint32_t id, String &message){ binary(id, message.c_str(), message.length()); } +void AsyncWebSocket::binary(uint32_t id, const __FlashStringHelper *message, size_t len){ + AsyncWebSocketClient * c = client(id); + if(c != NULL) + c-> binary(message, len); +} void AsyncWebSocket::binaryAll(const char * message){ binaryAll(message, strlen(message)); } @@ -764,6 +806,14 @@ void AsyncWebSocket::binaryAll(char * message){ void AsyncWebSocket::binaryAll(String &message){ binaryAll(message.c_str(), message.length()); } +void AsyncWebSocket::binaryAll(const __FlashStringHelper *message, size_t len){ + AsyncWebSocketClient * c = _clients; + while(c != NULL){ + if(c->status() == WS_CONNECTED) + c-> binary(message, len); + c = c->next; + } + } const char * WS_STR_CONNECTION = "Connection"; const char * WS_STR_UPGRADE = "Upgrade"; diff --git a/src/AsyncWebSocket.h b/src/AsyncWebSocket.h index 2b59d89..42d8677 100644 --- a/src/AsyncWebSocket.h +++ b/src/AsyncWebSocket.h @@ -106,12 +106,14 @@ class AsyncWebSocketClient { void text(uint8_t * message, size_t len); void text(char * message); void text(String &message); + void text(const __FlashStringHelper *data); void binary(const char * message, size_t len); void binary(const char * message); void binary(uint8_t * message, size_t len); void binary(char * message); void binary(String &message); + void binary(const __FlashStringHelper *data, size_t len); //system callbacks (do not call) void _onAck(size_t len, uint32_t time); @@ -151,24 +153,28 @@ class AsyncWebSocket: public AsyncWebHandler { void text(uint32_t id, uint8_t * message, size_t len); void text(uint32_t id, char * message); void text(uint32_t id, String &message); + void text(uint32_t id, const __FlashStringHelper *message); void textAll(const char * message, size_t len); void textAll(const char * message); void textAll(uint8_t * message, size_t len); void textAll(char * message); void textAll(String &message); + void textAll(const __FlashStringHelper *message); void binary(uint32_t id, const char * message, size_t len); void binary(uint32_t id, const char * message); void binary(uint32_t id, uint8_t * message, size_t len); void binary(uint32_t id, char * message); void binary(uint32_t id, String &message); + void binary(uint32_t id, const __FlashStringHelper *message, size_t len); void binaryAll(const char * message, size_t len); void binaryAll(const char * message); void binaryAll(uint8_t * message, size_t len); void binaryAll(char * message); void binaryAll(String &message); + void binaryAll(const __FlashStringHelper *message, size_t len); void message(uint32_t id, AsyncWebSocketMessage *message); void messageAll(AsyncWebSocketMessage *message);