tcp: add sanity checks to rx zerocopy
[platform/kernel/linux-rpi.git] / net / ipv4 / ip_output.c
index 6ba1a0f..4ab877c 100644 (file)
@@ -133,7 +133,7 @@ EXPORT_SYMBOL_GPL(ip_local_out);
 static inline int ip_select_ttl(const struct inet_sock *inet,
                                const struct dst_entry *dst)
 {
-       int ttl = inet->uc_ttl;
+       int ttl = READ_ONCE(inet->uc_ttl);
 
        if (ttl < 0)
                ttl = ip4_dst_hoplimit(dst);
@@ -207,6 +207,9 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
        } else if (rt->rt_type == RTN_BROADCAST)
                IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTBCAST, skb->len);
 
+       /* OUTOCTETS should be counted after fragment */
+       IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
+
        if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
                skb = skb_expand_head(skb, hh_len);
                if (!skb)
@@ -216,7 +219,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
        if (lwtunnel_xmit_redirect(dst->lwtstate)) {
                int res = lwtunnel_xmit(skb);
 
-               if (res < 0 || res == LWTUNNEL_XMIT_DONE)
+               if (res != LWTUNNEL_XMIT_CONTINUE)
                        return res;
        }
 
@@ -236,7 +239,7 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
        net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
                            __func__);
        kfree_skb_reason(skb, SKB_DROP_REASON_NEIGH_CREATEFAIL);
-       return -EINVAL;
+       return PTR_ERR(neigh);
 }
 
 static int ip_finish_output_gso(struct net *net, struct sock *sk,
@@ -366,8 +369,6 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
        /*
         *      If the indicated interface is up and running, send the packet.
         */
-       IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
-
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
 
@@ -424,8 +425,6 @@ int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
 
-       IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
-
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
 
@@ -982,7 +981,7 @@ static int __ip_append_data(struct sock *sk,
        paged = !!cork->gso_size;
 
        if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
-           sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
+           READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
                tskey = atomic_inc_return(&sk->sk_tskey) - 1;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
@@ -1039,7 +1038,7 @@ static int __ip_append_data(struct sock *sk,
                        }
                }
        } else if ((flags & MSG_SPLICE_PAGES) && length) {
-               if (inet->hdrincl)
+               if (inet_test_bit(HDRINCL, sk))
                        return -EPERM;
                if (rt->dst.dev->features & NETIF_F_SG &&
                    getfrag == ip_generic_getfrag)
@@ -1467,7 +1466,8 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
                 * so icmphdr does not in skb linear region and can not get icmp_type
                 * by icmp_hdr(skb)->type.
                 */
-               if (sk->sk_type == SOCK_RAW && !inet_sk(sk)->hdrincl)
+               if (sk->sk_type == SOCK_RAW &&
+                   !inet_test_bit(HDRINCL, sk))
                        icmp_type = fl4->fl4_icmp_type;
                else
                        icmp_type = icmp_hdr(skb)->type;