On a store_block() failure httpc_recv_cb() calls altcp_abort(), which
frees the pcb, and then returns ERR_BUF. lwIP's receive-callback contract
requires ERR_ABRT once tcp_abort() has been called. On any other return
value tcp_input() keeps using the freed pcb (for example it stores the
segment in pcb->refused_data), a use-after-free.

Return ERR_ABRT so tcp_input() stops touching the pcb.

Fixes: 3c656c928bd7 ("net: lwip: add wget command")
Signed-off-by: Shahriyar Jalayeri <[email protected]>
---
 net/lwip/wget.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/net/lwip/wget.c b/net/lwip/wget.c
index 247ece18e2b..9e93765926d 100644
--- a/net/lwip/wget.c
+++ b/net/lwip/wget.c
@@ -205,8 +205,12 @@ static err_t httpc_recv_cb(void *arg, struct altcp_pcb 
*pcb, struct pbuf *pbuf,
 
        for (buf = pbuf; buf; buf = buf->next) {
                if (store_block(ctx, buf->payload, buf->len) < 0) {
+                       /*
+                        * altcp_abort() freed the pcb; the recv callback must
+                        * return ERR_ABRT so tcp_input() stops using it.
+                        */
                        altcp_abort(pcb);
-                       ret = ERR_BUF;
+                       ret = ERR_ABRT;
                        goto out;
                }
        }

-- 
2.43.0

Reply via email to