From: Eric Dumazet <eduma...@google.com>

dccp_parse_options() improperly parses 12 or 16 bytes in excess,
because it forgets to subtract DCCP header len.

This causes various issues, since these 12/16 bytes are part of the
payload and this might not even be present in skb->head, as
dccp_invalid_packet() only pulled everything but payload.

KASAN complains since we might access uninitialized data.

Strangely enough, net/netfilter/xt_dccp.c got this right.

Signed-off-by: Eric Dumazet <eduma...@google.com>
Reported-by: Andrey Konovalov <andreyk...@google.com>
Cc: Gerrit Renker <ger...@erg.abdn.ac.uk>
---
 net/dccp/options.c |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/net/dccp/options.c b/net/dccp/options.c
index 
74d29c56c36709fd4e31f0e63a1f8b1aa38a32cd..41bd4bc4026f97b155e12a3a37095653836ce7fc
 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -54,10 +54,9 @@ int dccp_parse_options(struct sock *sk, struct 
dccp_request_sock *dreq,
        struct dccp_sock *dp = dccp_sk(sk);
        const struct dccp_hdr *dh = dccp_hdr(skb);
        const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type;
-       unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
-       unsigned char *opt_ptr = options;
-       const unsigned char *opt_end = (unsigned char *)dh +
-                                       (dh->dccph_doff * 4);
+       unsigned char *opt_ptr = (unsigned char *)dh + __dccp_hdr_len(dh);
+       unsigned int optlen = dh->dccph_doff * 4 - __dccp_hdr_len(dh);
+       const unsigned char *opt_end = opt_ptr + optlen;
        struct dccp_options_received *opt_recv = &dp->dccps_options_received;
        unsigned char opt, len;
        unsigned char *uninitialized_var(value);


Reply via email to