Commit c1e9dcb3 authored by Alexey Kuznetsov's avatar Alexey Kuznetsov Committed by James Morris

[IPSEC]: Semantic fixes with help from Maxim Giryaev.

- BSD apps want sin_zero cleared in sys_getname.
- Fix protocol setting in flow descriptor of RAW sockets
- Wildcard protocol is represented differently in policy
than for association.
- Missing update of key manager sequence in xfrm_state entries.
parent 32e71bf0
...@@ -722,6 +722,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -722,6 +722,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin_port = inet->sport; sin->sin_port = inet->sport;
sin->sin_addr.s_addr = addr; sin->sin_addr.s_addr = addr;
} }
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
*uaddr_len = sizeof(*sin); *uaddr_len = sizeof(*sin);
return 0; return 0;
} }
......
...@@ -430,7 +430,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ...@@ -430,7 +430,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
{ .daddr = daddr, { .daddr = daddr,
.saddr = saddr, .saddr = saddr,
.tos = tos } }, .tos = tos } },
.proto = IPPROTO_RAW }; .proto = inet->hdrincl ? IPPROTO_RAW : sk->protocol };
err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT); err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT);
} }
if (err) if (err)
......
#include <net/xfrm.h> #include <net/xfrm.h>
#include <linux/pfkeyv2.h> #include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
/* Each xfrm_state is linked to three tables: /* Each xfrm_state is linked to three tables:
...@@ -91,7 +92,7 @@ void xfrm_state_flush(u8 proto) ...@@ -91,7 +92,7 @@ void xfrm_state_flush(u8 proto)
for (i = 0; i < XFRM_DST_HSIZE; i++) { for (i = 0; i < XFRM_DST_HSIZE; i++) {
restart: restart:
list_for_each_entry(x, xfrm_state_bydst+i, bydst) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
if (!proto || x->id.proto == proto) { if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) {
atomic_inc(&x->refcnt); atomic_inc(&x->refcnt);
spin_unlock_bh(&xfrm_state_lock); spin_unlock_bh(&xfrm_state_lock);
...@@ -389,7 +390,7 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), ...@@ -389,7 +390,7 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
spin_lock_bh(&xfrm_state_lock); spin_lock_bh(&xfrm_state_lock);
for (i = 0; i < XFRM_DST_HSIZE; i++) { for (i = 0; i < XFRM_DST_HSIZE; i++) {
list_for_each_entry(x, xfrm_state_bydst+i, bydst) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
if (proto == 255 || x->id.proto == proto) if (proto == IPSEC_PROTO_ANY || x->id.proto == proto)
count++; count++;
} }
} }
...@@ -400,7 +401,7 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), ...@@ -400,7 +401,7 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
for (i = 0; i < XFRM_DST_HSIZE; i++) { for (i = 0; i < XFRM_DST_HSIZE; i++) {
list_for_each_entry(x, xfrm_state_bydst+i, bydst) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
if (proto != 255 && x->id.proto != proto) if (proto != IPSEC_PROTO_ANY && x->id.proto != proto)
continue; continue;
err = func(x, --count, data); err = func(x, --count, data);
if (err) if (err)
......
...@@ -759,7 +759,10 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, ...@@ -759,7 +759,10 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/ (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
sizeof(uint64_t); sizeof(uint64_t);
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
addr->sadb_address_proto = 0; /* XXX IPSEC_PROTO_ANY ?? */ /* "if the ports are non-zero, then the sadb_address_proto field,
normally zero, MUST be filled in with the transport
protocol's number." - RFC2367 */
addr->sadb_address_proto = 0;
addr->sadb_address_prefixlen = 32; /* XXX */ addr->sadb_address_prefixlen = 32; /* XXX */
addr->sadb_address_reserved = 0; addr->sadb_address_reserved = 0;
((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET; ((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
...@@ -772,7 +775,7 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, ...@@ -772,7 +775,7 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/ (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
sizeof(uint64_t); sizeof(uint64_t);
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0; /* XXX IPSEC_PROTO_ANY ?? */ addr->sadb_address_proto = 0;
addr->sadb_address_prefixlen = 32; /* XXX */ addr->sadb_address_prefixlen = 32; /* XXX */
addr->sadb_address_reserved = 0; addr->sadb_address_reserved = 0;
((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET; ((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
...@@ -971,6 +974,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, ...@@ -971,6 +974,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
goto out; goto out;
x->curlft.add_time = (unsigned long)xtime.tv_sec; x->curlft.add_time = (unsigned long)xtime.tv_sec;
x->km.warn_bytes = x->lft.soft_byte_limit; x->km.warn_bytes = x->lft.soft_byte_limit;
x->km.seq = hdr->sadb_msg_seq;
x->km.state = XFRM_STATE_VALID; x->km.state = XFRM_STATE_VALID;
return x; return x;
...@@ -1001,15 +1005,14 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h ...@@ -1001,15 +1005,14 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
u8 proto; u8 proto;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
!ext_hdrs[SADB_EXT_SPIRANGE-1])
return -EINVAL; return -EINVAL;
proto = pfkey_satype2proto(hdr->sadb_msg_satype); proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0) if (proto == 0)
return -EINVAL; return -EINVAL;
if ((sa2 = ext_hdrs[SADB_X_EXT_SA2]) != NULL) { if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) {
mode = sa2->sadb_x_sa2_mode - 1; mode = sa2->sadb_x_sa2_mode - 1;
reqid = sa2->sadb_x_sa2_reqid; reqid = sa2->sadb_x_sa2_reqid;
} else { } else {
...@@ -1017,9 +1020,9 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h ...@@ -1017,9 +1020,9 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
reqid = 0; reqid = 0;
} }
addr = ext_hdrs[SADB_EXT_ADDRESS_SRC]; addr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1];
saddr = (struct sockaddr_in*)(addr + 1); saddr = (struct sockaddr_in*)(addr + 1);
addr = ext_hdrs[SADB_EXT_ADDRESS_DST]; addr = ext_hdrs[SADB_EXT_ADDRESS_DST-1];
daddr = (struct sockaddr_in*)(addr + 1); daddr = (struct sockaddr_in*)(addr + 1);
x = xfrm_find_acq(mode, reqid, proto, daddr->sin_addr.s_addr, x = xfrm_find_acq(mode, reqid, proto, daddr->sin_addr.s_addr,
...@@ -1027,12 +1030,21 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h ...@@ -1027,12 +1030,21 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
if (x == NULL) if (x == NULL)
return -ENOENT; return -ENOENT;
resp_skb = NULL; resp_skb = ERR_PTR(-ENOENT);
spin_lock_bh(&x->lock); spin_lock_bh(&x->lock);
if (x->km.state != XFRM_STATE_DEAD) { if (x->km.state != XFRM_STATE_DEAD) {
struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE]; struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE-1];
xfrm_alloc_spi(x, range->sadb_spirange_min, range->sadb_spirange_max); u32 min_spi, max_spi;
if (range != NULL) {
min_spi = range->sadb_spirange_min;
max_spi = range->sadb_spirange_max;
} else {
min_spi = htonl(0x100);
max_spi = htonl(0x0fffffff);
}
xfrm_alloc_spi(x, min_spi, max_spi);
if (x->id.spi) if (x->id.spi)
resp_skb = pfkey_xfrm_state2msg(x, 0, 3); resp_skb = pfkey_xfrm_state2msg(x, 0, 3);
} }
...@@ -1113,7 +1125,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, ...@@ -1113,7 +1125,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
out_hdr = (struct sadb_msg *) out_skb->data; out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = hdr->sadb_msg_version; out_hdr->sadb_msg_version = hdr->sadb_msg_version;
out_hdr->sadb_msg_type = SADB_ADD; out_hdr->sadb_msg_type = hdr->sadb_msg_type;
out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
out_hdr->sadb_msg_errno = 0; out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_reserved = 0; out_hdr->sadb_msg_reserved = 0;
...@@ -1359,14 +1371,17 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) ...@@ -1359,14 +1371,17 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
if (rq->sadb_x_ipsecrequest_mode == 0) if (rq->sadb_x_ipsecrequest_mode == 0)
return -EINVAL; return -EINVAL;
t->id.proto = rq->sadb_x_ipsecrequest_proto; t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */
t->mode = rq->sadb_x_ipsecrequest_mode-1; t->mode = rq->sadb_x_ipsecrequest_mode-1;
t->share = rq->sadb_x_ipsecrequest_level; t->share = rq->sadb_x_ipsecrequest_level;
t->reqid = rq->sadb_x_ipsecrequest_reqid; t->reqid = rq->sadb_x_ipsecrequest_reqid;
addr = (void*)(rq+1); /* addresses present only in tunnel mode */
t->saddr.xfrm4_addr = addr->sin_addr.s_addr; if (t->mode) {
addr++; addr = (void*)(rq+1);
t->id.daddr.xfrm4_addr = addr->sin_addr.s_addr; t->saddr.xfrm4_addr = addr->sin_addr.s_addr;
addr++;
t->id.daddr.xfrm4_addr = addr->sin_addr.s_addr;
}
/* No way to set this via kame pfkey */ /* No way to set this via kame pfkey */
t->aalgos = t->ealgos = t->calgos = ~0; t->aalgos = t->ealgos = t->calgos = ~0;
xp->xfrm_nr++; xp->xfrm_nr++;
...@@ -1396,6 +1411,7 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir) ...@@ -1396,6 +1411,7 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir)
struct sadb_address *addr; struct sadb_address *addr;
struct sadb_lifetime *lifetime; struct sadb_lifetime *lifetime;
struct sadb_x_policy *pol; struct sadb_x_policy *pol;
struct sockaddr_in *sin;
int i; int i;
int size; int size;
...@@ -1414,7 +1430,6 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir) ...@@ -1414,7 +1430,6 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir)
/* call should fill header later */ /* call should fill header later */
hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
memset(hdr, 0, size); /* XXX do we need this ? */ memset(hdr, 0, size); /* XXX do we need this ? */
hdr->sadb_msg_len = size / sizeof(uint64_t);
/* src address */ /* src address */
addr = (struct sadb_address*) skb_put(skb, addr = (struct sadb_address*) skb_put(skb,
...@@ -1426,11 +1441,12 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir) ...@@ -1426,11 +1441,12 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir)
addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
addr->sadb_address_prefixlen = xp->selector.prefixlen_s; addr->sadb_address_prefixlen = xp->selector.prefixlen_s;
addr->sadb_address_reserved = 0; addr->sadb_address_reserved = 0;
((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET; /* src address */
((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = sin = (struct sockaddr_in*)(addr + 1);
xp->selector.saddr.xfrm4_addr; sin->sin_family = AF_INET;
((struct sockaddr_in*)(addr + 1))->sin_port = sin->sin_addr.s_addr = xp->selector.saddr.xfrm4_addr;
xp->selector.sport; sin->sin_port = xp->selector.sport;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
/* dst address */ /* dst address */
addr = (struct sadb_address*) skb_put(skb, addr = (struct sadb_address*) skb_put(skb,
sizeof(struct sadb_address)+sizeof(struct sockaddr_in)); sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
...@@ -1441,11 +1457,11 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir) ...@@ -1441,11 +1457,11 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir)
addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
addr->sadb_address_prefixlen = xp->selector.prefixlen_d; addr->sadb_address_prefixlen = xp->selector.prefixlen_d;
addr->sadb_address_reserved = 0; addr->sadb_address_reserved = 0;
((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET; sin = (struct sockaddr_in*)(addr + 1);
((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = sin->sin_family = AF_INET;
xp->selector.daddr.xfrm4_addr; sin->sin_addr.s_addr = xp->selector.daddr.xfrm4_addr;
((struct sockaddr_in*)(addr + 1))->sin_port = sin->sin_port = xp->selector.dport;
xp->selector.dport; memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
/* hard time */ /* hard time */
lifetime = (struct sadb_lifetime *) skb_put(skb, lifetime = (struct sadb_lifetime *) skb_put(skb,
...@@ -1494,25 +1510,34 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir) ...@@ -1494,25 +1510,34 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir)
for (i=0; i<xp->xfrm_nr; i++) { for (i=0; i<xp->xfrm_nr; i++) {
struct sadb_x_ipsecrequest *rq; struct sadb_x_ipsecrequest *rq;
struct xfrm_tmpl *t = xp->xfrm_vec + i; struct xfrm_tmpl *t = xp->xfrm_vec + i;
struct sockaddr_in *addr; int req_size;
size = sizeof(struct sadb_x_ipsecrequest)+2*sizeof(struct sockaddr_in); req_size = sizeof(struct sadb_x_ipsecrequest);
rq = (void*)skb_put(skb, size); if (t->mode)
pol->sadb_x_policy_len += size/8; req_size += 2*sizeof(struct sockaddr_in);
rq->sadb_x_ipsecrequest_len = size; else
size -= 2*sizeof(struct sockaddr_in);
rq = (void*)skb_put(skb, req_size);
pol->sadb_x_policy_len += req_size/8;
rq->sadb_x_ipsecrequest_len = req_size;
rq->sadb_x_ipsecrequest_proto = t->id.proto; rq->sadb_x_ipsecrequest_proto = t->id.proto;
rq->sadb_x_ipsecrequest_mode = t->mode+1; rq->sadb_x_ipsecrequest_mode = t->mode+1;
rq->sadb_x_ipsecrequest_level = t->share; rq->sadb_x_ipsecrequest_level = t->share;
rq->sadb_x_ipsecrequest_reqid = t->reqid; rq->sadb_x_ipsecrequest_reqid = t->reqid;
addr = (void*)(rq+1); if (t->mode) {
addr->sin_family = AF_INET; sin = (void*)(rq+1);
addr->sin_addr.s_addr = t->saddr.xfrm4_addr; sin->sin_family = AF_INET;
addr->sin_port = 0; sin->sin_addr.s_addr = t->saddr.xfrm4_addr;
addr++; sin->sin_port = 0;
addr->sin_family = AF_INET; memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
addr->sin_addr.s_addr = t->id.daddr.xfrm4_addr; sin++;
addr->sin_port = 0; sin->sin_family = AF_INET;
sin->sin_addr.s_addr = t->id.daddr.xfrm4_addr;
sin->sin_port = 0;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
}
} }
hdr->sadb_msg_len = size / sizeof(uint64_t);
return skb; return skb;
} }
...@@ -2015,7 +2040,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct ...@@ -2015,7 +2040,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/ (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
sizeof(uint64_t); sizeof(uint64_t);
addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
addr->sadb_address_proto = 0; /* XXX IPSEC_PROTO_ANY ?? */ addr->sadb_address_proto = 0;
addr->sadb_address_prefixlen = 32; addr->sadb_address_prefixlen = 32;
addr->sadb_address_reserved = 0; addr->sadb_address_reserved = 0;
((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET; ((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
...@@ -2030,7 +2055,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct ...@@ -2030,7 +2055,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/ (sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
sizeof(uint64_t); sizeof(uint64_t);
addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
addr->sadb_address_proto = 0; /* XXX IPSEC_PROTO_ANY ?? */ addr->sadb_address_proto = 0;
addr->sadb_address_prefixlen = 32; addr->sadb_address_prefixlen = 32;
addr->sadb_address_reserved = 0; addr->sadb_address_reserved = 0;
((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET; ((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
......
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