HTTPD bug fix which is caused by stack overflow.

Dependents:   mbed_controller_demo

Fork of HTTPD by Suga koubou

Original HTTPD implementation of Suga koubou is great but has some bug inside unfortunately. The most critical bug was accessing buffer with the index of out of range like following.

problematic code

char buf[256];

n = httpd->_state[id].client->receive(buf, sizeof(buf));
buf[n] =0;

With above code, it could set buf[256] = 0 when more that 255 data is received. Setting buf[256] causes some other area of memory is corrupted so that system can be predictive status since than.

bug fixed code

n = httpd->_state[id].client->receive(buf, sizeof(buf)-1);
buf[n] =0;
Committer:
hillkim7
Date:
Fri Apr 10 09:04:38 2015 +0000
Revision:
2:584ce0a1a76e
Parent:
1:a4c4bd58dd3b
Fix critical bug cause by accessing buffer with index of out of range.; Set reasonable stack size for server task.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
okini3939 0:d18dff347122 1 /* Copyright (C) 2013 Hiroshi Suga, MIT License
okini3939 0:d18dff347122 2 *
okini3939 0:d18dff347122 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
okini3939 0:d18dff347122 4 * and associated documentation files (the "Software"), to deal in the Software without restriction,
okini3939 0:d18dff347122 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
okini3939 0:d18dff347122 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
okini3939 0:d18dff347122 7 * furnished to do so, subject to the following conditions:
okini3939 0:d18dff347122 8 *
okini3939 0:d18dff347122 9 * The above copyright notice and this permission notice shall be included in all copies or
okini3939 0:d18dff347122 10 * substantial portions of the Software.
okini3939 0:d18dff347122 11 *
okini3939 0:d18dff347122 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
okini3939 0:d18dff347122 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
okini3939 0:d18dff347122 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
okini3939 0:d18dff347122 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
okini3939 0:d18dff347122 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
okini3939 0:d18dff347122 17 */
okini3939 0:d18dff347122 18
okini3939 0:d18dff347122 19 #include "HTTPD.h"
okini3939 0:d18dff347122 20
hillkim7 2:584ce0a1a76e 21 /*
hillkim7 2:584ce0a1a76e 22 // There was hald fault error of HTTPD with Seeed Arch Max platform
hillkim7 2:584ce0a1a76e 23 // because of stack overwritten.
hillkim7 2:584ce0a1a76e 24 // According to the Callgraph report of Keil MDK 4.1,
hillkim7 2:584ce0a1a76e 25 // the Max Depth is 424 bytes.
hillkim7 2:584ce0a1a76e 26 HTTPD::daemon(const void*) (Thumb, 110 bytes, Stack size 0 bytes, httpd.o(.text))
hillkim7 1:a4c4bd58dd3b 27
hillkim7 2:584ce0a1a76e 28 [Stack]
hillkim7 2:584ce0a1a76e 29
hillkim7 2:584ce0a1a76e 30 Max Depth = 424 + Unknown Stack Size
hillkim7 2:584ce0a1a76e 31 Call Chain = HTTPD::daemon(const void*) <-> TCPSocketServer::accept(TCPSocketConnection&) <->
hillkim7 2:584ce0a1a76e 32 Socket::wait_readable(TimeInterval&) <-> Socket::select(timeval*, bool, bool) <->
hillkim7 2:584ce0a1a76e 33 lwip_select <-> lwip_selscan <-> sys_arch_unprotect <-> error <-> exit (Cycle)
hillkim7 2:584ce0a1a76e 34 */
hillkim7 1:a4c4bd58dd3b 35 #define DAEMON_STACK_SIZE 512
hillkim7 1:a4c4bd58dd3b 36
okini3939 0:d18dff347122 37 HTTPD * HTTPD::_inst;
okini3939 0:d18dff347122 38
okini3939 0:d18dff347122 39 HTTPD::HTTPD () {
okini3939 0:d18dff347122 40 _inst = this;
okini3939 0:d18dff347122 41 memset(_state, 0, sizeof(_state));
okini3939 0:d18dff347122 42 _handler_count = 0;
okini3939 0:d18dff347122 43 }
okini3939 0:d18dff347122 44
okini3939 0:d18dff347122 45 int HTTPD::start (int port) {
okini3939 0:d18dff347122 46 int i;
okini3939 0:d18dff347122 47
okini3939 0:d18dff347122 48 for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
okini3939 0:d18dff347122 49 _state[i].buf = new CircBuffer<char>(HTTPD_BUF_SIZE);
okini3939 0:d18dff347122 50 _state[i].thread = new Thread(child, (void*)i, osPriorityNormal, HTTPD_STACK_SIZE);
okini3939 0:d18dff347122 51 _state[i].client = new TCPSocketConnection;
okini3939 0:d18dff347122 52 }
okini3939 0:d18dff347122 53 #ifdef HTTPD_ENABLE_CLOSER
okini3939 0:d18dff347122 54 _state[HTTPD_MAX_CLIENTS].thread = new Thread(closer, (void*)HTTPD_MAX_CLIENTS, osPriorityNormal, 128);
okini3939 0:d18dff347122 55 _state[HTTPD_MAX_CLIENTS].client = new TCPSocketConnection;
okini3939 0:d18dff347122 56 #endif
okini3939 0:d18dff347122 57
okini3939 0:d18dff347122 58 _server.bind(port);
okini3939 0:d18dff347122 59 _server.listen();
hillkim7 1:a4c4bd58dd3b 60 _daemon = new Thread(daemon, NULL, osPriorityNormal, DAEMON_STACK_SIZE);
okini3939 0:d18dff347122 61 return 0;
okini3939 0:d18dff347122 62 }
okini3939 0:d18dff347122 63
okini3939 0:d18dff347122 64 void HTTPD::daemon (void const *args) {
okini3939 0:d18dff347122 65 HTTPD *httpd = HTTPD::getInstance();
okini3939 0:d18dff347122 66 int i, t = 0;
okini3939 0:d18dff347122 67
okini3939 0:d18dff347122 68 INFO("Wait for new connection...\r\n");
okini3939 0:d18dff347122 69 for (;;) {
okini3939 0:d18dff347122 70 if (t >= 0) {
okini3939 0:d18dff347122 71 if (httpd->_server.accept(*httpd->_state[t].client) == 0) {
okini3939 0:d18dff347122 72 INFO("accept %d\r\n", t);
okini3939 0:d18dff347122 73 httpd->_state[t].thread->signal_set(1);
okini3939 0:d18dff347122 74 }
okini3939 0:d18dff347122 75 } else {
okini3939 0:d18dff347122 76 #ifdef HTTPD_ENABLE_CLOSER
okini3939 0:d18dff347122 77 if (httpd->_server.accept(*httpd->_state[HTTPD_MAX_CLIENTS].client) == 0) {
okini3939 0:d18dff347122 78 INFO("accept x\r\n");
okini3939 0:d18dff347122 79 httpd->_state[HTTPD_MAX_CLIENTS].thread->signal_set(1);
okini3939 0:d18dff347122 80 }
okini3939 0:d18dff347122 81 #endif
okini3939 0:d18dff347122 82 }
okini3939 0:d18dff347122 83
okini3939 0:d18dff347122 84 t = -1;
okini3939 0:d18dff347122 85 for (i = 0; i < HTTPD_MAX_CLIENTS; i ++) {
okini3939 0:d18dff347122 86 if (httpd->_state[i].thread->get_state() == Thread::WaitingAnd) {
okini3939 0:d18dff347122 87 if (t < 0) t = i; // next empty thread
okini3939 0:d18dff347122 88 }
okini3939 0:d18dff347122 89 }
okini3939 0:d18dff347122 90 }
okini3939 0:d18dff347122 91 }
okini3939 0:d18dff347122 92
okini3939 0:d18dff347122 93 void HTTPD::child (void const *arg) {
okini3939 0:d18dff347122 94 HTTPD *httpd = HTTPD::getInstance();
okini3939 0:d18dff347122 95 int id = (int)arg;
okini3939 0:d18dff347122 96 int i, n;
okini3939 0:d18dff347122 97 char buf[HTTPD_BUF_SIZE];
okini3939 0:d18dff347122 98
okini3939 0:d18dff347122 99 for (;;) {
okini3939 0:d18dff347122 100 Thread::signal_wait(1);
okini3939 0:d18dff347122 101
okini3939 0:d18dff347122 102 httpd->_state[id].mode = MODE_REQUEST;
okini3939 0:d18dff347122 103 httpd->_state[id].buf->flush();
okini3939 0:d18dff347122 104 httpd->_state[id].keepalive = 0;
okini3939 0:d18dff347122 105 INFO("Connection from %s\r\n", httpd->_state[id].client->get_address());
okini3939 0:d18dff347122 106 httpd->_state[id].client->set_blocking(false, HTTPD_TIMEOUT);
okini3939 0:d18dff347122 107 for (;;) {
okini3939 0:d18dff347122 108 if (! httpd->_state[id].client->is_connected()) break;
okini3939 0:d18dff347122 109
hillkim7 2:584ce0a1a76e 110 n = httpd->_state[id].client->receive(buf, sizeof(buf)-1);
okini3939 0:d18dff347122 111 if (n < 0) break;
okini3939 0:d18dff347122 112 buf[n] = 0;
okini3939 0:d18dff347122 113 // DBG("Recv %d '%s'", n, buf);
okini3939 0:d18dff347122 114
okini3939 0:d18dff347122 115 for (i = 0; i < n; i ++) {
okini3939 0:d18dff347122 116 httpd->recvData(id, buf[i]);
okini3939 0:d18dff347122 117 }
okini3939 0:d18dff347122 118 }
okini3939 0:d18dff347122 119
okini3939 0:d18dff347122 120 httpd->_state[id].client->close();
okini3939 0:d18dff347122 121 INFO("Close %s\r\n", httpd->_state[id].client->get_address());
okini3939 0:d18dff347122 122 }
okini3939 0:d18dff347122 123 }
okini3939 0:d18dff347122 124
okini3939 0:d18dff347122 125 void HTTPD::closer (void const *arg) {
okini3939 0:d18dff347122 126 HTTPD *httpd = HTTPD::getInstance();
okini3939 0:d18dff347122 127 int id = (int)arg;
okini3939 0:d18dff347122 128
okini3939 0:d18dff347122 129 for (;;) {
okini3939 0:d18dff347122 130 Thread::signal_wait(1);
okini3939 0:d18dff347122 131
okini3939 0:d18dff347122 132 httpd->_state[id].client->close();
okini3939 0:d18dff347122 133 INFO("Close %s\r\n", httpd->_state[id].client->get_address());
okini3939 0:d18dff347122 134 }
okini3939 0:d18dff347122 135 }