diff -urN gpxe-0.9.7/src/net/udp/tftp.c gpxe-0.9.7-oackfix/src/net/udp/tftp.c --- gpxe-0.9.7/src/net/udp/tftp.c 2009-03-01 21:23:42.000000000 -0500 +++ gpxe-0.9.7-oackfix/src/net/udp/tftp.c 2009-08-21 20:45:10.000000000 -0400 @@ -670,6 +670,7 @@ char *end = buf + len; char *name; char *value; + char *next; int rc = 0; /* Sanity check */ @@ -679,26 +680,41 @@ rc = -EINVAL; goto done; } - if ( end[-1] != '\0' ) { - DBGC ( tftp, "TFTP %p received OACK missing final NUL\n", - tftp ); - rc = -EINVAL; - goto done; - } /* Process each option in turn */ - name = oack->data; - while ( name < end ) { - value = ( name + strlen ( name ) + 1 ); + for ( name = oack->data ; name < end ; name = next ) { + + /* Parse option name and value + * + * We treat parsing errors as non-fatal, because there + * exists at least one TFTP server (IBM Tivoli PXE + * Server 5.1.0.3) that has been observed to send + * malformed OACKs containing trailing garbage bytes. + */ + value = ( name + strnlen ( name, ( end - name ) ) + 1 ); + if ( value > end ) { + DBGC ( tftp, "TFTP %p received OACK with malformed " + "option name:\n", tftp ); + DBGC_HD ( tftp, oack, len ); + break; + } if ( value == end ) { DBGC ( tftp, "TFTP %p received OACK missing value " "for option \"%s\"\n", tftp, name ); - rc = -EINVAL; - goto done; + DBGC_HD ( tftp, oack, len ); + break; } + next = ( value + strnlen ( value, ( end - value ) ) + 1 ); + if ( next > end ) { + DBGC ( tftp, "TFTP %p received OACK with malformed " + "value for option \"%s\":\n", tftp, name ); + DBGC_HD ( tftp, oack, len ); + break; + } + + /* Process option */ if ( ( rc = tftp_process_option ( tftp, name, value ) ) != 0 ) goto done; - name = ( value + strlen ( value ) + 1 ); } /* Process tsize information, if available */