diff options
author | Eric Dumazet <edumazet@google.com> | 2015-03-11 21:53:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-11 21:55:28 -0400 |
commit | 33cf7c90fe2f97afb1cadaa0cfb782cb9d1b9ee2 (patch) | |
tree | 7a0c80d0b2bb618919d966ce5b827c7eb8f843f6 /net/core | |
parent | 654eff45166c7e89d18fc476325c975768b2e347 (diff) |
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>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/sock.c | 1 | ||||
-rw-r--r-- | net/core/sock_diag.c | 37 |
2 files changed, 28 insertions, 10 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 726e1f99aa8d..a9a9c2ff9260 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -1538,6 +1538,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) | |||
1538 | newsk->sk_err = 0; | 1538 | newsk->sk_err = 0; |
1539 | newsk->sk_priority = 0; | 1539 | newsk->sk_priority = 0; |
1540 | newsk->sk_incoming_cpu = raw_smp_processor_id(); | 1540 | newsk->sk_incoming_cpu = raw_smp_processor_id(); |
1541 | atomic64_set(&newsk->sk_cookie, 0); | ||
1541 | /* | 1542 | /* |
1542 | * Before updating sk_refcnt, we must commit prior changes to memory | 1543 | * Before updating sk_refcnt, we must commit prior changes to memory |
1543 | * (Documentation/RCU/rculist_nulls.txt for details) | 1544 | * (Documentation/RCU/rculist_nulls.txt for details) |
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index 96e70ee05a8d..74dddf84adcd 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c | |||
@@ -13,22 +13,39 @@ static const struct sock_diag_handler *sock_diag_handlers[AF_MAX]; | |||
13 | static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); | 13 | static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); |
14 | static DEFINE_MUTEX(sock_diag_table_mutex); | 14 | static DEFINE_MUTEX(sock_diag_table_mutex); |
15 | 15 | ||
16 | int sock_diag_check_cookie(void *sk, const __u32 *cookie) | 16 | static u64 sock_gen_cookie(struct sock *sk) |
17 | { | 17 | { |
18 | if ((cookie[0] != INET_DIAG_NOCOOKIE || | 18 | while (1) { |
19 | cookie[1] != INET_DIAG_NOCOOKIE) && | 19 | u64 res = atomic64_read(&sk->sk_cookie); |
20 | ((u32)(unsigned long)sk != cookie[0] || | 20 | |
21 | (u32)((((unsigned long)sk) >> 31) >> 1) != cookie[1])) | 21 | if (res) |
22 | return -ESTALE; | 22 | return res; |
23 | else | 23 | res = atomic64_inc_return(&sock_net(sk)->cookie_gen); |
24 | atomic64_cmpxchg(&sk->sk_cookie, 0, res); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) | ||
29 | { | ||
30 | u64 res; | ||
31 | |||
32 | if (cookie[0] == INET_DIAG_NOCOOKIE && cookie[1] == INET_DIAG_NOCOOKIE) | ||
24 | return 0; | 33 | return 0; |
34 | |||
35 | res = sock_gen_cookie(sk); | ||
36 | if ((u32)res != cookie[0] || (u32)(res >> 32) != cookie[1]) | ||
37 | return -ESTALE; | ||
38 | |||
39 | return 0; | ||
25 | } | 40 | } |
26 | EXPORT_SYMBOL_GPL(sock_diag_check_cookie); | 41 | EXPORT_SYMBOL_GPL(sock_diag_check_cookie); |
27 | 42 | ||
28 | void sock_diag_save_cookie(void *sk, __u32 *cookie) | 43 | void sock_diag_save_cookie(struct sock *sk, __u32 *cookie) |
29 | { | 44 | { |
30 | cookie[0] = (u32)(unsigned long)sk; | 45 | u64 res = sock_gen_cookie(sk); |
31 | cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1); | 46 | |
47 | cookie[0] = (u32)res; | ||
48 | cookie[1] = (u32)(res >> 32); | ||
32 | } | 49 | } |
33 | EXPORT_SYMBOL_GPL(sock_diag_save_cookie); | 50 | EXPORT_SYMBOL_GPL(sock_diag_save_cookie); |
34 | 51 | ||