net: add real socket cookies
A long standing problem in netlink socket dumps is the use of kernel socket addresses as cookies. 1) It is a security concern. 2) Sockets can be reused quite quickly, so there is no guarantee a cookie is used once and identify a flow. 3) request sock, establish sock, and timewait socks for a given flow have different cookies. Part of our effort to bring better TCP statistics requires to switch to a different allocator. In this patch, I chose to use a per network namespace 64bit generator, and to use it only in the case a socket needs to be dumped to netlink. (This might be refined later if needed) Note that I tried to carry cookies from request sock, to establish sock, then timewait sockets. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Eric Salo <salo@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
654eff4516
commit
33cf7c90fe
@@ -1538,6 +1538,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
|
||||
newsk->sk_err = 0;
|
||||
newsk->sk_priority = 0;
|
||||
newsk->sk_incoming_cpu = raw_smp_processor_id();
|
||||
atomic64_set(&newsk->sk_cookie, 0);
|
||||
/*
|
||||
* Before updating sk_refcnt, we must commit prior changes to memory
|
||||
* (Documentation/RCU/rculist_nulls.txt for details)
|
||||
|
@@ -13,22 +13,39 @@ static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
|
||||
static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
|
||||
static DEFINE_MUTEX(sock_diag_table_mutex);
|
||||
|
||||
int sock_diag_check_cookie(void *sk, const __u32 *cookie)
|
||||
static u64 sock_gen_cookie(struct sock *sk)
|
||||
{
|
||||
if ((cookie[0] != INET_DIAG_NOCOOKIE ||
|
||||
cookie[1] != INET_DIAG_NOCOOKIE) &&
|
||||
((u32)(unsigned long)sk != cookie[0] ||
|
||||
(u32)((((unsigned long)sk) >> 31) >> 1) != cookie[1]))
|
||||
return -ESTALE;
|
||||
else
|
||||
while (1) {
|
||||
u64 res = atomic64_read(&sk->sk_cookie);
|
||||
|
||||
if (res)
|
||||
return res;
|
||||
res = atomic64_inc_return(&sock_net(sk)->cookie_gen);
|
||||
atomic64_cmpxchg(&sk->sk_cookie, 0, res);
|
||||
}
|
||||
}
|
||||
|
||||
int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
|
||||
{
|
||||
u64 res;
|
||||
|
||||
if (cookie[0] == INET_DIAG_NOCOOKIE && cookie[1] == INET_DIAG_NOCOOKIE)
|
||||
return 0;
|
||||
|
||||
res = sock_gen_cookie(sk);
|
||||
if ((u32)res != cookie[0] || (u32)(res >> 32) != cookie[1])
|
||||
return -ESTALE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sock_diag_check_cookie);
|
||||
|
||||
void sock_diag_save_cookie(void *sk, __u32 *cookie)
|
||||
void sock_diag_save_cookie(struct sock *sk, __u32 *cookie)
|
||||
{
|
||||
cookie[0] = (u32)(unsigned long)sk;
|
||||
cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
|
||||
u64 res = sock_gen_cookie(sk);
|
||||
|
||||
cookie[0] = (u32)res;
|
||||
cookie[1] = (u32)(res >> 32);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sock_diag_save_cookie);
|
||||
|
||||
|
Reference in New Issue
Block a user