usb/126884: [patch] Bug in buffer handling in ugen.c

Daan Vreeken [PA4DAN] Daan at VEHosting.nl
Wed Aug 27 11:40:04 UTC 2008


>Number:         126884
>Category:       usb
>Synopsis:       [patch] Bug in buffer handling in ugen.c
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-usb
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 27 11:40:02 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Daan Vreeken [PA4DAN]
>Release:        FreeBSD 7.0-STABLE amd64
>Organization:
VEHosting.nl
>Environment:
System: FreeBSD TVlottePert.VEHosting.nl 7.0-STABLE FreeBSD 7.0-STABLE #0: Fri Jun 13 18:02:09 CEST 2008 root at TVlottePert.VEHosting.nl:/usr/obj/usr/src/sys/GENERIC amd64


	
>Description:
	In ugen_isoc_rintr() old data is thrown away when the fifo is full.
	This code contains multiple errors :
	o Only in the case of sce->fill < sce->cur data is thrown away.
	  (No data is discarded when sce->fill is near the end of the buffer
	  and sce->cur is near the beginning of the buffer.)
	o Too much data is discarded. If 10 bytes need to be written with
	  only space left for 8 bytes, 10 bytes of input are discarded instead
	  of just 2.
	o When sce->cur reaches/passes the end of the buffer, the pointer is
	  set to sce->ibuf + (sce->limit - sce->cur) instead of to
	  sce->ibuf + (sce->cur - sce->limit). This could leave the sce->cur
	  pointer ahead of the buffer pointing to unknown memory.

>How-To-Repeat:
	Try to use the ugen interface to read data from a device with an
	isochronous endpoint that delivers isochronous packets of varying
	length and see that data gets corrupted.
	
>Fix:
	The attached patch is to -CURRENT, but the bug is found in other
	branches too.
	The patch moves the deletion of data into the while loop that copies
	data from the incoming packet. This way data is also discarded in the
	case where sce->fill >= sce->cur initially (because the while loop
	already breaks filling the end & beginning of the buffer into two
	itterations).

	

--- ugen.c.patch begins here ---
--- ugen.c-1.112	2008-08-27 11:48:37.000000000 +0200
+++ ugen.c	2008-08-27 12:08:10.000000000 +0200
@@ -1054,15 +1054,6 @@
 	DPRINTFN(5,("ugen_isoc_rintr: xfer %td, count=%d\n", req - sce->isoreqs,
 		    count));
 
-	/* throw away oldest input if the buffer is full */
-	if(sce->fill < sce->cur && sce->cur <= sce->fill + count) {
-		sce->cur += count;
-		if(sce->cur >= sce->limit)
-			sce->cur = sce->ibuf + (sce->limit - sce->cur);
-		DPRINTFN(5, ("ugen_isoc_rintr: throwing away %d bytes\n",
-			     count));
-	}
-
 	isize = UGETW(sce->edesc->wMaxPacketSize);
 	for (i = 0; i < UGEN_NISORFRMS; i++) {
 		u_int32_t actlen = req->sizes[i];
@@ -1071,6 +1062,22 @@
 		/* copy data to buffer */
 		while (actlen > 0) {
 			n = min(actlen, sce->limit - sce->fill);
+
+			/* throw away oldest input if the buffer is full */
+			if(sce->fill < sce->cur &&
+			    sce->cur <= sce->fill + n) {
+				u_int32_t drop;
+				
+				/* calculate fow many bytes we have to drop */
+				drop = scr->cur - sce->fill;
+
+				sce->cur += drop;
+				if(sce->cur >= sce->limit)
+					sce->cur = sce->ibuf;
+				DPRINTFN(5, ("ugen_isoc_rintr: throwing "
+				    "away %d bytes\n", drop));
+			}
+
 			memcpy(sce->fill, buf, n);
 
 			buf += n;
--- ugen.c.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-usb mailing list