lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 2 Apr 2019 15:34:50 +0000
From:   Martin Lau <kafai@...com>
To:     hujunwei <hujunwei4@...wei.com>
CC:     kbuild test robot <lkp@...el.com>,
        "kbuild-all@...org" <kbuild-all@...org>,
        "davem@...emloft.net" <davem@...emloft.net>,
        "kuznet@....inr.ac.ru" <kuznet@....inr.ac.ru>,
        "yoshfuji@...ux-ipv6.org" <yoshfuji@...ux-ipv6.org>,
        "netdev@...r.kernel.org" <netdev@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        "mingfangsen@...wei.com" <mingfangsen@...wei.com>,
        "liuzhiqiang26@...wei.com" <liuzhiqiang26@...wei.com>,
        "zhangwenhao8@...wei.com" <zhangwenhao8@...wei.com>,
        "wangxiaogang3@...wei.com" <wangxiaogang3@...wei.com>
Subject: Re: [PATCH v3 net] ipv6: Fix dangling pointer when ipv6 fragment

On Tue, Apr 02, 2019 at 06:49:03PM +0800, kbuild test robot wrote:
> 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);
hmm... This line has been moved up since v2. :(

>    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://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_pipermail_kbuild-2Dall&d=DwIBAg&c=5VD0RTtNlTh3ycd41b3MUw&r=VQnoQ7LvghIj0gVEaiQSUw&m=VM2d9MD3GON8eQRY0bYRU7OGyFCoSiaFiYJJa6-3rDU&s=p3p0GnDqN_d4cCUIgH993sIXi_Sw8tUInnni3uMPXKk&e=                   Intel Corporation


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ