net: sock_copy() fixes
Commit e912b1142b
(net: sk_prot_alloc() should not blindly overwrite memory)
took care of not zeroing whole new socket at allocation time.
sock_copy() is another spot where we should be very careful.
We should not set refcnt to a non null value, until
we are sure other fields are correctly setup, or
a lockless reader could catch this socket by mistake,
while not fully (re)initialized.
This patch puts sk_node & sk_refcnt to the very beginning
of struct sock to ease sock_copy() & sk_prot_alloc() job.
We add appropriate smp_wmb() before sk_refcnt initializations
to match our RCU requirements (changes to sock keys should
be committed to memory before sk_refcnt setting)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
303d67c288
commit
4dc6dc7162
@ -919,13 +919,19 @@ static inline void sock_lock_init(struct sock *sk)
|
||||
af_family_keys + sk->sk_family);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet,
|
||||
* even temporarly, because of RCU lookups. sk_node should also be left as is.
|
||||
*/
|
||||
static void sock_copy(struct sock *nsk, const struct sock *osk)
|
||||
{
|
||||
#ifdef CONFIG_SECURITY_NETWORK
|
||||
void *sptr = nsk->sk_security;
|
||||
#endif
|
||||
|
||||
memcpy(nsk, osk, osk->sk_prot->obj_size);
|
||||
BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) !=
|
||||
sizeof(osk->sk_node) + sizeof(osk->sk_refcnt));
|
||||
memcpy(&nsk->sk_copy_start, &osk->sk_copy_start,
|
||||
osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start));
|
||||
#ifdef CONFIG_SECURITY_NETWORK
|
||||
nsk->sk_security = sptr;
|
||||
security_sk_clone(osk, nsk);
|
||||
@ -1140,6 +1146,11 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
|
||||
|
||||
newsk->sk_err = 0;
|
||||
newsk->sk_priority = 0;
|
||||
/*
|
||||
* Before updating sk_refcnt, we must commit prior changes to memory
|
||||
* (Documentation/RCU/rculist_nulls.txt for details)
|
||||
*/
|
||||
smp_wmb();
|
||||
atomic_set(&newsk->sk_refcnt, 2);
|
||||
|
||||
/*
|
||||
@ -1855,6 +1866,11 @@ void sock_init_data(struct socket *sock, struct sock *sk)
|
||||
|
||||
sk->sk_stamp = ktime_set(-1L, 0);
|
||||
|
||||
/*
|
||||
* Before updating sk_refcnt, we must commit prior changes to memory
|
||||
* (Documentation/RCU/rculist_nulls.txt for details)
|
||||
*/
|
||||
smp_wmb();
|
||||
atomic_set(&sk->sk_refcnt, 1);
|
||||
atomic_set(&sk->sk_wmem_alloc, 1);
|
||||
atomic_set(&sk->sk_drops, 0);
|
||||
|
Reference in New Issue
Block a user