diff options
| author | Eric Dumazet <edumazet@google.com> | 2023-08-03 16:30:21 +0000 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-08-16 18:21:01 +0200 |
| commit | 6d701c95ee6463abcbb6da543060d6e444554135 (patch) | |
| tree | a315e83cec0bf361cb8d8a65d36ccd022fb1542e | |
| parent | 6d0bd7b7b3a7a5177de44f12459022b4ca57af19 (diff) | |
| download | linux-6d701c95ee6463abcbb6da543060d6e444554135.tar.gz linux-6d701c95ee6463abcbb6da543060d6e444554135.tar.bz2 linux-6d701c95ee6463abcbb6da543060d6e444554135.zip | |
dccp: fix data-race around dp->dccps_mss_cache
commit a47e598fbd8617967e49d85c49c22f9fc642704c upstream.
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: 7c657876b63c ("[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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | net/dccp/output.c | 2 | ||||
| -rw-r--r-- | net/dccp/proto.c | 10 |
2 files changed, 9 insertions, 3 deletions
diff --git a/net/dccp/output.c b/net/dccp/output.c index 50e6d5699bb2..d679032f0034 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -185,7 +185,7 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu) /* And store cached results */ icsk->icsk_pmtu_cookie = pmtu; - dp->dccps_mss_cache = cur_mps; + WRITE_ONCE(dp->dccps_mss_cache, cur_mps); return cur_mps; } diff --git a/net/dccp/proto.c b/net/dccp/proto.c index e946211758c0..3293c1e3aa5d 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -639,7 +639,7 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, return dccp_getsockopt_service(sk, len, (__be32 __user *)optval, optlen); case DCCP_SOCKOPT_GET_CUR_MPS: - val = dp->dccps_mss_cache; + val = READ_ONCE(dp->dccps_mss_cache); break; case DCCP_SOCKOPT_AVAILABLE_CCIDS: return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen); @@ -748,7 +748,7 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) trace_dccp_probe(sk, len); - if (len > dp->dccps_mss_cache) + if (len > READ_ONCE(dp->dccps_mss_cache)) return -EMSGSIZE; lock_sock(sk); @@ -781,6 +781,12 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) 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); rc = memcpy_from_msg(skb_put(skb, len), msg, len); if (rc != 0) |
