mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
sctp: fix soft lockup from unpadded ASCONF-ACK parameter iteration
sctp_verify_asconf() walks ASCONF-ACK parameters with
sctp_walk_params(), which advances by SCTP_PAD4(length), while the
consumer sctp_get_asconf_response() 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. All reads stay
within the received skb, so the lockup is a pure remote denial of
service. A remote peer can trigger it 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).
The SCTP_PARAM_ERR_CAUSE case of sctp_verify_asconf() also performs
no length check, letting a parameter without a complete error
header reach the consumer, which reads errhdr.cause past the end of
the parameter, an out-of-bounds read.
Reject SCTP_PARAM_ERR_CAUSE parameters shorter than
sizeof(struct sctp_addip_param) + sizeof(struct sctp_errhdr) at the
verifier, and advance the consumer iterator with the same padding
rule as the verifier to keep the two walks in lockstep. The verifier
change guarantees a complete error header in every ERR_CAUSE
parameter the consumer can see, so the consumer's asconf_ack_len
check is dropped and it returns err_param->cause directly. The
consumer padding fix is still required because odd lengths remain
valid for SCTP_PARAM_ERR_CAUSE per RFC 5061.
The issue was found by ZeroHive, a vulnerability hunting agent at
Tencent Yunding Lab.
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
Acked-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20260828042431.3873725-1-bsdhenrymartin@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
2188569e7e
commit
2cb0b0b1ed
|
|
@ -3215,6 +3215,9 @@ bool sctp_verify_asconf(const struct sctp_association *asoc,
|
|||
*errp = param.p;
|
||||
switch (param.p->type) {
|
||||
case SCTP_PARAM_ERR_CAUSE:
|
||||
if (length < sizeof(struct sctp_addip_param) +
|
||||
sizeof(struct sctp_errhdr))
|
||||
return false;
|
||||
break;
|
||||
case SCTP_PARAM_IPV4_ADDRESS:
|
||||
if (length != sizeof(struct sctp_ipv4addr_param))
|
||||
|
|
@ -3448,20 +3451,15 @@ static __be16 sctp_get_asconf_response(struct sctp_chunk *asconf_ack,
|
|||
case SCTP_PARAM_ERR_CAUSE:
|
||||
length = sizeof(*asconf_ack_param);
|
||||
err_param = (void *)asconf_ack_param + length;
|
||||
asconf_ack_len -= length;
|
||||
if (asconf_ack_len > 0)
|
||||
return err_param->cause;
|
||||
else
|
||||
return SCTP_ERROR_INV_PARAM;
|
||||
break;
|
||||
return err_param->cause;
|
||||
default:
|
||||
return SCTP_ERROR_INV_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
length = ntohs(asconf_ack_param->param_hdr.length);
|
||||
asconf_ack_param = (void *)asconf_ack_param + length;
|
||||
asconf_ack_len -= length;
|
||||
asconf_ack_param = (void *)asconf_ack_param + SCTP_PAD4(length);
|
||||
asconf_ack_len -= SCTP_PAD4(length);
|
||||
}
|
||||
|
||||
return err_code;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user