[PATCH net] sctp: fix soft lockup from unpadded ASCONF-ACK parameter iteration

Henry Martin <[email protected]>
Newsgroups org.kernel.vger.netdev,org.kernel.vger.linux-sctp
Message-ID <[email protected]>
sctp_verify_asconf() walks ASCONF-ACK parameters with
sctp_walk_params(), which advances by SCTP_PAD4(length), and its
SCTP_PARAM_ERR_CAUSE case performs no length checks, so an odd-length
parameter passes verification. The consumer sctp_get_asconf_response()
then iterates the same parameters advancing by the raw length, without
padding. A single odd-length parameter desynchronises the two walks and
makes the consumer interpret attacker-controlled bytes at a misaligned
offset.

When those bytes yield a length of zero, the while loop over
asconf_ack_len makes no progress, spinning forever in softirq context,
and the watchdog reports a soft lockup. A remote peer can trigger this
with a crafted ASCONF-ACK on an ADD-IP enabled association with an
outstanding ASCONF (RFC 5061 section 4.1.2 requires the chunk to be
authenticated, but the predefined empty key id 0 allows the peer to
compute the same association HMAC from publicly exchanged parameters,
so the gate does not help).

All reads stay within the received skb, so this is a pure remote
denial of service.

Advance the iterator with the same padding rule as the verifier and
reject zero or truncated lengths to guarantee forward progress.

The issue was found by ZeroHive, a vulnerability hunting agent at
Tencent Yunding Lab.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Henry Martin <[email protected]>
---
 net/sctp/sm_make_chunk.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 5a335c980a7a4..0634241fd6649 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -3452,8 +3462,10 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
 		}
 
 		length = ntohs(asconf_ack_param->param_hdr.length);
-		asconf_ack_param = (void *)asconf_ack_param + length;
-		asconf_ack_len -= length;
+		if (length < sizeof(struct sctp_paramhdr))
+			return SCTP_ERROR_INV_PARAM;
+		asconf_ack_param = (void *)asconf_ack_param + SCTP_PAD4(length);
+		asconf_ack_len -= SCTP_PAD4(length);
 	}
 
 	return err_code;
--
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.