dccp: fix data-race around dp->dccps_mss_cache

dccp_sendmsg() reads dp->dccps_mss_cache before locking the socket.
Same thing in do_dccp_getsockopt().

Add READ_ONCE()/WRITE_ONCE() annotations,
and change dccp_sendmsg() to check again dccps_mss_cache
after socket is locked.

Fixes: 7c657876b6 ("[DCCP]: Initial implementation")
Reported-by: syzbot <syzkaller@googlegroups.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20230803163021.2958262-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Eric Dumazet 2023-08-03 16:30:21 +00:00 committed by Jakub Kicinski
parent fc2ea6ab0a
commit a47e598fbd
2 changed files with 9 additions and 3 deletions

View File

@ -187,7 +187,7 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
/* And store cached results */ /* And store cached results */
icsk->icsk_pmtu_cookie = pmtu; icsk->icsk_pmtu_cookie = pmtu;
dp->dccps_mss_cache = cur_mps; WRITE_ONCE(dp->dccps_mss_cache, cur_mps);
return cur_mps; return cur_mps;
} }

View File

@ -630,7 +630,7 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
return dccp_getsockopt_service(sk, len, return dccp_getsockopt_service(sk, len,
(__be32 __user *)optval, optlen); (__be32 __user *)optval, optlen);
case DCCP_SOCKOPT_GET_CUR_MPS: case DCCP_SOCKOPT_GET_CUR_MPS:
val = dp->dccps_mss_cache; val = READ_ONCE(dp->dccps_mss_cache);
break; break;
case DCCP_SOCKOPT_AVAILABLE_CCIDS: case DCCP_SOCKOPT_AVAILABLE_CCIDS:
return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen); return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
@ -739,7 +739,7 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
trace_dccp_probe(sk, len); trace_dccp_probe(sk, len);
if (len > dp->dccps_mss_cache) if (len > READ_ONCE(dp->dccps_mss_cache))
return -EMSGSIZE; return -EMSGSIZE;
lock_sock(sk); lock_sock(sk);
@ -772,6 +772,12 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
goto out_discard; goto out_discard;
} }
/* We need to check dccps_mss_cache after socket is locked. */
if (len > dp->dccps_mss_cache) {
rc = -EMSGSIZE;
goto out_discard;
}
skb_reserve(skb, sk->sk_prot->max_header); skb_reserve(skb, sk->sk_prot->max_header);
rc = memcpy_from_msg(skb_put(skb, len), msg, len); rc = memcpy_from_msg(skb_put(skb, len), msg, len);
if (rc != 0) if (rc != 0)