Merge tag 'ipsec-2023-05-16' of git://git.kernel.org/pub/scm/linux/kernel/git/klasser...
authorJakub Kicinski <kuba@kernel.org>
Wed, 17 May 2023 03:52:34 +0000 (20:52 -0700)
committerJakub Kicinski <kuba@kernel.org>
Wed, 17 May 2023 03:52:35 +0000 (20:52 -0700)
Steffen Klassert says:

====================
pull request (net): ipsec 2023-05-16

1) Don't check the policy default if we have an allow
   policy. Fix from Sabrina Dubroca.

2) Fix netdevice refount usage on offload.
   From Leon Romanovsky.

3) Use netdev_put instead of dev_puti to correctly release
   the netdev on failure in xfrm_dev_policy_add.
   From Leon Romanovsky.

4) Revert "Fix XFRM-I support for nested ESP tunnels"
   This broke Netfilter policy matching.
   From Martin Willi.

5) Reject optional tunnel/BEET mode templates in outbound policies
   on netlink and pfkey sockets. From Tobias Brunner.

6) Check if_id in inbound policy/secpath match to make
   it symetric to the outbound codepath.
   From Benedict Wong.

* tag 'ipsec-2023-05-16' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec:
  xfrm: Check if_id in inbound policy/secpath match
  af_key: Reject optional tunnel/BEET mode templates in outbound policies
  xfrm: Reject optional tunnel/BEET mode templates in outbound policies
  Revert "Fix XFRM-I support for nested ESP tunnels"
  xfrm: Fix leak of dev tracker
  xfrm: release all offloaded policy memory
  xfrm: don't check the default policy if the policy allows the packet
====================

Link: https://lore.kernel.org/r/20230516052405.2677554-1-steffen.klassert@secunet.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/key/af_key.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_interface_core.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c

index a815f5ab4c49a08a51f7ae5e1200e589621799e8..31ab12fd720aefdab9e3eced63d2a37d169516f9 100644 (file)
@@ -1940,7 +1940,8 @@ static u32 gen_reqid(struct net *net)
 }
 
 static int
-parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
+parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_policy *pol,
+                  struct sadb_x_ipsecrequest *rq)
 {
        struct net *net = xp_net(xp);
        struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
@@ -1958,9 +1959,12 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
        if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0)
                return -EINVAL;
        t->mode = mode;
-       if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
+       if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) {
+               if ((mode == XFRM_MODE_TUNNEL || mode == XFRM_MODE_BEET) &&
+                   pol->sadb_x_policy_dir == IPSEC_DIR_OUTBOUND)
+                       return -EINVAL;
                t->optional = 1;
-       else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
+       else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) {
                t->reqid = rq->sadb_x_ipsecrequest_reqid;
                if (t->reqid > IPSEC_MANUAL_REQID_MAX)
                        t->reqid = 0;
@@ -2002,7 +2006,7 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
                    rq->sadb_x_ipsecrequest_len < sizeof(*rq))
                        return -EINVAL;
 
-               if ((err = parse_ipsecrequest(xp, rq)) < 0)
+               if ((err = parse_ipsecrequest(xp, pol, rq)) < 0)
                        return err;
                len -= rq->sadb_x_ipsecrequest_len;
                rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len);
index bef28c6187ebdd0cfc34c8594aab96ac0b13dd24..408f5e55744edd1c865fe679da6bc43e4413f2db 100644 (file)
@@ -378,7 +378,7 @@ int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
                break;
        default:
                xdo->dev = NULL;
-               dev_put(dev);
+               netdev_put(dev, &xdo->dev_tracker);
                NL_SET_ERR_MSG(extack, "Unrecognized offload direction");
                return -EINVAL;
        }
index 35279c220bd786750da0ead2765a99b290539c5d..1f99dc46902719e6716b0cb93f95d1087d2c8bd8 100644 (file)
@@ -310,52 +310,6 @@ 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;
@@ -991,8 +945,8 @@ static struct pernet_operations xfrmi_net_ops = {
 };
 
 static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
-       .handler        =       xfrmi6_rcv,
-       .input_handler  =       xfrmi6_input,
+       .handler        =       xfrm6_rcv,
+       .input_handler  =       xfrm_input,
        .cb_handler     =       xfrmi_rcv_cb,
        .err_handler    =       xfrmi6_err,
        .priority       =       10,
@@ -1042,8 +996,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
 #endif
 
 static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
-       .handler        =       xfrmi4_rcv,
-       .input_handler  =       xfrmi4_input,
+       .handler        =       xfrm4_rcv,
+       .input_handler  =       xfrm_input,
        .cb_handler     =       xfrmi_rcv_cb,
        .err_handler    =       xfrmi4_err,
        .priority       =       10,
index 5c61ec04b839ba1e0c7da13d96f9804c04b71f53..6d15788b512315f030899998354a7c8f4edc4e8c 100644 (file)
@@ -3312,7 +3312,7 @@ xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl)
 
 static inline int
 xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
-             unsigned short family)
+             unsigned short family, u32 if_id)
 {
        if (xfrm_state_kern(x))
                return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
@@ -3323,7 +3323,8 @@ xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
                (tmpl->allalgs || (tmpl->aalgos & (1<<x->props.aalgo)) ||
                 !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) &&
                !(x->props.mode != XFRM_MODE_TRANSPORT &&
-                 xfrm_state_addr_cmp(tmpl, x, family));
+                 xfrm_state_addr_cmp(tmpl, x, family)) &&
+               (if_id == 0 || if_id == x->if_id);
 }
 
 /*
@@ -3335,7 +3336,7 @@ xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x,
  */
 static inline int
 xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start,
-              unsigned short family)
+              unsigned short family, u32 if_id)
 {
        int idx = start;
 
@@ -3345,7 +3346,7 @@ xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int star
        } else
                start = -1;
        for (; idx < sp->len; idx++) {
-               if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
+               if (xfrm_state_ok(tmpl, sp->xvec[idx], family, if_id))
                        return ++idx;
                if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) {
                        if (start == -1)
@@ -3712,12 +3713,6 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                }
                xfrm_nr = ti;
 
-               if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK &&
-                   !xfrm_nr) {
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
-                       goto reject;
-               }
-
                if (npols > 1) {
                        xfrm_tmpl_sort(stp, tpp, xfrm_nr, family);
                        tpp = stp;
@@ -3730,7 +3725,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                 * are implied between each two transformations.
                 */
                for (i = xfrm_nr-1, k = 0; i >= 0; i--) {
-                       k = xfrm_policy_ok(tpp[i], sp, k, family);
+                       k = xfrm_policy_ok(tpp[i], sp, k, family, if_id);
                        if (k < 0) {
                                if (k < -1)
                                        /* "-2 - errored_index" returned */
@@ -3745,9 +3740,6 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                        goto reject;
                }
 
-               if (if_id)
-                       secpath_reset(skb);
-
                xfrm_pols_put(pols, npols);
                return 1;
        }
index d720e163ae6e5efb8342402f59be0db284fb0663..c34a2a06ca9407230ab66426bf14e39fd04637f4 100644 (file)
@@ -1770,7 +1770,7 @@ static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
 }
 
 static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
-                        struct netlink_ext_ack *extack)
+                        int dir, struct netlink_ext_ack *extack)
 {
        u16 prev_family;
        int i;
@@ -1796,6 +1796,10 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
                switch (ut[i].mode) {
                case XFRM_MODE_TUNNEL:
                case XFRM_MODE_BEET:
+                       if (ut[i].optional && dir == XFRM_POLICY_OUT) {
+                               NL_SET_ERR_MSG(extack, "Mode in optional template not allowed in outbound policy");
+                               return -EINVAL;
+                       }
                        break;
                default:
                        if (ut[i].family != prev_family) {
@@ -1833,7 +1837,7 @@ static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family,
 }
 
 static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs,
-                              struct netlink_ext_ack *extack)
+                              int dir, struct netlink_ext_ack *extack)
 {
        struct nlattr *rt = attrs[XFRMA_TMPL];
 
@@ -1844,7 +1848,7 @@ static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs,
                int nr = nla_len(rt) / sizeof(*utmpl);
                int err;
 
-               err = validate_tmpl(nr, utmpl, pol->family, extack);
+               err = validate_tmpl(nr, utmpl, pol->family, dir, extack);
                if (err)
                        return err;
 
@@ -1921,7 +1925,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net,
        if (err)
                goto error;
 
-       if (!(err = copy_from_user_tmpl(xp, attrs, extack)))
+       if (!(err = copy_from_user_tmpl(xp, attrs, p->dir, extack)))
                err = copy_from_user_sec_ctx(xp, attrs);
        if (err)
                goto error;
@@ -1980,6 +1984,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        if (err) {
                xfrm_dev_policy_delete(xp);
+               xfrm_dev_policy_free(xp);
                security_xfrm_policy_free(xp->security);
                kfree(xp);
                return err;
@@ -3499,7 +3504,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
                return NULL;
 
        nr = ((len - sizeof(*p)) / sizeof(*ut));
-       if (validate_tmpl(nr, ut, p->sel.family, NULL))
+       if (validate_tmpl(nr, ut, p->sel.family, p->dir, NULL))
                return NULL;
 
        if (p->dir > XFRM_POLICY_OUT)