]> git.ipfire.org Git - thirdparty/linux.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)
committerDavid S. Miller <davem@davemloft.net>
Mon, 25 Feb 2019 22:32:35 +0000 (14:32 -0800)
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>
include/net/ip.h
net/ipv4/cipso_ipv4.c
net/ipv4/ip_options.c

index 8866bfce61214b6af1c3c59b4885c8c39e8e0e90..f0e8d064e2495e57afabe718f9b5982691000827 100644 (file)
@@ -667,6 +667,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 777fa3b7fb13d9f73a71eee2162ce472c1097b92..eff86a71c1b0f37b978c47af5c747e194908c629 100644 (file)
@@ -1735,13 +1735,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);
 
 /*