[PATCH] net: tftp: fix malformed option string parsing

Jerome Forissier jerome.forissier at arm.com
Mon Mar 23 13:08:53 CET 2026



On 23/03/2026 12:58, Sverdlin, Alexander (SI B PRO TI EAC CCP) wrote:
> Hi Chencheng,
> 
> On Mon, 2026-03-23 at 12:05 +0100, Chencheng Zhang wrote:
>> When formatting the TFTP options (tsize, blksize, windowsize), the
>> code previously used sprintf() with embedded null bytes (%c). Because
>> sprintf() returns the length excluding the terminating null byte,
>> subsequent sprintf() calls overwrote the required null separators.
> 
> I'm not convinced, the analysis explains the observed effect,
> 
>> This caused the options to be concatenated into a single malformed
>> string (e.g., "tsize0blksize1468") which breaks strict TFTP servers
>                      ^^
> ... as missing 0 byte between 'e' and '0' is not even at the end...
> 
>> like atftpd, causing them to reply with empty packets or drop the
>> connection.
>>
>> Fix this by explicitly using strcpy() for the option names and manually
>> advancing the pointer to ensure the null bytes are preserved.
>>
>> Signed-off-by: Chencheng Zhang <charles.cc.zhang at gmail.com>
>> ---
>>  net/tftp.c | 33 +++++++++++++++++++++------------
>>  1 file changed, 21 insertions(+), 12 deletions(-)
>>
>> diff --git a/net/tftp.c b/net/tftp.c
>> index 5f2e0a2bc06..5a8094791ab 100644
>> --- a/net/tftp.c
>> +++ b/net/tftp.c
>> @@ -355,20 +355,29 @@ static void tftp_send(void)
>>  		debug("send option \"timeout %s\"\n", (char *)pkt);
>>  		pkt += strlen((char *)pkt) + 1;
>>  #ifdef CONFIG_TFTP_TSIZE
>> -		pkt += sprintf((char *)pkt, "tsize%c%u%c",
>                                                  ^^^
> ... of this format string.

+1, and NACK. The original code is perfectly fine assuming a compliant
snprintf() implementation.

> 
> Are you using USE_TINY_PRINTF or not?
> Do you test with commit 1bc125becaa5 ("tiny-printf: emit \0 as %c")?


Nice hint :)

Thanks,
-- 
Jerome

>> -				0, net_boot_file_size, 0);
>> +		/* Write "tsize" + \0 */
>> +		strcpy((char *)pkt, "tsize");
>> +		pkt += 6; /* 5 chars + 1 null */
>> +
>> +		/* Write the value + \0 */
>> +		pkt += sprintf((char *)pkt, "%u", net_boot_file_size) + 1;
>>  #endif
>> -		/* try for more effic. blk size */
>> -		pkt += sprintf((char *)pkt, "blksize%c%d%c",
>> -				0, tftp_block_size_option, 0);
>>  
>> -		/* try for more effic. window size.
>> -		 * Implemented only for tftp get.
>> -		 * Don't bother sending if it's 1
>> -		 */
>> -		if (tftp_state == STATE_SEND_RRQ && tftp_window_size_option > 1)
>> -			pkt += sprintf((char *)pkt, "windowsize%c%d%c",
>> -					0, tftp_window_size_option, 0);
>> +		/* Write "blksize" + \0 */
>> +		strcpy((char *)pkt, "blksize");
>> +		pkt += 8; /* 7 chars + 1 null */
>> +
>> +		/* Write the value + \0 */
>> +		pkt += sprintf((char *)pkt, "%d", tftp_block_size_option) + 1;
>> +
>> +		if (tftp_state == STATE_SEND_RRQ && tftp_window_size_option > 1) {
>> +			/* Write "windowsize" + \0 */
>> +			strcpy((char *)pkt, "windowsize");
>> +			pkt += 11; /* 10 chars + 1 null */
>> +
>> +			/* Write the value + \0 */
>> +			pkt += sprintf((char *)pkt, "%d", tftp_window_size_option) + 1;
>> +		}
>>  		len = pkt - xp;
>>  		break;
>>  
> 



More information about the U-Boot mailing list