aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2022-01-09 16:59:30 -0800
committerJakub Kicinski <kuba@kernel.org>2022-01-09 17:00:17 -0800
commit8aaaf2f3af2ae212428f4db1af34214225f5cec3 (patch)
tree43c7f4f8af2fad7919f169b0924dba5e43147d97 /net/xfrm
parenttcp: tcp_send_challenge_ack delete useless param `skb` (diff)
parentamt: fix wrong return type of amt_send_membership_update() (diff)
downloadlinux-dev-8aaaf2f3af2ae212428f4db1af34214225f5cec3.tar.xz
linux-dev-8aaaf2f3af2ae212428f4db1af34214225f5cec3.zip
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Merge in fixes directly in prep for the 5.17 merge window. No conflicts. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_interface.c14
-rw-r--r--net/xfrm/xfrm_output.c30
-rw-r--r--net/xfrm/xfrm_policy.c21
-rw-r--r--net/xfrm/xfrm_user.c23
4 files changed, 77 insertions, 11 deletions
diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
index 41de46b5ffa9..57448fc519fc 100644
--- a/net/xfrm/xfrm_interface.c
+++ b/net/xfrm/xfrm_interface.c
@@ -637,11 +637,16 @@ static int xfrmi_newlink(struct net *src_net, struct net_device *dev,
struct netlink_ext_ack *extack)
{
struct net *net = dev_net(dev);
- struct xfrm_if_parms p;
+ struct xfrm_if_parms p = {};
struct xfrm_if *xi;
int err;
xfrmi_netlink_parms(data, &p);
+ if (!p.if_id) {
+ NL_SET_ERR_MSG(extack, "if_id must be non zero");
+ return -EINVAL;
+ }
+
xi = xfrmi_locate(net, &p);
if (xi)
return -EEXIST;
@@ -666,7 +671,12 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
{
struct xfrm_if *xi = netdev_priv(dev);
struct net *net = xi->net;
- struct xfrm_if_parms p;
+ struct xfrm_if_parms p = {};
+
+ if (!p.if_id) {
+ NL_SET_ERR_MSG(extack, "if_id must be non zero");
+ return -EINVAL;
+ }
xfrmi_netlink_parms(data, &p);
xi = xfrmi_locate(net, &p);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 3585bfc302f9..d4935b3b9983 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -648,10 +648,12 @@ static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb
* This requires hardware to know the inner packet type to calculate
* the inner header checksum. Save inner ip protocol here to avoid
* traversing the packet in the vendor's xmit code.
- * If the encap type is IPIP, just save skb->inner_ipproto. Otherwise,
- * get the ip protocol from the IP header.
+ * For IPsec tunnel mode save the ip protocol from the IP header of the
+ * plain text packet. Otherwise If the encap type is IPIP, just save
+ * skb->inner_ipproto in any other case get the ip protocol from the IP
+ * header.
*/
-static void xfrm_get_inner_ipproto(struct sk_buff *skb)
+static void xfrm_get_inner_ipproto(struct sk_buff *skb, struct xfrm_state *x)
{
struct xfrm_offload *xo = xfrm_offload(skb);
const struct ethhdr *eth;
@@ -659,6 +661,25 @@ static void xfrm_get_inner_ipproto(struct sk_buff *skb)
if (!xo)
return;
+ if (x->outer_mode.encap == XFRM_MODE_TUNNEL) {
+ switch (x->outer_mode.family) {
+ case AF_INET:
+ xo->inner_ipproto = ip_hdr(skb)->protocol;
+ break;
+ case AF_INET6:
+ xo->inner_ipproto = ipv6_hdr(skb)->nexthdr;
+ break;
+ default:
+ break;
+ }
+
+ return;
+ }
+
+ /* non-Tunnel Mode */
+ if (!skb->encapsulation)
+ return;
+
if (skb->inner_protocol_type == ENCAP_TYPE_IPPROTO) {
xo->inner_ipproto = skb->inner_ipproto;
return;
@@ -713,8 +734,7 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
sp->xvec[sp->len++] = x;
xfrm_state_hold(x);
- if (skb->encapsulation)
- xfrm_get_inner_ipproto(skb);
+ xfrm_get_inner_ipproto(skb, x);
skb->encapsulation = 1;
if (skb_is_gso(skb)) {
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9341298b2a70..dccb8f3318ef 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -33,6 +33,7 @@
#include <net/flow.h>
#include <net/xfrm.h>
#include <net/ip.h>
+#include <net/gre.h>
#if IS_ENABLED(CONFIG_IPV6_MIP6)
#include <net/mip6.h>
#endif
@@ -3421,6 +3422,26 @@ decode_session6(struct sk_buff *skb, struct flowi *fl, bool reverse)
}
fl6->flowi6_proto = nexthdr;
return;
+ case IPPROTO_GRE:
+ if (!onlyproto &&
+ (nh + offset + 12 < skb->data ||
+ pskb_may_pull(skb, nh + offset + 12 - skb->data))) {
+ struct gre_base_hdr *gre_hdr;
+ __be32 *gre_key;
+
+ nh = skb_network_header(skb);
+ gre_hdr = (struct gre_base_hdr *)(nh + offset);
+ gre_key = (__be32 *)(gre_hdr + 1);
+
+ if (gre_hdr->flags & GRE_KEY) {
+ if (gre_hdr->flags & GRE_CSUM)
+ gre_key++;
+ fl6->fl6_gre_key = *gre_key;
+ }
+ }
+ fl6->flowi6_proto = nexthdr;
+ return;
+
#if IS_ENABLED(CONFIG_IPV6_MIP6)
case IPPROTO_MH:
offset += ipv6_optlen(exthdr);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 6228c0089b78..8cd6c8129004 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -630,8 +630,13 @@ static struct xfrm_state *xfrm_state_construct(struct net *net,
xfrm_smark_init(attrs, &x->props.smark);
- if (attrs[XFRMA_IF_ID])
+ if (attrs[XFRMA_IF_ID]) {
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+ if (!x->if_id) {
+ err = -EINVAL;
+ goto error;
+ }
+ }
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
if (err)
@@ -1427,8 +1432,13 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
mark = xfrm_mark_get(attrs, &m);
- if (attrs[XFRMA_IF_ID])
+ if (attrs[XFRMA_IF_ID]) {
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+ if (!if_id) {
+ err = -EINVAL;
+ goto out_noput;
+ }
+ }
if (p->info.seq) {
x = xfrm_find_acq_byseq(net, mark, p->info.seq);
@@ -1741,8 +1751,13 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us
xfrm_mark_get(attrs, &xp->mark);
- if (attrs[XFRMA_IF_ID])
+ if (attrs[XFRMA_IF_ID]) {
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+ if (!xp->if_id) {
+ err = -EINVAL;
+ goto error;
+ }
+ }
return xp;
error:
@@ -3072,7 +3087,7 @@ static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
if (x->props.extra_flags)
l += nla_total_size(sizeof(x->props.extra_flags));
if (x->xso.dev)
- l += nla_total_size(sizeof(x->xso));
+ l += nla_total_size(sizeof(struct xfrm_user_offload));
if (x->props.smark.v | x->props.smark.m) {
l += nla_total_size(sizeof(x->props.smark.v));
l += nla_total_size(sizeof(x->props.smark.m));