Both tcp_v4_err() and tcp_v6_err() do the following operations while they do not own the socket lock : fastopen = tp->fastopen_rsk; snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; The problem is that without appropriate barrier, the compiler might reload tp->fastopen_rsk and trigger a NULL deref. request sockets are protected by RCU, we can simply add the missing annotations and barriers to solve the issue.
Showing the changes to include/linux (1 of 11 files). Show all
Unified · Split
| @@ -393,7 +393,7 @@ struct tcp_sock { · 392 unmodified lines | ||
| 393 | 393 | /* fastopen_rsk points to request_sock that resulted in this big |
| 394 | 394 | * socket. Used to retransmit SYNACKs etc. |
| 395 | 395 | */ |
| 396 | − struct request_sock *fastopen_rsk; | |
| 396 | + struct request_sock __rcu *fastopen_rsk; | |
| 397 | 397 | u32 *saved_syn; |
| 398 | 398 | }; |
| 399 | 399 | |
| @@ -447,8 +447,8 @@ static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) · 47 unmodified lines | ||
| 447 | 447 | |
| 448 | 448 | static inline bool tcp_passive_fastopen(const struct sock *sk) |
| 449 | 449 | { |
| 450 | − return (sk->sk_state == TCP_SYN_RECV && | |
| 451 | − tcp_sk(sk)->fastopen_rsk != NULL); | |
| 450 | + return sk->sk_state == TCP_SYN_RECV && | |
| 451 | + rcu_access_pointer(tcp_sk(sk)->fastopen_rsk) != NULL; | |
| 452 | 452 | } |
| 453 | 453 | |
| 454 | 454 | static inline void fastopen_queue_tune(struct sock *sk, int backlog) |