From: Drew Kluemke <[email protected]>

The TFTP OACK handler matches option names in the received packet with
strcasecmp(), which scans until a NUL byte. A malformed or truncated
OACK packet may not contain a NUL within the received length, causing
an out-of-bounds read past the packet buffer.

Replace each strcasecmp() with a strncasecmp() bounded to the option
name length plus an explicit check that the name is NUL-terminated at
the expected position. For the "windowsize" option, whose name and
value extend beyond the loop's "i + 8 < len" guard, add an explicit
"i + 11 < len" bound before the comparison.

Signed-off-by: Drew Kluemke <[email protected]>
Signed-off-by: Sriram Sriram <[email protected]>
---
 net/tftp.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/net/tftp.c b/net/tftp.c
index beb9d08f5a2..35693e2a93e 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -544,7 +544,8 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
                 * something like "len-8" may give a *huge* number
                 */
                for (i = 0; i+8 < len; i++) {
-                       if (strcasecmp((char *)pkt + i, "blksize") == 0) {
+                       if (!strncasecmp((char *)pkt + i, "blksize", 7) &&
+                           pkt[i + 7] == '\0') {
                                tftp_block_size = (unsigned short)
                                        dectoul((char *)pkt + i + 8, NULL);
                                debug("Blocksize oack: %s, %d\n",
@@ -555,7 +556,8 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
                                        tftp_state = STATE_INVALID_OPTION;
                                }
                        }
-                       if (strcasecmp((char *)pkt + i, "timeout") == 0) {
+                       if (!strncasecmp((char *)pkt + i, "timeout", 7) &&
+                           pkt[i + 7] == '\0') {
                                timeout_val_rcvd = (unsigned short)
                                        dectoul((char *)pkt + i + 8, NULL);
                                debug("Timeout oack: %s, %d\n",
@@ -567,14 +569,17 @@ static void tftp_handler(uchar *pkt, unsigned dest, 
struct in_addr sip,
                                }
                        }
 #ifdef CONFIG_TFTP_TSIZE
-                       if (strcasecmp((char *)pkt + i, "tsize") == 0) {
+                       if (!strncasecmp((char *)pkt + i, "tsize", 5) &&
+                           pkt[i + 5] == '\0') {
                                tftp_tsize = dectoul((char *)pkt + i + 6,
                                                     NULL);
                                debug("size = %s, %u\n",
                                      (char *)pkt + i + 6, tftp_tsize);
                        }
 #endif
-                       if (strcasecmp((char *)pkt + i,  "windowsize") == 0) {
+                       if (i + 11 < len &&
+                           !strncasecmp((char *)pkt + i, "windowsize", 10) &&
+                           pkt[i + 10] == '\0') {
                                tftp_windowsize =
                                        dectoul((char *)pkt + i + 11, NULL);
                                debug("windowsize = %s, %d\n",
-- 
2.49.0

Reply via email to