[PATCH] net: tftp: fix malformed option string parsing
Jerome Forissier
jerome.forissier at arm.com
Mon Mar 23 16:57:13 CET 2026
On 23/03/2026 14:51, Chencheng Zhang wrote:
> Hi Sverdin and Jerome,
>
>> Do you test with commit 1bc125becaa5 ("tiny-printf: emit \0 as %c")?
> Thanks for pointing that out!
> I have checked my baseline which is TI u-boot v2025-01. Clearly 1bc125becaa5 is not included. I patched my baseline with 1bc125becaa5 and it works.
>
> You can reject my patch.
OK. Thanks for contributing nevertheless.
--
Jerome
> BR/Chencheng
>
> On Mon, 23 Mar 2026 at 13:10, Jerome Forissier <jerome.forissier at arm.com <mailto:jerome.forissier at arm.com>> wrote:
>
>
>
> 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 <mailto: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