Merge branch 'contrib/github_pr_14196_v5.2' into 'release/v5.2'

fix(esp_http_server): prevent concurrent access to socket used in async http requests (GitHub PR) (v5.2)

See merge request espressif/esp-idf!34685
This commit is contained in:
Mahavir Jain
2024-11-06 17:43:00 +08:00
3 changed files with 75 additions and 53 deletions

View File

@@ -247,6 +247,11 @@ static int httpd_process_session(struct sock_db *session, void *context)
return 1; return 1;
} }
// session is busy in an async task, do not process here.
if (session->for_async_req) {
return 1;
}
process_session_context_t *ctx = (process_session_context_t *)context; process_session_context_t *ctx = (process_session_context_t *)context;
int fd = session->fd; int fd = session->fd;

View File

@@ -72,6 +72,7 @@ static int enum_function(struct sock_db *session, void *context)
case HTTPD_TASK_INIT: case HTTPD_TASK_INIT:
session->fd = -1; session->fd = -1;
session->ctx = NULL; session->ctx = NULL;
session->for_async_req = false;
break; break;
// Get active session // Get active session
case HTTPD_TASK_GET_ACTIVE: case HTTPD_TASK_GET_ACTIVE:
@@ -87,7 +88,7 @@ static int enum_function(struct sock_db *session, void *context)
break; break;
// Set descriptor // Set descriptor
case HTTPD_TASK_SET_DESCRIPTOR: case HTTPD_TASK_SET_DESCRIPTOR:
if (session->fd != -1) { if (session->fd != -1 && !session->for_async_req) {
FD_SET(session->fd, ctx->fdset); FD_SET(session->fd, ctx->fdset);
if (session->fd > ctx->max_fd) { if (session->fd > ctx->max_fd) {
ctx->max_fd = session->fd; ctx->max_fd = session->fd;

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2018-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2018-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -575,9 +575,24 @@ esp_err_t httpd_req_async_handler_begin(httpd_req_t *r, httpd_req_t **out)
} }
memcpy(async->aux, r->aux, sizeof(struct httpd_req_aux)); memcpy(async->aux, r->aux, sizeof(struct httpd_req_aux));
// Copy response header block
struct httpd_data *hd = (struct httpd_data *) r->handle;
struct httpd_req_aux *async_aux = (struct httpd_req_aux *) async->aux;
struct httpd_req_aux *r_aux = (struct httpd_req_aux *) r->aux;
async_aux->resp_hdrs = calloc(hd->config.max_resp_headers, sizeof(struct resp_hdr));
if (async_aux->resp_hdrs == NULL) {
free(async_aux);
free(async);
return ESP_ERR_NO_MEM;
}
memcpy(async_aux->resp_hdrs, r_aux->resp_hdrs, hd->config.max_resp_headers * sizeof(struct resp_hdr));
// Prevent the main thread from reading the rest of the request after the handler returns.
r_aux->remaining_len = 0;
// mark socket as "in use" // mark socket as "in use"
struct httpd_req_aux *ra = r->aux; r_aux->sd->for_async_req = true;
ra->sd->for_async_req = true;
*out = async; *out = async;
@@ -593,6 +608,7 @@ esp_err_t httpd_req_async_handler_complete(httpd_req_t *r)
struct httpd_req_aux *ra = r->aux; struct httpd_req_aux *ra = r->aux;
ra->sd->for_async_req = false; ra->sd->for_async_req = false;
free(ra->resp_hdrs);
free(r->aux); free(r->aux);
free(r); free(r);
@@ -619,7 +635,7 @@ static int httpd_sock_err(const char *ctx, int sockfd)
int errval; int errval;
ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, errno); ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, errno);
switch(errno) { switch (errno) {
case EAGAIN: case EAGAIN:
case EINTR: case EINTR:
errval = HTTPD_SOCK_ERR_TIMEOUT; errval = HTTPD_SOCK_ERR_TIMEOUT;