Subject: kern/21030: fcntl(2) to accepted socket does not work correctly
To: None <gnats-bugs@gnats.netbsd.org>
From: Naoto Shimazaki <igy@arhc.org>
List: netbsd-bugs
Date: 04/05/2003 23:48:39
>Number: 21030
>Category: kern
>Synopsis: fcntl(2) to accepted socket does not work correctly
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Apr 05 06:49:01 PST 2003
>Closed-Date:
>Last-Modified:
>Originator:
>Release: NetBSD 1.6Q
>Organization:
PRUG
>Environment:
System: NetBSD caolila 1.6Q NetBSD 1.6Q (CAOLILA) #5: Sat Apr 5 22:50:32 JST 2003 igy@caolila:/net/cur/obj/sys/arch/i386/compile/CAOLILA i386
Architecture: i386
Machine: i386
>Description:
Inconsistency between f_flag in struct file and so_state in struct socket
breaks latest revision (1.107) of fcntl(2).
1. create a socket and set the flag "O_NONBLOCK".
2. doing bind(2), listen(2), and accept(2)
Under this condition, new socket provided by accept(2) behaves as
non-blocking I/O because SS_NBIO in so_state is inherited from the
listening socket. However fcntl(sk, F_GETFL) says O_NONBLOCK flag is
cleared.
There is inconsistency between f_flag and so_state.
When do fcntl(sk, F_SETFL, 0) on the new socket with latest fcntl(2),
fcntl(2) skips (*fp->f_ops->fo_ioctl)(fp, FIONBIO, &fl, p) because
O_NONBLOCK is already cleared. the new socket still behaves as
non-blocking I/O.
This could happen with O_ASYNC.
>How-To-Repeat:
Run the program attached below.
I tried it on a few system. Here is the result.
lsk: listening socket
ask: socket returned by accept(2)
1. Listening without O_NONBLOCK
flag
lsk ask read
NetBSD-current 0x002 0x002 blocked
NetBSD-1.6 0x002 0x002 blocked
FreeBSD-4.7 0x002 0x002 blocked
Linux-2.4.20 0x002 0x002 blocked
NetBSD-current(patched) 0x002 0x002 blocked
2. Listening with O_NONBLOCK
flag
lsk ask read
NetBSD-current 0x006 0x002 EAGAIN <- flag is inconsistent
NetBSD-1.6 0x006 0x002 EAGAIN <- flag is inconsistent
FreeBSD-4.7 0x006 0x006 EAGAIN
Linux-2.4.20 0x802 0x002 blocked
NetBSD-current(patched) 0x006 0x006 EAGAIN
3. Listening with O_NONBLOCK,
do fcntl(ask, F_SETFL, 0) for accepted socket
flag
lsk ask read
NetBSD-currentr 0x006 0x002 EAGAIN <- fcntl is ignored
NetBSD-1.6 0x006 0x002 blocked
FreeBSD-4.7 0x006 0x002 blocked
Linux-2.4.20 0x802 0x002 blocked
NetBSD-current(patched) 0x006 0x002 blocked
P.S.
I found Linux does not inherit blocking behavior :-)
>Fix:
apply this patch
-------- cut here --------
--- uipc_syscalls.c 2003-04-05 22:57:42.000000000 +0900
+++ uipc_syscalls.c.new 2003-04-05 22:57:47.000000000 +0900
@@ -175,6 +175,7 @@
unsigned int namelen;
int error, s, fd;
struct socket *so;
+ int fflag;
p = l->l_proc;
fdp = p->p_fd;
@@ -222,6 +223,7 @@
splx(s);
return (error);
}
+ fflag = fp->f_flag;
/* falloc() will use the descriptor for us */
if ((error = falloc(p, &fp, &fd)) != 0) {
splx(s);
@@ -238,7 +240,7 @@
so = aso;
}
fp->f_type = DTYPE_SOCKET;
- fp->f_flag = FREAD|FWRITE;
+ fp->f_flag = fflag;
fp->f_ops = &socketops;
fp->f_data = (caddr_t)so;
FILE_UNUSE(fp, p);
-------- cut here --------
--
Naoto Shimazaki
>Release-Note:
>Audit-Trail:
>Unformatted: