Merge tag 'ipsec-2023-06-20' of git://git.kernel.org/pub/scm/linux/kernel/git/klasser...
authorDavid S. Miller <davem@davemloft.net>
Tue, 20 Jun 2023 12:33:50 +0000 (13:33 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 20 Jun 2023 12:33:50 +0000 (13:33 +0100)
ipsec-2023-06-20

include/net/xfrm.h
net/ipv4/esp4_offload.c
net/ipv4/xfrm4_input.c
net/ipv6/esp6_offload.c
net/ipv6/xfrm6_input.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_interface_core.c
net/xfrm/xfrm_policy.c

index 33ee3f5936e6959ba8e27c08a5134428d96f3a01..151ca95dd08db32b7cf6db46ad441471dfffbc16 100644 (file)
@@ -1054,6 +1054,7 @@ struct xfrm_offload {
 struct sec_path {
        int                     len;
        int                     olen;
+       int                     verified_cnt;
 
        struct xfrm_state       *xvec[XFRM_MAX_DEPTH];
        struct xfrm_offload     ovec[XFRM_MAX_OFFLOAD_DEPTH];
index 3969fa805679cd25f373526f5a7d0b7be7172040..ee848be59e65a7d8f90a6bd09c61732152fad68c 100644 (file)
@@ -340,6 +340,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb,  netdev_features_
 
        secpath_reset(skb);
 
+       if (skb_needs_linearize(skb, skb->dev->features) &&
+           __skb_linearize(skb))
+               return -ENOMEM;
        return 0;
 }
 
index ad2afeef4f106b713d659bb94e7215b6e9226f9b..eac206a290d05930c97f572e55ec0c26f3fefad0 100644 (file)
@@ -164,6 +164,7 @@ drop:
        kfree_skb(skb);
        return 0;
 }
+EXPORT_SYMBOL(xfrm4_udp_encap_rcv);
 
 int xfrm4_rcv(struct sk_buff *skb)
 {
index 75c02992c520f94e1f53de89ea6463acc842c331..7723402689973f236ae96e159eddc6ea2ea09559 100644 (file)
@@ -374,6 +374,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb,  netdev_features
 
        secpath_reset(skb);
 
+       if (skb_needs_linearize(skb, skb->dev->features) &&
+           __skb_linearize(skb))
+               return -ENOMEM;
        return 0;
 }
 
index 04cbeefd8982898e690a12a9eff9a966d77c08e7..4907ab241d6bedf9ecfaa02017178e13fef4b980 100644 (file)
@@ -86,6 +86,9 @@ int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
        __be32 *udpdata32;
        __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 (!encap_type)
                return 1;
index 39fb91ff23d96d3507b8cea9b2c73bc0defb8e5c..815b380804011021d1783094cc90ecc6f3ed6aa4 100644 (file)
@@ -131,6 +131,7 @@ struct sec_path *secpath_set(struct sk_buff *skb)
        memset(sp->ovec, 0, sizeof(sp->ovec));
        sp->olen = 0;
        sp->len = 0;
+       sp->verified_cnt = 0;
 
        return sp;
 }
@@ -330,11 +331,10 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
 {
        switch (x->props.mode) {
        case XFRM_MODE_BEET:
-               switch (XFRM_MODE_SKB_CB(skb)->protocol) {
-               case IPPROTO_IPIP:
-               case IPPROTO_BEETPH:
+               switch (x->sel.family) {
+               case AF_INET:
                        return xfrm4_remove_beet_encap(x, skb);
-               case IPPROTO_IPV6:
+               case AF_INET6:
                        return xfrm6_remove_beet_encap(x, skb);
                }
                break;
index 1f99dc46902719e6716b0cb93f95d1087d2c8bd8..35279c220bd786750da0ead2765a99b290539c5d 100644 (file)
@@ -310,6 +310,52 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
        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)
 {
        const struct xfrm_mode *inner_mode;
@@ -945,8 +991,8 @@ static struct pernet_operations xfrmi_net_ops = {
 };
 
 static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
-       .handler        =       xfrm6_rcv,
-       .input_handler  =       xfrm_input,
+       .handler        =       xfrmi6_rcv,
+       .input_handler  =       xfrmi6_input,
        .cb_handler     =       xfrmi_rcv_cb,
        .err_handler    =       xfrmi6_err,
        .priority       =       10,
@@ -996,8 +1042,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
 #endif
 
 static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
-       .handler        =       xfrm4_rcv,
-       .input_handler  =       xfrm_input,
+       .handler        =       xfrmi4_rcv,
+       .input_handler  =       xfrmi4_input,
        .cb_handler     =       xfrmi_rcv_cb,
        .err_handler    =       xfrmi4_err,
        .priority       =       10,
index 6d15788b512315f030899998354a7c8f4edc4e8c..e7617c9959c311f14e04bfddaa00019df91a812a 100644 (file)
@@ -1831,6 +1831,7 @@ again:
 
                __xfrm_policy_unlink(pol, dir);
                spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
+               xfrm_dev_policy_delete(pol);
                cnt++;
                xfrm_audit_policy_delete(pol, 1, task_valid);
                xfrm_policy_kill(pol);
@@ -1869,6 +1870,7 @@ again:
 
                __xfrm_policy_unlink(pol, dir);
                spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
+               xfrm_dev_policy_delete(pol);
                cnt++;
                xfrm_audit_policy_delete(pol, 1, task_valid);
                xfrm_policy_kill(pol);
@@ -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))
                        return ++idx;
                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)
                                start = -2-idx;
                        break;
@@ -3723,6 +3732,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                 * Order is _important_. Later we will implement
                 * some barriers, but at the moment barriers
                 * 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--) {
                        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,
                }
 
                xfrm_pols_put(pols, npols);
+               sp->verified_cnt = k;
+
                return 1;
        }
        XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK);