]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
net: avoid use IPCB in cipso_v4_error
authorNazarov Sergey <s-nazarov@yandex.ru>
Mon, 25 Feb 2019 16:27:15 +0000 (19:27 +0300)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Wed, 14 Aug 2019 09:18:49 +0000 (11:18 +0200)
BugLink: https://bugs.launchpad.net/bugs/1837813
[ Upstream commit 3da1ed7ac398f34fff1694017a07054d69c5f5c5 ]

Extract IP options in cipso_v4_error and use __icmp_send.

Signed-off-by: Sergey Nazarov <s-nazarov@yandex.ru>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
include/net/ip.h
net/ipv4/cipso_ipv4.c
net/ipv4/ip_options.c

index 7c430343176afe769d3e885ca1d3bd5176541c3b..80575db4e304ca171eaf50f3dda73a34d631b6ab 100644 (file)
@@ -593,6 +593,8 @@ static inline int ip_options_echo(struct net *net, struct ip_options *dopt,
 }
 
 void ip_options_fragment(struct sk_buff *skb);
+int __ip_options_compile(struct net *net, struct ip_options *opt,
+                        struct sk_buff *skb, __be32 *info);
 int ip_options_compile(struct net *net, struct ip_options *opt,
                       struct sk_buff *skb);
 int ip_options_get(struct net *net, struct ip_options_rcu **optp,
index f4b83de2263eda25f4d61ee039de7e2162584624..f0165c5f376b398950db7696e813c94b19034068 100644 (file)
@@ -1736,13 +1736,26 @@ validate_return:
  */
 void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 {
+       unsigned char optbuf[sizeof(struct ip_options) + 40];
+       struct ip_options *opt = (struct ip_options *)optbuf;
+
        if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
                return;
 
+       /*
+        * We might be called above the IP layer,
+        * so we can not use icmp_send and IPCB here.
+        */
+
+       memset(opt, 0, sizeof(struct ip_options));
+       opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr);
+       if (__ip_options_compile(dev_net(skb->dev), opt, skb, NULL))
+               return;
+
        if (gateway)
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
+               __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0, opt);
        else
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
+               __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0, opt);
 }
 
 /**
index ed194d46c00e3292cd741a07cd8954ccdc5a1fd6..32a35043c9f590314b7fa354d5e948b59e665214 100644 (file)
@@ -251,8 +251,9 @@ static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb)
  * If opt == NULL, then skb->data should point to IP header.
  */
 
-int ip_options_compile(struct net *net,
-                      struct ip_options *opt, struct sk_buff *skb)
+int __ip_options_compile(struct net *net,
+                        struct ip_options *opt, struct sk_buff *skb,
+                        __be32 *info)
 {
        __be32 spec_dst = htonl(INADDR_ANY);
        unsigned char *pp_ptr = NULL;
@@ -468,11 +469,22 @@ eol:
                return 0;
 
 error:
-       if (skb) {
-               icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24));
-       }
+       if (info)
+               *info = htonl((pp_ptr-iph)<<24);
        return -EINVAL;
 }
+
+int ip_options_compile(struct net *net,
+                      struct ip_options *opt, struct sk_buff *skb)
+{
+       int ret;
+       __be32 info;
+
+       ret = __ip_options_compile(net, opt, skb, &info);
+       if (ret != 0 && skb)
+               icmp_send(skb, ICMP_PARAMETERPROB, 0, info);
+       return ret;
+}
 EXPORT_SYMBOL(ip_options_compile);
 
 /*