espintcp_sendskmsg_locked() calls put_page() and sk_mem_uncharge() for each scatterlist element it successfully sends, but never decrements sg.size. If tcp_sendmsg_locked() then fails partway through, the error path advances sg.start past the freed elements while sg.size still accounts for them. A subsequent sk_msg_free() in espintcp_close() loops until sg.size reaches zero, overshoots sg.end, hits zeroed entries with NULL pages, and crashes in put_page(). Fix this by decrementing sg.size as each element is freed. Also use sk_msg_iter_var_next() instead of raw addition for sg.start, so it wraps at NR_MSG_FRAG_IDS. Fixes: e27cca96cd68 ("xfrm: add espintcp (RFC 8229)") Cc: stable@vger.kernel.org Signed-off-by: Aaron Esau --- net/xfrm/espintcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c index e1b11ab59..6755f6df6 100644 --- a/net/xfrm/espintcp.c +++ b/net/xfrm/espintcp.c @@ -237,7 +237,8 @@ static int espintcp_sendskmsg_locked(struct sock *sk, ret = tcp_sendmsg_locked(sk, &msghdr, size); if (ret < 0) { emsg->offset = offset - sg->offset; - skmsg->sg.start += done; + while (done--) + sk_msg_iter_var_next(skmsg->sg.start); return ret; } @@ -250,6 +251,7 @@ static int espintcp_sendskmsg_locked(struct sock *sk, done++; put_page(p); sk_mem_uncharge(sk, sg->length); + skmsg->sg.size -= sg->length; sg = sg_next(sg); } while (sg); -- 2.54.0