View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0010300 | libmicrohttpd | internal event loop | public | 2025-08-29 12:06 | 2025-08-29 12:06 |
Reporter | arthurscchan | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | random |
Status | new | Resolution | open | ||
Summary | 0010300: Buggy conditional check found in mhd_recv.c | ||||
Description | A buggy conditional branch check has been found in the `mhd_recv_tls(...)` function. https://git.gnunet.org/libmicrohttpd2.git/tree/src/mhd2/mhd\_recv.c#n87 ``` static MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4) enum mhd_SocketError mhd_recv_tls (struct MHD_Connection *restrict c, size_t buf_size, char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], size_t *restrict received) { /* TLS connection */ enum mhd_SocketError res; mhd_assert (mhd_C_HAS_TLS (c)); mhd_assert (0 != buf_size); res = mhd_tls_conn_recv (c->tls, buf_size, buf, received); c->tls_has_data_in = mhd_TLS_BUF_NO_DATA; /* Updated with the actual value below */ if (mhd_SOCKET_ERR_AGAIN == res) c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */ (((unsigned int) c->sk.ready) & (~(enum mhd_SocketNetState) mhd_SOCKET_NET_STATE_RECV_READY)); else if (mhd_SOCKET_ERR_NO_ERROR == res) { if (! c->sk.props.is_nonblck) c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */ (((unsigned int) c->sk.ready) & (~(enum mhd_SocketNetState) mhd_SOCKET_NET_STATE_RECV_READY)); if (res == buf_size) { if (mhd_tls_conn_has_data_in (c->tls)) c->tls_has_data_in = mhd_TLS_BUF_HAS_DATA_IN; } #ifndef NDEBUG else mhd_assert (! mhd_tls_conn_has_data_in (c->tls)); #endif } return res; } ``` On lines 95–103 (https://git.gnunet.org/libmicrohttpd2.git/tree/src/mhd2/mhd_recv.c#n95), the `res` variable is explicitly defined as an `enum mhd_SocketError`. The `buf_size` parameter is asserted to be non-zero. The `res` variable stores the return value from `mhd_tls_conn_recv(...)`, which is expected to be an `enum` indicating either success (`mhd_SOCKET_ERR_NO_ERROR`) or a specific socket error. ``` enum mhd_SocketError res; mhd_assert (mhd_C_HAS_TLS (c)); mhd_assert (0 != buf_size); res = mhd_tls_conn_recv (c->tls, buf_size, buf, received); ``` Later, in lines 111–122 (https://git.gnunet.org/libmicrohttpd2.git/tree/src/mhd2/mhd_recv.c#n111), there is an `else if` branch that executes only if `mhd_SOCKET_ERR_NO_ERROR == res`. This means that `res` must equal `0` (as defined in the enum). However, the subsequent check `if (res == buf_size)` compares this status value (0) to the buffer size (which has been asserted to be non-zero), making the condition impossible to satisfy. As a result, the block that sets the `c->tls_has_data_in` flag is never executed. ``` else if (mhd_SOCKET_ERR_NO_ERROR == res) { if (! c->sk.props.is_nonblck) c->sk.ready = (enum mhd_SocketNetState) /* Clear 'recv-ready' */ (((unsigned int) c->sk.ready) & (~(enum mhd_SocketNetState) mhd_SOCKET_NET_STATE_RECV_READY)); if (res == buf_size) { if (mhd_tls_conn_has_data_in (c->tls)) c->tls_has_data_in = mhd_TLS_BUF_HAS_DATA_IN; } ``` Since `c->tls_has_data_in` is never set, the daemon and connection handler will always assume that there are no pre-decrypted bytes available in the TLS buffer. This means some branches that rely on this flag will never run, leading to the ignoring of already received data and always waiting for another socket event. This can lead to unnecessary delays, stalls, and reduced throughput because data already decrypted and buffered by the TLS layer is always ignored. | ||||
Additional Information | Found during the ongoing security audit carried out by Ada Logics and facilitated by OSTIF in the libmicrohttpd2 project. | ||||
Tags | No tags attached. | ||||
Date Modified | Username | Field | Change |
---|---|---|---|
2025-08-29 12:06 | arthurscchan | New Issue |