From 1bc91fa98c020c1f737680cc43a4c7584e17db15 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Thu, 17 Apr 2025 15:27:00 +0200 Subject: net-lwip: tftp: add LMB and buffer checks Legacy NET tftp invokes a store_block() function which performs buffer validation (LMB, address wrapping). Do the same with NET_LWIP. Signed-off-by: Jerome Forissier Suggested-by: Sughosh Ganu Acked-by: Sughosh Ganu Tested-by: Sughosh Ganu --- net/lwip/tftp.c | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 11 deletions(-) (limited to 'net/lwip/tftp.c') diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c index 4f9b2049187..162c141105c 100644 --- a/net/lwip/tftp.c +++ b/net/lwip/tftp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,47 @@ struct tftp_ctx { enum done_state done; }; +/** + * store_block() - copy received data + * + * This function is called by the receive callback to copy a block of data + * into its final location (ctx->daddr). Before doing so, it checks if the copy + * is allowed. + * + * @ctx: the context for the current transfer + * @src: the data received from the TCP stack + * @len: the length of the data + */ +static int store_block(struct tftp_ctx *ctx, void *src, u16_t len) +{ + ulong store_addr = ctx->daddr; + void *ptr; + + if (CONFIG_IS_ENABLED(LMB)) { + if (store_addr + len < store_addr || + lmb_read_check(store_addr, len)) { + puts("\nTFTP error: "); + puts("trying to overwrite reserved memory...\n"); + return -1; + } + } + + ptr = map_sysmem(store_addr, len); + memcpy(ptr, src, len); + unmap_sysmem(ptr); + + ctx->daddr += len; + ctx->size += len; + ctx->block_count++; + if (ctx->block_count % 10 == 0) { + putc('#'); + if (ctx->block_count % (65 * 10) == 0) + puts("\n\t "); + } + + return 0; +} + static void *tftp_open(const char *fname, const char *mode, u8_t is_write) { return NULL; @@ -71,17 +113,9 @@ static int tftp_write(void *handle, struct pbuf *p) struct tftp_ctx *ctx = handle; struct pbuf *q; - for (q = p; q; q = q->next) { - memcpy((void *)ctx->daddr, q->payload, q->len); - ctx->daddr += q->len; - ctx->size += q->len; - ctx->block_count++; - if (ctx->block_count % 10 == 0) { - putc('#'); - if (ctx->block_count % (65 * 10) == 0) - puts("\n\t "); - } - } + for (q = p; q; q = q->next) + if (store_block(ctx, q->payload, q->len) < 0) + return -1; return 0; } -- cgit v1.2.3 From 722e41ad9931bf6f327a66b5f8ec0dadfb32e0f3 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Mon, 28 Apr 2025 11:24:07 +0200 Subject: net: lwip: tftp: time out if there is no reply from server When there is no reply from the TFTP server, do_tftpb() should eventually time out. Add a 10 second timer for that purpose. Reported-by: Heinrich Schuchardt Signed-off-by: Jerome Forissier --- net/lwip/tftp.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'net/lwip/tftp.c') diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c index 162c141105c..fae701bad2e 100644 --- a/net/lwip/tftp.c +++ b/net/lwip/tftp.c @@ -16,6 +16,8 @@ #include #define PROGRESS_PRINT_STEP_BYTES (10 * 1024) +/* Max time to wait for first data packet from server */ +#define NO_RSP_TIMEOUT_MS 10000 enum done_state { NOT_DONE = 0, @@ -140,6 +142,17 @@ static const struct tftp_context tftp_context = { tftp_error }; +static void no_response(void *arg) +{ + struct tftp_ctx *ctx = (struct tftp_ctx *)arg; + + if (ctx->size) + return; + + printf("Timeout!\n"); + ctx->done = FAILURE; +} + static int tftp_loop(struct udevice *udev, ulong addr, char *fname, ip_addr_t srvip, uint16_t srvport) { @@ -184,6 +197,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname, return -1; } + sys_timeout(NO_RSP_TIMEOUT_MS, no_response, &ctx); while (!ctx.done) { net_lwip_rx(udev, netif); sys_check_timeouts(); @@ -193,6 +207,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname, break; } } + sys_untimeout(no_response, (void *)&ctx); tftp_cleanup(); -- cgit v1.2.3