[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAHsH6GubMoLBzDz=-0d5t9=HkU_iGHmH_gGNj4p4y+JzddcyVw@mail.gmail.com>
Date: Tue, 8 Nov 2022 10:36:18 +0200
From: Eyal Birger <eyal.birger@...il.com>
To: Benedict Wong <benedictwong@...gle.com>
Cc: netdev@...r.kernel.org, nharold@...gle.com, lorenzo@...gle.com
Subject: Re: [PATCH ipsec] Fix XFRM-I support for nested ESP tunnels
Hi,
On Tue, Nov 8, 2022 at 4:31 AM Benedict Wong <benedictwong@...gle.com> wrote:
>
> This change adds support for nested IPsec tunnels by ensuring that
> XFRM-I verifies existing policies before decapsulating a subsequent
> policies. Addtionally, this clears the secpath entries after policies
> are verified, ensuring that previous tunnels with no-longer-valid
> do not pollute subsequent policy checks.
>
> This is necessary especially for nested tunnels, as the IP addresses,
> protocol and ports may all change, thus not matching the previous
> policies. In order to ensure that packets match the relevant inbound
> templates, the xfrm_policy_check should be done before handing off to
> the inner XFRM protocol to decrypt and decapsulate.
>
> Notably, raw ESP/AH packets did not perform policy checks inherently,
> whereas all other encapsulated packets (UDP, TCP encapsulated) do policy
> checks after calling xfrm_input handling in the respective encapsulation
> layer.
>
> Test: Verified with additional Android Kernel Unit tests
> Signed-off-by: Benedict Wong <benedictwong@...gle.com>
> ---
> net/xfrm/xfrm_interface.c | 54 ++++++++++++++++++++++++++++++++++++---
> net/xfrm/xfrm_policy.c | 5 +++-
> 2 files changed, 54 insertions(+), 5 deletions(-)
>
> diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
> index 5113fa0fbcee..0c41ed112081 100644
> --- a/net/xfrm/xfrm_interface.c
> +++ b/net/xfrm/xfrm_interface.c
> @@ -207,6 +207,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;
> @@ -774,8 +820,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,
> @@ -825,8 +871,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,
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index f1a0bab920a5..04f66f6d5729 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -3516,7 +3516,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
> int xerr_idx = -1;
> const struct xfrm_if_cb *ifcb;
> struct sec_path *sp;
> - struct xfrm_if *xi;
> + struct xfrm_if *xi = NULL;
> u32 if_id = 0;
>
> rcu_read_lock();
> @@ -3667,6 +3667,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
> goto reject;
> }
>
> + if (xi)
> + secpath_reset(skb);
> +
This is different in the current kernel. "xi" no longer exists here.
I think the equivalent check would be to see if if_id isn't zero.
Eyal.
> xfrm_pols_put(pols, npols);
> return 1;
> }
> --
> 2.38.1.431.g37b22c650d-goog
>
Powered by blists - more mailing lists