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 | /* fastopen_rsk points to request_sock that resulted in this big | 393 | /* fastopen_rsk points to request_sock that resulted in this big |
| 394 | * socket. Used to retransmit SYNACKs etc. | 394 | * socket. Used to retransmit SYNACKs etc. |
| 395 | */ | 395 | */ |
| 396 | struct request_sock *fastopen_rsk; | 396 | struct request_sock __rcu *fastopen_rsk; |
| 397 | u32 *saved_syn; | 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 | static inline bool tcp_passive_fastopen(const struct sock *sk) | 448 | static inline bool tcp_passive_fastopen(const struct sock *sk) |
| 449 | { | 449 | { |
| 450 | return (sk->sk_state == TCP_SYN_RECV && | 450 | return sk->sk_state == TCP_SYN_RECV && |
| 451 | tcp_sk(sk)->fastopen_rsk != NULL); | 451 | rcu_access_pointer(tcp_sk(sk)->fastopen_rsk) != NULL; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | static inline void fastopen_queue_tune(struct sock *sk, int backlog) | 454 | static inline void fastopen_queue_tune(struct sock *sk, int backlog) |