CVE-2019-5436: Heap Buffer Overflow at lib/tftp.c
What the report claims
A heap buffer overflow can occur in lib/tftp.c due to state->blksize containing the default size instead of the size specified in the --tftp-blksize parameter.
Compare with curl's recorded outcome
Known vulnerability
A real vulnerability: CVE-2019-5436 TFTP receive buffer overflow
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The available evidence does not settle the report. A maintainer should investigate.
Why this finding?
- The core claim (C1) about state->blksize not reflecting --tftp-blksize cannot be verified because the option parsing and blksize initialization code are not in the provided snippets.
- The recvfrom call at line 1114 is confirmed, but the buffer size (state->rpacket.data) and how blksize is set are unknown from provided code.
- A human needs to examine the full lib/tftp.c to check: (1) tftp_state_data_t definition for rpacket.data size, (2) where state->blksize is initialized, (3) where --tftp-blksize is parsed and whether it updates state->blksize.
What still needs checking
- tftp_state_data_t structure definition (showing rpacket.data buffer size)
- Code that initializes state->blksize (likely in tftp_connect or tftp_do)
- Code that parses --tftp-blksize option and assigns it to state->blksize
How this analysis ran 5 claims · 1 citations verified
Checked against curl master on 2019-04-29 (9e8f28a8f1fe). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the report. The recvfrom call at lib/tftp.c:1114 is confirmed. However, to evaluate whether state->blksize incorrectly holds the default instead of the --tftp-blksize value, we need to see: (1) the tftp_state_data_t struct definition (size of rpacket.data), (2) where state->blksize is initialized, and (3) the --tftp-blksize option parsing code. Could you point to those locations or provide a patch showing the fix?
Inspect all claims and source code 5 claims · 2 code excerpts
Report claims
state->blksize contains the default size instead of the size specified in the --tftp-blksize parameter
Read the reasoning
The claim that state->blksize initialization and --tftp-blksize option parsing are not in the provided code snippets. The provided lib/tftp.c excerpt (lines 1089-1139) shows the recvfrom call using state->blksize but not where blksize is set or where the command-line option is processed. The tftp_state_data_t structure definition (which would show rpacket.data size) is also not provided.
line 1114 in file lib/tftp.c
Read the reasoning
The deterministic checks confirm the recvfrom call at line 1114 in lib/tftp.c exists as quoted in the report.
using --tftp-blksize N where N is lower than 293
Read the reasoning
The trigger condition depends on the relationship between --tftp-blksize value, state->blksize, and the rpacket.data buffer size. None of the option parsing code, blksize assignment, or buffer allocation is in the provided snippets.
crash or possibly remote code execution (RCE)
Read the reasoning
Impact depends on C1 being true. Without verifying the buffer size mismatch, crash/RCE potential cannot be assessed from provided code.
run evil-server.py, bind to an address, then connect with curl using --tftp-blksize N where N < 293
Read the reasoning
Reproduction references evil-server.py which is not provided. The steps assume the vulnerability exists but cannot be validated without the missing code context.
Read the original report
Source code
| 1089 | return GETSOCK_BLANK; |
| 1090 | |
| 1091 | socks[0] = conn->sock[FIRSTSOCKET]; |
| 1092 | |
| 1093 | return GETSOCK_READSOCK(0); |
| 1094 | } |
| 1095 | |
| 1096 | /********************************************************** |
| 1097 | * |
| 1098 | * tftp_receive_packet |
| 1099 | * |
| 1100 | * Called once select fires and data is ready on the socket |
| 1101 | * |
| 1102 | **********************************************************/ |
| 1103 | static CURLcode tftp_receive_packet(struct connectdata *conn) |
| 1104 | { |
| 1105 | struct Curl_sockaddr_storage fromaddr; |
| 1106 | curl_socklen_t fromlen; |
| 1107 | CURLcode result = CURLE_OK; |
| 1108 | struct Curl_easy *data = conn->data; |
| 1109 | tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; |
| 1110 | struct SingleRequest *k = &data->req; |
| 1111 | |
| 1112 | /* Receive the packet */ |
| 1113 | fromlen = sizeof(fromaddr); |
| 1114 | state->rbytes = (int)recvfrom(state->sockfd, |
| C2: Deterministic checks confirm lines 1109-1119 at revision 9e8f28a8f1fe contain recvfrom, blksize, state; the quoted recvfrom call matches lines 1114-1119. | |
| 1115 | (void *)state->rpacket.data, |
| 1116 | state->blksize + 4, |
| 1117 | 0, |
| 1118 | (struct sockaddr *)&fromaddr, |
| 1119 | &fromlen); |
| 1120 | if(state->remote_addrlen == 0) { |
| 1121 | memcpy(&state->remote_addr, &fromaddr, fromlen); |
| 1122 | state->remote_addrlen = fromlen; |
| 1123 | } |
| 1124 | |
| 1125 | /* Sanity check packet length */ |
| 1126 | if(state->rbytes < 4) { |
| 1127 | failf(data, "Received too short packet"); |
| 1128 | /* Not a timeout, but how best to handle it? */ |
| 1129 | state->event = TFTP_EVENT_TIMEOUT; |
| 1130 | } |
| 1131 | else { |
| 1132 | /* The event is given by the TFTP packet time */ |
| 1133 | unsigned short event = getrpacketevent(&state->rpacket); |
| 1134 | state->event = (tftp_event_t)event; |
| 1135 | |
| 1136 | switch(state->event) { |
| 1137 | case TFTP_EVENT_DATA: |
| 1138 | /* Don't pass to the client empty or retransmitted packets */ |
| 1139 | if(state->rbytes > 4 && |
| 194 | static void state(struct SASL *sasl, struct connectdata *conn, |
| 195 | saslstate newstate) |
| 196 | { |
| 197 | #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) |
| 198 | /* for debug purposes */ |
| 199 | static const char * const names[]={ |
| 200 | "STOP", |
| 201 | "PLAIN", |
| 202 | "LOGIN", |
| 203 | "LOGIN_PASSWD", |
| 204 | "EXTERNAL", |
| 205 | "CRAMMD5", |
| 206 | "DIGESTMD5", |
| 207 | "DIGESTMD5_RESP", |
| 208 | "NTLM", |
| 209 | "NTLM_TYPE2MSG", |
| 210 | "GSSAPI", |
| 211 | "GSSAPI_TOKEN", |
| 212 | "GSSAPI_NO_DATA", |
| 213 | "OAUTH2", |
| 214 | "OAUTH2_RESP", |
| 215 | "CANCEL", |
| 216 | "FINAL", |
| 217 | /* LAST */ |
| 218 | }; |
| 219 | |
| 220 | if(sasl->state != newstate) |
| 221 | infof(conn->data, "SASL %p state change from %s to %s\n", |
| 222 | (void *)sasl, names[sasl->state], names[newstate]); |
| 223 | #else |
| 224 | (void) conn; |
| 225 | #endif |
| 226 | |
| 227 | sasl->state = newstate; |
| 228 | } |