Hi hujunwei, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on net/master] url: https://github.com/0day-ci/linux/commits/hujunwei/ipv6-Fix-dangling-pointer-when-ipv6-fragment/20190402-175602 config: i386-randconfig-x005-201913 (attached as .config) compiler: gcc-7 (Debian 7.3.0-1) 7.3.0 reproduce: # save the attached .config to linux build tree make ARCH=i386 All warnings (new ones prefixed by >>): net//ipv6/ip6_output.c: In function 'ip6_fragment': >> net//ipv6/ip6_output.c:609:27: warning: 'prevhdr' is used uninitialized in this function [-Wuninitialized] nexthdr_offset = prevhdr - skb_network_header(skb); ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ vim +/prevhdr +609 net//ipv6/ip6_output.c 594 595 int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, 596 int (*output)(struct net *, struct sock *, struct sk_buff *)) 597 { 598 struct sk_buff *frag; 599 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); 600 struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? 601 inet6_sk(skb->sk) : NULL; 602 struct ipv6hdr *tmp_hdr; 603 struct frag_hdr *fh; 604 unsigned int mtu, hlen, left, len, nexthdr_offset; 605 int hroom, troom; 606 __be32 frag_id; 607 int ptr, offset = 0, err = 0; 608 u8 *prevhdr, nexthdr = 0; > 609 nexthdr_offset = prevhdr - skb_network_header(skb); 610 611 err = ip6_find_1stfragopt(skb, &prevhdr); 612 if (err < 0) 613 goto fail; 614 hlen = err; 615 nexthdr = *prevhdr; 616 617 mtu = ip6_skb_dst_mtu(skb); 618 619 /* We must not fragment if the socket is set to force MTU discovery 620 * or if the skb it not generated by a local socket. 621 */ 622 if (unlikely(!skb->ignore_df && skb->len > mtu)) 623 goto fail_toobig; 624 625 if (IP6CB(skb)->frag_max_size) { 626 if (IP6CB(skb)->frag_max_size > mtu) 627 goto fail_toobig; 628 629 /* don't send fragments larger than what we received */ 630 mtu = IP6CB(skb)->frag_max_size; 631 if (mtu < IPV6_MIN_MTU) 632 mtu = IPV6_MIN_MTU; 633 } 634 635 if (np && np->frag_size < mtu) { 636 if (np->frag_size) 637 mtu = np->frag_size; 638 } 639 if (mtu < hlen + sizeof(struct frag_hdr) + 8) 640 goto fail_toobig; 641 mtu -= hlen + sizeof(struct frag_hdr); 642 643 frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, 644 &ipv6_hdr(skb)->saddr); 645 646 if (skb->ip_summed == CHECKSUM_PARTIAL && 647 (err = skb_checksum_help(skb))) 648 goto fail; 649 650 prevhdr = skb_network_header(skb) + nexthdr_offset; 651 hroom = LL_RESERVED_SPACE(rt->dst.dev); 652 if (skb_has_frag_list(skb)) { 653 unsigned int first_len = skb_pagelen(skb); 654 struct sk_buff *frag2; 655 656 if (first_len - hlen > mtu || 657 ((first_len - hlen) & 7) || 658 skb_cloned(skb) || 659 skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) 660 goto slow_path; 661 662 skb_walk_frags(skb, frag) { 663 /* Correct geometry. */ 664 if (frag->len > mtu || 665 ((frag->len & 7) && frag->next) || 666 skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr))) 667 goto slow_path_clean; 668 669 /* Partially cloned skb? */ 670 if (skb_shared(frag)) 671 goto slow_path_clean; 672 673 BUG_ON(frag->sk); 674 if (skb->sk) { 675 frag->sk = skb->sk; 676 frag->destructor = sock_wfree; 677 } 678 skb->truesize -= frag->truesize; 679 } 680 681 err = 0; 682 offset = 0; 683 /* BUILD HEADER */ 684 685 *prevhdr = NEXTHDR_FRAGMENT; 686 tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); 687 if (!tmp_hdr) { 688 err = -ENOMEM; 689 goto fail; 690 } 691 frag = skb_shinfo(skb)->frag_list; 692 skb_frag_list_init(skb); 693 694 __skb_pull(skb, hlen); 695 fh = __skb_push(skb, sizeof(struct frag_hdr)); 696 __skb_push(skb, hlen); 697 skb_reset_network_header(skb); 698 memcpy(skb_network_header(skb), tmp_hdr, hlen); 699 700 fh->nexthdr = nexthdr; 701 fh->reserved = 0; 702 fh->frag_off = htons(IP6_MF); 703 fh->identification = frag_id; 704 705 first_len = skb_pagelen(skb); 706 skb->data_len = first_len - skb_headlen(skb); 707 skb->len = first_len; 708 ipv6_hdr(skb)->payload_len = htons(first_len - 709 sizeof(struct ipv6hdr)); 710 711 for (;;) { 712 /* Prepare header of the next frame, 713 * before previous one went down. */ 714 if (frag) { 715 frag->ip_summed = CHECKSUM_NONE; 716 skb_reset_transport_header(frag); 717 fh = __skb_push(frag, sizeof(struct frag_hdr)); 718 __skb_push(frag, hlen); 719 skb_reset_network_header(frag); 720 memcpy(skb_network_header(frag), tmp_hdr, 721 hlen); 722 offset += skb->len - hlen - sizeof(struct frag_hdr); 723 fh->nexthdr = nexthdr; 724 fh->reserved = 0; 725 fh->frag_off = htons(offset); 726 if (frag->next) 727 fh->frag_off |= htons(IP6_MF); 728 fh->identification = frag_id; 729 ipv6_hdr(frag)->payload_len = 730 htons(frag->len - 731 sizeof(struct ipv6hdr)); 732 ip6_copy_metadata(frag, skb); 733 } 734 735 err = output(net, sk, skb); 736 if (!err) 737 IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), 738 IPSTATS_MIB_FRAGCREATES); 739 740 if (err || !frag) 741 break; 742 743 skb = frag; 744 frag = skb->next; 745 skb_mark_not_on_list(skb); 746 } 747 748 kfree(tmp_hdr); 749 750 if (err == 0) { 751 IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), 752 IPSTATS_MIB_FRAGOKS); 753 return 0; 754 } 755 756 kfree_skb_list(frag); 757 758 IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), 759 IPSTATS_MIB_FRAGFAILS); 760 return err; 761 762 slow_path_clean: 763 skb_walk_frags(skb, frag2) { 764 if (frag2 == frag) 765 break; 766 frag2->sk = NULL; 767 frag2->destructor = NULL; 768 skb->truesize += frag2->truesize; 769 } 770 } 771 772 slow_path: 773 left = skb->len - hlen; /* Space per frame */ 774 ptr = hlen; /* Where to start from */ 775 776 /* 777 * Fragment the datagram. 778 */ 779 780 troom = rt->dst.dev->needed_tailroom; 781 782 /* 783 * Keep copying data until we run out. 784 */ 785 while (left > 0) { 786 u8 *fragnexthdr_offset; 787 788 len = left; 789 /* IF: it doesn't fit, use 'mtu' - the data space left */ 790 if (len > mtu) 791 len = mtu; 792 /* IF: we are not sending up to and including the packet end 793 then align the next start on an eight byte boundary */ 794 if (len < left) { 795 len &= ~7; 796 } 797 798 /* Allocate buffer */ 799 frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) + 800 hroom + troom, GFP_ATOMIC); 801 if (!frag) { 802 err = -ENOMEM; 803 goto fail; 804 } 805 806 /* 807 * Set up data on packet 808 */ 809 810 ip6_copy_metadata(frag, skb); 811 skb_reserve(frag, hroom); 812 skb_put(frag, len + hlen + sizeof(struct frag_hdr)); 813 skb_reset_network_header(frag); 814 fh = (struct frag_hdr *)(skb_network_header(frag) + hlen); 815 frag->transport_header = (frag->network_header + hlen + 816 sizeof(struct frag_hdr)); 817 818 /* 819 * Charge the memory for the fragment to any owner 820 * it might possess 821 */ 822 if (skb->sk) 823 skb_set_owner_w(frag, skb->sk); 824 825 /* 826 * Copy the packet header into the new buffer. 827 */ 828 skb_copy_from_linear_data(skb, skb_network_header(frag), hlen); 829 830 fragnexthdr_offset = skb_network_header(frag); 831 fragnexthdr_offset += prevhdr - skb_network_header(skb); 832 *fragnexthdr_offset = NEXTHDR_FRAGMENT; 833 834 /* 835 * Build fragment header. 836 */ 837 fh->nexthdr = nexthdr; 838 fh->reserved = 0; 839 fh->identification = frag_id; 840 841 /* 842 * Copy a block of the IP datagram. 843 */ 844 BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag), 845 len)); 846 left -= len; 847 848 fh->frag_off = htons(offset); 849 if (left > 0) 850 fh->frag_off |= htons(IP6_MF); 851 ipv6_hdr(frag)->payload_len = htons(frag->len - 852 sizeof(struct ipv6hdr)); 853 854 ptr += len; 855 offset += len; 856 857 /* 858 * Put this fragment into the sending queue. 859 */ 860 err = output(net, sk, frag); 861 if (err) 862 goto fail; 863 864 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 865 IPSTATS_MIB_FRAGCREATES); 866 } 867 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 868 IPSTATS_MIB_FRAGOKS); 869 consume_skb(skb); 870 return err; 871 872 fail_toobig: 873 if (skb->sk && dst_allfrag(skb_dst(skb))) 874 sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK); 875 876 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 877 err = -EMSGSIZE; 878 879 fail: 880 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 881 IPSTATS_MIB_FRAGFAILS); 882 kfree_skb(skb); 883 return err; 884 } 885 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation