Subject: port-i386/2612: spkrwrite sometimes overruns given data and plays random music
To: None <gnats-bugs@NetBSD.ORG>
From: None <enami@ba2.so-net.or.jp>
List: netbsd-bugs
Date: 07/09/1996 21:25:07
>Number:         2612
>Category:       port-i386
>Synopsis:       spkrwrite sometimes overruns given data and plays random music
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    gnats-admin (GNATS administrator)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Jul  9 08:50:01 1996
>Last-Modified:
>Originator:     enami tsugutomo
>Organization:
	An individual
>Release:        1.2_ALPHA
>Environment:
System: NetBSD plants-doll.enami.ba2.so-net.or.jp 1.2_BETA NetBSD 1.2_BETA (PLANTS_DOLL) #170: Sat Jul 6 15:31:38 JST 1996 enami@plants-doll.enami.ba2.so-net.or.jp:/usr/src/sys/arch/i386/compile/PLANTS_DOLL i386


>Description:
	The function spkrwrite in arch/i386/isa/spkr.c sometimes overruns
	given data.  In such case, speaker plays random music after palying
	right one.
>How-To-Repeat:
	Apply following patch to spkr.c.  It fills a internal buffer with
	wrong garbage before copy given data.  Then do
		echo -n o4cc >/dev/speaker.
	This should only play two beep, but it may plays random music (and
	may panic if DEV_BSZIE is exceeded).

Index: spkr.c
===================================================================
RCS file: /a/cvsroot/NetBSD/sys/arch/i386/isa/spkr.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 spkr.c
--- spkr.c	1996/05/07 02:40:14	1.1.1.5
+++ spkr.c	1996/07/09 11:39:54
@@ -503,8 +503,11 @@
 	return(ENXIO);
     else
     {
+	int i;
 	n = min(DEV_BSIZE, uio->uio_resid);
 	cp = spkr_inbuf->b_data;
+	for (i = 0; i < DEV_BSIZE; i++)
+		cp[i] = '#';
 	error = uiomove(cp, n, uio);
 	if (!error)
 		playstring(cp, n);

>Fix:
	The problem is in a function playstring; it uses cp[1] without
	checking slen > 0 and if garbage looks right data it decrements slen
	over zero (it becomes very large integer because slen is size_t).
	To fix the problem I think there is at lease two way:

	a) Check if slen > 0 whenever uses cp[1].
	or
	b) Put a sentinel after given data so that random garbage in
	buffer does not confuse the playstring.

	Here is a patch for style b). It is shorter than a).

Index: spkr.c
===================================================================
RCS file: /a/cvsroot/NetBSD/sys/arch/i386/isa/spkr.c,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 spkr.c
--- spkr.c	1996/05/07 02:40:14	1.1.1.5
+++ spkr.c	1996/07/09 12:04:32
@@ -253,7 +253,7 @@
 {
     int		pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
 
-#define GETNUM(cp, v)	for(v=0; isdigit(cp[1]) && slen > 0; ) \
+#define GETNUM(cp, v)	for(v=0; isdigit(cp[1]); ) \
 				{v = v * 10 + (*++cp - '0'); slen--;}
     for (; slen--; cp++)
     {
@@ -503,11 +503,13 @@
 	return(ENXIO);
     else
     {
-	n = min(DEV_BSIZE, uio->uio_resid);
+	n = min(DEV_BSIZE - 1, uio->uio_resid);
 	cp = spkr_inbuf->b_data;
 	error = uiomove(cp, n, uio);
-	if (!error)
+	if (!error) {
+		cp[n] = '\0';		/* put a sentinel */
 		playstring(cp, n);
+	}
 	return(error);
     }
 }
>Audit-Trail:
>Unformatted: