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: Mon, 29 Apr 2024 23:30:48 +0900
From: Ryosuke Yasuoka <ryasuoka@...hat.com>
To: Simon Horman <horms@...nel.org>
Cc: krzk@...nel.org, davem@...emloft.net, edumazet@...gle.com,
	kuba@...nel.org, pabeni@...hat.com, netdev@...r.kernel.org,
	linux-kernel@...r.kernel.org, syoshida@...hat.com,
	syzbot+d7b4dc6cd50410152534@...kaller.appspotmail.com
Subject: Re: [PATCH net v2] nfc: nci: Fix uninit-value in nci_rx_work

On Sun, Apr 28, 2024 at 02:45:25PM +0100, Simon Horman wrote:
> On Sat, Apr 27, 2024 at 07:35:54PM +0900, Ryosuke Yasuoka wrote:
> > syzbot reported the following uninit-value access issue [1]
> > 
> > nci_rx_work() parses received packet from ndev->rx_q. It should be
> > validated header size, payload size and total packet size before
> > processing the packet. If an invalid packet is detected, it should be
> > silently discarded.
> > 
> > Fixes: d24b03535e5e ("nfc: nci: Fix uninit-value in nci_dev_up and nci_ntf_packet")
> > Reported-and-tested-by: syzbot+d7b4dc6cd50410152534@...kaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=d7b4dc6cd50410152534 [1]
> > Signed-off-by: Ryosuke Yasuoka <ryasuoka@...hat.com>
> 
> ...
> 
> > @@ -1516,30 +1526,36 @@ static void nci_rx_work(struct work_struct *work)
> >  		nfc_send_to_raw_sock(ndev->nfc_dev, skb,
> >  				     RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);
> >  
> > -		if (!nci_plen(skb->data)) {
> > -			kfree_skb(skb);
> > -			break;
> > -		}
> > +		if (!skb->len)
> > +			goto invalid_pkt_free;
> >  
> >  		/* Process frame */
> >  		switch (nci_mt(skb->data)) {
> >  		case NCI_MT_RSP_PKT:
> > +			if (!nci_valid_size(skb, NCI_CTRL_HDR_SIZE))
> > +				goto invalid_pkt_free;
> 
> Hi Yasuoka-san,
> 
> My reading is that this will jump to the label invalid_pkt_free,
> which is intended.
> 
> >  			nci_rsp_packet(ndev, skb);
> >  			break;
> 
> But this will exit the switch statement, which lands
> at the label invalid_pkt_free, where skb is kfreed.
> This doesn't seem to be intended.
> 
> >  
> >  		case NCI_MT_NTF_PKT:
> > +			if (!nci_valid_size(skb, NCI_CTRL_HDR_SIZE))
> > +				goto invalid_pkt_free;
> >  			nci_ntf_packet(ndev, skb);
> >  			break;
> >  
> >  		case NCI_MT_DATA_PKT:
> > +			if (!nci_valid_size(skb, NCI_DATA_HDR_SIZE))
> > +				goto invalid_pkt_free;
> >  			nci_rx_data_packet(ndev, skb);
> >  			break;
> >  
> >  		default:
> >  			pr_err("unknown MT 0x%x\n", nci_mt(skb->data));
> > -			kfree_skb(skb);
> > -			break;
> > +			goto invalid_pkt_free;
> >  		}
> 
> If so, then one solution may be to add the following here:
> 
> 		continue;
> 
> > +invalid_pkt_free:
> > +		kfree_skb(skb);
> > +		break;
> >  	}
> >  
> >  	/* check if a data exchange timeout has occurred */
> > -- 
> > 2.44.0
> > 
> > 
> 

Thank you for your comment, Simon.

Yes, if it handles packets correctly in nci_{rsp,ntf,rx_data}_packet(),
it should not reach invalid_pkt_free and it should continue to work in
the for statement. Sorry, it is my mistake and need to fix it.

BTW, in the current implementation, if the payload is zero, it will free
the skb and exit the for statement. I wonder it is intended. 

> > -		if (!nci_plen(skb->data)) {
> > -			kfree_skb(skb);
> > -			break;
> > -		}

When the packet is invalid, it should be discarded but it should not
exit the for statement by break. Instead, the skb should just free and
it should handle the subsequent packet by continue. If yes, then it 
may be like below,

	for (; (skb = skb_dequeue(&ndev->rx_q)); kcov_remote_stop()) {
		kcov_remote_start_common(skb_get_kcov_handle(skb));

		/* Send copy to sniffer */
		nfc_send_to_raw_sock(ndev->nfc_dev, skb,
				     RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);

		if (!skb->len)
			goto invalid_pkt_free;

		/* Process frame */
		switch (nci_mt(skb->data)) {
		case NCI_MT_RSP_PKT:
			if (!nci_valid_size(skb, NCI_CTRL_HDR_SIZE))
				goto invalid_pkt_free;
			nci_rsp_packet(ndev, skb);
			continue;   <<<---

		case NCI_MT_NTF_PKT:
			if (!nci_valid_size(skb, NCI_CTRL_HDR_SIZE))
				goto invalid_pkt_free;
			nci_ntf_packet(ndev, skb);
			continue;   <<<---

		case NCI_MT_DATA_PKT:
			if (!nci_valid_size(skb, NCI_DATA_HDR_SIZE))
				goto invalid_pkt_free;
			nci_rx_data_packet(ndev, skb);
			continue;   <<<---

		default:
			pr_err("unknown MT 0x%x\n", nci_mt(skb->data));
			goto invalid_pkt_free;
		}
invalid_pkt_free:
		kfree_skb(skb);
	}

Could I hear your opinion?


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ