Commit e438edaa authored by David S. Miller's avatar David S. Miller

Merge tag 'ipsec-2023-06-20' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec

ipsec-2023-06-20
parents 440d71e2 f015b900
...@@ -1054,6 +1054,7 @@ struct xfrm_offload { ...@@ -1054,6 +1054,7 @@ struct xfrm_offload {
struct sec_path { struct sec_path {
int len; int len;
int olen; int olen;
int verified_cnt;
struct xfrm_state *xvec[XFRM_MAX_DEPTH]; struct xfrm_state *xvec[XFRM_MAX_DEPTH];
struct xfrm_offload ovec[XFRM_MAX_OFFLOAD_DEPTH]; struct xfrm_offload ovec[XFRM_MAX_OFFLOAD_DEPTH];
......
...@@ -340,6 +340,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_ ...@@ -340,6 +340,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
secpath_reset(skb); secpath_reset(skb);
if (skb_needs_linearize(skb, skb->dev->features) &&
__skb_linearize(skb))
return -ENOMEM;
return 0; return 0;
} }
......
...@@ -164,6 +164,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -164,6 +164,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
EXPORT_SYMBOL(xfrm4_udp_encap_rcv);
int xfrm4_rcv(struct sk_buff *skb) int xfrm4_rcv(struct sk_buff *skb)
{ {
......
...@@ -374,6 +374,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features ...@@ -374,6 +374,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
secpath_reset(skb); secpath_reset(skb);
if (skb_needs_linearize(skb, skb->dev->features) &&
__skb_linearize(skb))
return -ENOMEM;
return 0; return 0;
} }
......
...@@ -86,6 +86,9 @@ int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -86,6 +86,9 @@ int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
__be32 *udpdata32; __be32 *udpdata32;
__u16 encap_type = up->encap_type; __u16 encap_type = up->encap_type;
if (skb->protocol == htons(ETH_P_IP))
return xfrm4_udp_encap_rcv(sk, skb);
/* if this is not encapsulated socket, then just return now */ /* if this is not encapsulated socket, then just return now */
if (!encap_type) if (!encap_type)
return 1; return 1;
......
...@@ -131,6 +131,7 @@ struct sec_path *secpath_set(struct sk_buff *skb) ...@@ -131,6 +131,7 @@ struct sec_path *secpath_set(struct sk_buff *skb)
memset(sp->ovec, 0, sizeof(sp->ovec)); memset(sp->ovec, 0, sizeof(sp->ovec));
sp->olen = 0; sp->olen = 0;
sp->len = 0; sp->len = 0;
sp->verified_cnt = 0;
return sp; return sp;
} }
...@@ -330,11 +331,10 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x, ...@@ -330,11 +331,10 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
{ {
switch (x->props.mode) { switch (x->props.mode) {
case XFRM_MODE_BEET: case XFRM_MODE_BEET:
switch (XFRM_MODE_SKB_CB(skb)->protocol) { switch (x->sel.family) {
case IPPROTO_IPIP: case AF_INET:
case IPPROTO_BEETPH:
return xfrm4_remove_beet_encap(x, skb); return xfrm4_remove_beet_encap(x, skb);
case IPPROTO_IPV6: case AF_INET6:
return xfrm6_remove_beet_encap(x, skb); return xfrm6_remove_beet_encap(x, skb);
} }
break; break;
......
...@@ -310,6 +310,52 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet) ...@@ -310,6 +310,52 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
skb->mark = 0; skb->mark = 0;
} }
static int xfrmi_input(struct sk_buff *skb, int nexthdr, __be32 spi,
int encap_type, unsigned short family)
{
struct sec_path *sp;
sp = skb_sec_path(skb);
if (sp && (sp->len || sp->olen) &&
!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
goto discard;
XFRM_SPI_SKB_CB(skb)->family = family;
if (family == AF_INET) {
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
} else {
XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr);
XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
}
return xfrm_input(skb, nexthdr, spi, encap_type);
discard:
kfree_skb(skb);
return 0;
}
static int xfrmi4_rcv(struct sk_buff *skb)
{
return xfrmi_input(skb, ip_hdr(skb)->protocol, 0, 0, AF_INET);
}
static int xfrmi6_rcv(struct sk_buff *skb)
{
return xfrmi_input(skb, skb_network_header(skb)[IP6CB(skb)->nhoff],
0, 0, AF_INET6);
}
static int xfrmi4_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET);
}
static int xfrmi6_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET6);
}
static int xfrmi_rcv_cb(struct sk_buff *skb, int err) static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
{ {
const struct xfrm_mode *inner_mode; const struct xfrm_mode *inner_mode;
...@@ -945,8 +991,8 @@ static struct pernet_operations xfrmi_net_ops = { ...@@ -945,8 +991,8 @@ static struct pernet_operations xfrmi_net_ops = {
}; };
static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = { static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
.handler = xfrm6_rcv, .handler = xfrmi6_rcv,
.input_handler = xfrm_input, .input_handler = xfrmi6_input,
.cb_handler = xfrmi_rcv_cb, .cb_handler = xfrmi_rcv_cb,
.err_handler = xfrmi6_err, .err_handler = xfrmi6_err,
.priority = 10, .priority = 10,
...@@ -996,8 +1042,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = { ...@@ -996,8 +1042,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
#endif #endif
static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = { static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
.handler = xfrm4_rcv, .handler = xfrmi4_rcv,
.input_handler = xfrm_input, .input_handler = xfrmi4_input,
.cb_handler = xfrmi_rcv_cb, .cb_handler = xfrmi_rcv_cb,
.err_handler = xfrmi4_err, .err_handler = xfrmi4_err,
.priority = 10, .priority = 10,
......
...@@ -1831,6 +1831,7 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid) ...@@ -1831,6 +1831,7 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_dev_policy_delete(pol);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
...@@ -1869,6 +1870,7 @@ int xfrm_dev_policy_flush(struct net *net, struct net_device *dev, ...@@ -1869,6 +1870,7 @@ int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_dev_policy_delete(pol);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
...@@ -3349,6 +3351,13 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star ...@@ -3349,6 +3351,13 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id)) if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id))
return ++idx; return ++idx;
if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
if (idx < sp->verified_cnt) {
/* Secpath entry previously verified, consider optional and
* continue searching
*/
continue;
}
if (start == -1) if (start == -1)
start = -2-idx; start = -2-idx;
break; break;
...@@ -3723,6 +3732,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -3723,6 +3732,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
* Order is _important_. Later we will implement * Order is _important_. Later we will implement
* some barriers, but at the moment barriers * some barriers, but at the moment barriers
* are implied between each two transformations. * are implied between each two transformations.
* Upon success, marks secpath entries as having been
* verified to allow them to be skipped in future policy
* checks (e.g. nested tunnels).
*/ */
for (i = xfrm_nr-1, k = 0; i >= 0; i--) { for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
k = xfrm_policy_ok(tpp[i], sp, k, family, if_id); k = xfrm_policy_ok(tpp[i], sp, k, family, if_id);
...@@ -3741,6 +3753,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -3741,6 +3753,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
} }
xfrm_pols_put(pols, npols); xfrm_pols_put(pols, npols);
sp->verified_cnt = k;
return 1; return 1;
} }
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);
......
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