Commit 02085b17 authored by Yuejie Shi's avatar Yuejie Shi Committed by Ben Hutchings

af_key: Add lock to key dump

commit 89e357d8 upstream.

A dump may come in the middle of another dump, modifying its dump
structure members. This race condition will result in NULL pointer
dereference in kernel. So add a lock to prevent that race.

Fixes: 83321d6b ("[AF_KEY]: Dump SA/SP entries non-atomically")
Signed-off-by: default avatarYuejie Shi <syjcnss@gmail.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
[bwh: Backported to 3.2:
 - pfkey_dump() doesn't support filters
 - Adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 4c68c4f7
...@@ -63,6 +63,7 @@ struct pfkey_sock { ...@@ -63,6 +63,7 @@ struct pfkey_sock {
} u; } u;
struct sk_buff *skb; struct sk_buff *skb;
} dump; } dump;
struct mutex dump_lock;
}; };
static inline struct pfkey_sock *pfkey_sk(struct sock *sk) static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
...@@ -139,6 +140,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, ...@@ -139,6 +140,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol,
{ {
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
struct sock *sk; struct sock *sk;
struct pfkey_sock *pfk;
int err; int err;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
...@@ -153,6 +155,9 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, ...@@ -153,6 +155,9 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol,
if (sk == NULL) if (sk == NULL)
goto out; goto out;
pfk = pfkey_sk(sk);
mutex_init(&pfk->dump_lock);
sock->ops = &pfkey_ops; sock->ops = &pfkey_ops;
sock_init_data(sock, sk); sock_init_data(sock, sk);
...@@ -283,13 +288,23 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) ...@@ -283,13 +288,23 @@ static int pfkey_do_dump(struct pfkey_sock *pfk)
struct sadb_msg *hdr; struct sadb_msg *hdr;
int rc; int rc;
mutex_lock(&pfk->dump_lock);
if (!pfk->dump.dump) {
rc = 0;
goto out;
}
rc = pfk->dump.dump(pfk); rc = pfk->dump.dump(pfk);
if (rc == -ENOBUFS) if (rc == -ENOBUFS) {
return 0; rc = 0;
goto out;
}
if (pfk->dump.skb) { if (pfk->dump.skb) {
if (!pfkey_can_dump(&pfk->sk)) if (!pfkey_can_dump(&pfk->sk)) {
return 0; rc = 0;
goto out;
}
hdr = (struct sadb_msg *) pfk->dump.skb->data; hdr = (struct sadb_msg *) pfk->dump.skb->data;
hdr->sadb_msg_seq = 0; hdr->sadb_msg_seq = 0;
...@@ -300,6 +315,9 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) ...@@ -300,6 +315,9 @@ static int pfkey_do_dump(struct pfkey_sock *pfk)
} }
pfkey_terminate_dump(pfk); pfkey_terminate_dump(pfk);
out:
mutex_unlock(&pfk->dump_lock);
return rc; return rc;
} }
...@@ -1791,18 +1809,24 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms ...@@ -1791,18 +1809,24 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms
u8 proto; u8 proto;
struct pfkey_sock *pfk = pfkey_sk(sk); struct pfkey_sock *pfk = pfkey_sk(sk);
if (pfk->dump.dump != NULL) mutex_lock(&pfk->dump_lock);
if (pfk->dump.dump != NULL) {
mutex_unlock(&pfk->dump_lock);
return -EBUSY; return -EBUSY;
}
proto = pfkey_satype2proto(hdr->sadb_msg_satype); proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0) if (proto == 0) {
mutex_unlock(&pfk->dump_lock);
return -EINVAL; return -EINVAL;
}
pfk->dump.msg_version = hdr->sadb_msg_version; pfk->dump.msg_version = hdr->sadb_msg_version;
pfk->dump.msg_pid = hdr->sadb_msg_pid; pfk->dump.msg_pid = hdr->sadb_msg_pid;
pfk->dump.dump = pfkey_dump_sa; pfk->dump.dump = pfkey_dump_sa;
pfk->dump.done = pfkey_dump_sa_done; pfk->dump.done = pfkey_dump_sa_done;
xfrm_state_walk_init(&pfk->dump.u.state, proto); xfrm_state_walk_init(&pfk->dump.u.state, proto);
mutex_unlock(&pfk->dump_lock);
return pfkey_do_dump(pfk); return pfkey_do_dump(pfk);
} }
...@@ -2661,14 +2685,18 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb ...@@ -2661,14 +2685,18 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb
{ {
struct pfkey_sock *pfk = pfkey_sk(sk); struct pfkey_sock *pfk = pfkey_sk(sk);
if (pfk->dump.dump != NULL) mutex_lock(&pfk->dump_lock);
if (pfk->dump.dump != NULL) {
mutex_unlock(&pfk->dump_lock);
return -EBUSY; return -EBUSY;
}
pfk->dump.msg_version = hdr->sadb_msg_version; pfk->dump.msg_version = hdr->sadb_msg_version;
pfk->dump.msg_pid = hdr->sadb_msg_pid; pfk->dump.msg_pid = hdr->sadb_msg_pid;
pfk->dump.dump = pfkey_dump_sp; pfk->dump.dump = pfkey_dump_sp;
pfk->dump.done = pfkey_dump_sp_done; pfk->dump.done = pfkey_dump_sp_done;
xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN);
mutex_unlock(&pfk->dump_lock);
return pfkey_do_dump(pfk); return pfkey_do_dump(pfk);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment