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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
12a0a6c054
@ -63,8 +63,13 @@ struct pfkey_sock {
|
||||
} u;
|
||||
struct sk_buff *skb;
|
||||
} 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)
|
||||
{
|
||||
return (struct pfkey_sock *)sk;
|
||||
@ -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 sock *sk;
|
||||
struct pfkey_sock *pfk;
|
||||
int err;
|
||||
|
||||
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,
|
||||
if (sk == NULL)
|
||||
goto out;
|
||||
|
||||
pfk = pfkey_sk(sk);
|
||||
mutex_init(&pfk->dump_lock);
|
||||
|
||||
sock->ops = &pfkey_ops;
|
||||
sock_init_data(sock, sk);
|
||||
|
||||
@ -281,13 +290,23 @@ static int pfkey_do_dump(struct pfkey_sock *pfk)
|
||||
struct sadb_msg *hdr;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&pfk->dump_lock);
|
||||
if (!pfk->dump.dump) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = pfk->dump.dump(pfk);
|
||||
if (rc == -ENOBUFS)
|
||||
return 0;
|
||||
if (rc == -ENOBUFS) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pfk->dump.skb) {
|
||||
if (!pfkey_can_dump(&pfk->sk))
|
||||
return 0;
|
||||
if (!pfkey_can_dump(&pfk->sk)) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdr = (struct sadb_msg *) pfk->dump.skb->data;
|
||||
hdr->sadb_msg_seq = 0;
|
||||
@ -298,6 +317,9 @@ static int pfkey_do_dump(struct pfkey_sock *pfk)
|
||||
}
|
||||
|
||||
pfkey_terminate_dump(pfk);
|
||||
|
||||
out:
|
||||
mutex_unlock(&pfk->dump_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -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 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;
|
||||
}
|
||||
|
||||
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
|
||||
if (proto == 0)
|
||||
if (proto == 0) {
|
||||
mutex_unlock(&pfk->dump_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (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);
|
||||
if (filter == NULL)
|
||||
if (filter == NULL) {
|
||||
mutex_unlock(&pfk->dump_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr,
|
||||
sizeof(xfrm_address_t));
|
||||
@ -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.done = pfkey_dump_sa_done;
|
||||
xfrm_state_walk_init(&pfk->dump.u.state, proto, filter);
|
||||
mutex_unlock(&pfk->dump_lock);
|
||||
|
||||
return pfkey_do_dump(pfk);
|
||||
}
|
||||
@ -1913,19 +1943,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
|
||||
|
||||
/* addresses present only in tunnel mode */
|
||||
if (t->mode == XFRM_MODE_TUNNEL) {
|
||||
u8 *sa = (u8 *) (rq + 1);
|
||||
int family, socklen;
|
||||
int err;
|
||||
|
||||
family = pfkey_sockaddr_extract((struct sockaddr *)sa,
|
||||
&t->saddr);
|
||||
if (!family)
|
||||
return -EINVAL;
|
||||
|
||||
socklen = pfkey_sockaddr_len(family);
|
||||
if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen),
|
||||
&t->id.daddr) != family)
|
||||
return -EINVAL;
|
||||
t->encap_family = family;
|
||||
err = parse_sockaddr_pair(
|
||||
(struct sockaddr *)(rq + 1),
|
||||
rq->sadb_x_ipsecrequest_len - sizeof(*rq),
|
||||
&t->saddr, &t->id.daddr, &t->encap_family);
|
||||
if (err)
|
||||
return err;
|
||||
} else
|
||||
t->encap_family = xp->family;
|
||||
|
||||
@ -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))
|
||||
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)
|
||||
return err;
|
||||
len -= rq->sadb_x_ipsecrequest_len;
|
||||
@ -2408,7 +2437,6 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_KEY_MIGRATE
|
||||
static int pfkey_sockaddr_pair_size(sa_family_t family)
|
||||
{
|
||||
return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2);
|
||||
@ -2420,7 +2448,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
|
||||
{
|
||||
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;
|
||||
|
||||
af = pfkey_sockaddr_extract(sa, saddr);
|
||||
@ -2436,6 +2464,7 @@ static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_KEY_MIGRATE
|
||||
static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
|
||||
struct xfrm_migrate *m)
|
||||
{
|
||||
@ -2443,13 +2472,14 @@ static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len,
|
||||
struct sadb_x_ipsecrequest *rq2;
|
||||
int mode;
|
||||
|
||||
if (len <= sizeof(struct sadb_x_ipsecrequest) ||
|
||||
len < rq1->sadb_x_ipsecrequest_len)
|
||||
if (len < sizeof(*rq1) ||
|
||||
len < rq1->sadb_x_ipsecrequest_len ||
|
||||
rq1->sadb_x_ipsecrequest_len < sizeof(*rq1))
|
||||
return -EINVAL;
|
||||
|
||||
/* old endoints */
|
||||
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_family);
|
||||
if (err)
|
||||
@ -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);
|
||||
len -= rq1->sadb_x_ipsecrequest_len;
|
||||
|
||||
if (len <= sizeof(struct sadb_x_ipsecrequest) ||
|
||||
len < rq2->sadb_x_ipsecrequest_len)
|
||||
if (len <= sizeof(*rq2) ||
|
||||
len < rq2->sadb_x_ipsecrequest_len ||
|
||||
rq2->sadb_x_ipsecrequest_len < sizeof(*rq2))
|
||||
return -EINVAL;
|
||||
|
||||
/* new endpoints */
|
||||
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_family);
|
||||
if (err)
|
||||
@ -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);
|
||||
|
||||
if (pfk->dump.dump != NULL)
|
||||
mutex_lock(&pfk->dump_lock);
|
||||
if (pfk->dump.dump != NULL) {
|
||||
mutex_unlock(&pfk->dump_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pfk->dump.msg_version = hdr->sadb_msg_version;
|
||||
pfk->dump.msg_portid = hdr->sadb_msg_pid;
|
||||
pfk->dump.dump = pfkey_dump_sp;
|
||||
pfk->dump.done = pfkey_dump_sp_done;
|
||||
xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN);
|
||||
mutex_unlock(&pfk->dump_lock);
|
||||
|
||||
return pfkey_do_dump(pfk);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user