Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Oct 2001 15:54:49 +0300 (EEST)
From:      Valentin Nechayev <netch@lucky.net>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   kern/30985: incorrect signal handling in snpread()
Message-ID:  <200110021254.PVC23146@burka.carrier.kiev.ua>

next in thread | raw e-mail | index | archive | help

>Number:         30985
>Category:       kern
>Synopsis:       incorrect signal handling in snpread()
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Oct 02 06:00:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Valentin Nechayev <netch@lucky.net>
>Release:        FreeBSD 4.4-RELEASE i386
>Organization:
Lucky Net Ltd.
>Environment:

Found on: FreeBSD 4.2-STABLE
Confirmed on: FreeBSD 4.4-RELEASE

>Description:

sleeping in snpread() waiting for data is interruptible (PCATCH flag),
but does not check for tsleep() status which can say that signal came.
As a result, system hangs in "forever" cycle.

Discovered by: Vladimir Jakovenko <vovik@lucky.net>

>How-To-Repeat:

Write any userland program which does read() on snp(4) device in
blocking mode. Run it and interrupt it from its terminal with intr character
(Ctrl-C in standard case). Local (virtual) console, e.g. ttyv1, may be
required.
Standard watch(8) does not show this behavoir in 99.99...% cases because
it waits in select(), not in read(). But it also can fall to this case
in rare case when signal occurs during snpread() (am I wrong?)

>Fix:

Following simple fix provides checking for tsleep() return code
and EINTR returning when signal is caught. It is applicable for
all late 4.* systems.
It also increases IPL around the data wait cycle. As data can be put
to snoop device during interrupt (am I wrong?), it is desirable.
If hard-interrupt and soft-interrupt handling code can't put data to
snoop device, this IPL increasing isn't needed.
I didn't increase IPL around uiomove() due to some deja-vu.

But it should be noted that there are some principal architectural
issues in this approach. As snp device is designed for use when
select/poll is used to wait and ioctl(FIONREAD) is desired to get
tty status, it may be desirable to avoid blocking reads of snp device
totally. I can't suppose what approach is more right.

==={{{
--- tty_snoop.c.0	Thu Nov 18 08:39:47 1999
+++ tty_snoop.c	Tue Oct  2 15:23:54 2001
@@ -143,18 +143,26 @@
 	if (snp->snp_tty == NULL)
 		return (EIO);
 
+	s = spltty();
 	snp->snp_flags &= ~SNOOP_RWAIT;
 
 	do {
 		if (snp->snp_len == 0) {
-			if (flag & IO_NDELAY)
+			if (flag & IO_NDELAY) {
+				splx(s);
 				return (EWOULDBLOCK);
+			}
 			snp->snp_flags |= SNOOP_RWAIT;
-			tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
+			error = tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
+			if (error == EINTR || error == ERESTART) {
+				splx(s);
+				return EINTR;
+			}
 		}
 	} while (snp->snp_len == 0);
 
 	n = snp->snp_len;
+	splx(s);
 
 	while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
 		len = MIN(uio->uio_resid, snp->snp_len);
===}}}


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

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200110021254.PVC23146>