Commit 12a0a6c0 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec

Steffen Klassert says:

====================
pull request (net): ipsec 2017-04-19

Two fixes for af_key:

1) Add a lock to key dump to prevent a NULL pointer dereference.
   From Yuejie Shi.

2) Fix slab-out-of-bounds in parse_ipsecrequests.
   From Herbert Xu.

Please pull or let me know if there are problems.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9d386cd9 096f41d3
...@@ -63,8 +63,13 @@ struct pfkey_sock { ...@@ -63,8 +63,13 @@ struct pfkey_sock {
} u; } u;
struct sk_buff *skb; struct sk_buff *skb;
} dump; } dump;
struct mutex dump_lock;
}; };
static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
xfrm_address_t *saddr, xfrm_address_t *daddr,
u16 *family);
static inline struct pfkey_sock *pfkey_sk(struct sock *sk) static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
{ {
return (struct pfkey_sock *)sk; return (struct pfkey_sock *)sk;
...@@ -139,6 +144,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, ...@@ -139,6 +144,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 (!ns_capable(net->user_ns, CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
...@@ -153,6 +159,9 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol, ...@@ -153,6 +159,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);
...@@ -281,13 +290,23 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) ...@@ -281,13 +290,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;
...@@ -298,6 +317,9 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) ...@@ -298,6 +317,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;
} }
...@@ -1793,19 +1815,26 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms ...@@ -1793,19 +1815,26 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms
struct xfrm_address_filter *filter = NULL; struct xfrm_address_filter *filter = NULL;
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;
}
if (ext_hdrs[SADB_X_EXT_FILTER - 1]) { if (ext_hdrs[SADB_X_EXT_FILTER - 1]) {
struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1]; struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1];
filter = kmalloc(sizeof(*filter), GFP_KERNEL); filter = kmalloc(sizeof(*filter), GFP_KERNEL);
if (filter == NULL) if (filter == NULL) {
mutex_unlock(&pfk->dump_lock);
return -ENOMEM; return -ENOMEM;
}
memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr, memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr,
sizeof(xfrm_address_t)); sizeof(xfrm_address_t));
...@@ -1821,6 +1850,7 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms ...@@ -1821,6 +1850,7 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms
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, filter); xfrm_state_walk_init(&pfk->dump.u.state, proto, filter);
mutex_unlock(&pfk->dump_lock);
return pfkey_do_dump(pfk); return pfkey_do_dump(pfk);
} }
...@@ -1913,19 +1943,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) ...@@ -1913,19 +1943,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
/* addresses present only in tunnel mode */ /* addresses present only in tunnel mode */
if (t->mode == XFRM_MODE_TUNNEL) { if (t->mode == XFRM_MODE_TUNNEL) {
u8 *sa = (u8 *) (rq + 1); int err;
int family, socklen;
family = pfkey_sockaddr_extract((struct sockaddr *)sa, err = parse_sockaddr_pair(
&t->saddr); (struct sockaddr *)(rq + 1),
if (!family) rq->sadb_x_ipsecrequest_len - sizeof(*rq),
return -EINVAL; &t->saddr, &t->id.daddr, &t->encap_family);
if (err)
socklen = pfkey_sockaddr_len(family); return err;
if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
&t->id.daddr) != family)
return -EINVAL;
t->encap_family = family;
} else } else
t->encap_family = xp->family; t->encap_family = xp->family;
...@@ -1945,7 +1970,11 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) ...@@ -1945,7 +1970,11 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
if (pol->sadb_x_policy_len * 8 < sizeof(struct sadb_x_policy)) if (pol->sadb_x_policy_len * 8 < sizeof(struct sadb_x_policy))
return -EINVAL; return -EINVAL;
while (len >= sizeof(struct sadb_x_ipsecrequest)) { while (len >= sizeof(*rq)) {
if (len < rq->sadb_x_ipsecrequest_len ||
rq->sadb_x_ipsecrequest_len < sizeof(*rq))
return -EINVAL;
if ((err = parse_ipsecrequest(xp, rq)) < 0) if ((err = parse_ipsecrequest(xp, rq)) < 0)
return err; return err;
len -= rq->sadb_x_ipsecrequest_len; len -= rq->sadb_x_ipsecrequest_len;
...@@ -2408,7 +2437,6 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc ...@@ -2408,7 +2437,6 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
return err; return err;
} }
#ifdef CONFIG_NET_KEY_MIGRATE
static int pfkey_sockaddr_pair_size(sa_family_t family) static int pfkey_sockaddr_pair_size(sa_family_t family)
{ {
return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
...@@ -2420,7 +2448,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, ...@@ -2420,7 +2448,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
{ {
int af, socklen; int af, socklen;
if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) if (ext_len < 2 || ext_len < pfkey_sockaddr_pair_size(sa->sa_family))
return -EINVAL; return -EINVAL;
af = pfkey_sockaddr_extract(sa, saddr); af = pfkey_sockaddr_extract(sa, saddr);
...@@ -2436,6 +2464,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, ...@@ -2436,6 +2464,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
return 0; return 0;
} }
#ifdef CONFIG_NET_KEY_MIGRATE
static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
struct xfrm_migrate *m) struct xfrm_migrate *m)
{ {
...@@ -2443,13 +2472,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, ...@@ -2443,13 +2472,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
struct sadb_x_ipsecrequest *rq2; struct sadb_x_ipsecrequest *rq2;
int mode; int mode;
if (len <= sizeof(struct sadb_x_ipsecrequest) || if (len < sizeof(*rq1) ||
len < rq1->sadb_x_ipsecrequest_len) len < rq1->sadb_x_ipsecrequest_len ||
rq1->sadb_x_ipsecrequest_len < sizeof(*rq1))
return -EINVAL; return -EINVAL;
/* old endoints */ /* old endoints */
err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1),
rq1->sadb_x_ipsecrequest_len, rq1->sadb_x_ipsecrequest_len - sizeof(*rq1),
&m->old_saddr, &m->old_daddr, &m->old_saddr, &m->old_daddr,
&m->old_family); &m->old_family);
if (err) if (err)
...@@ -2458,13 +2488,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, ...@@ -2458,13 +2488,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len);
len -= rq1->sadb_x_ipsecrequest_len; len -= rq1->sadb_x_ipsecrequest_len;
if (len <= sizeof(struct sadb_x_ipsecrequest) || if (len <= sizeof(*rq2) ||
len < rq2->sadb_x_ipsecrequest_len) len < rq2->sadb_x_ipsecrequest_len ||
rq2->sadb_x_ipsecrequest_len < sizeof(*rq2))
return -EINVAL; return -EINVAL;
/* new endpoints */ /* new endpoints */
err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1),
rq2->sadb_x_ipsecrequest_len, rq2->sadb_x_ipsecrequest_len - sizeof(*rq2),
&m->new_saddr, &m->new_daddr, &m->new_saddr, &m->new_daddr,
&m->new_family); &m->new_family);
if (err) if (err)
...@@ -2679,14 +2710,18 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb ...@@ -2679,14 +2710,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_portid = hdr->sadb_msg_pid; pfk->dump.msg_portid = 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