Date: Fri, 30 Oct 1998 03:32:30 -0500 (EST) From: viro@math.psu.edu To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: kern/8498: Race condition between unp_gc() and accept(). Message-ID: <199810300832.DAA28142@hilbert.math.psu.edu>
next in thread | raw e-mail | index | archive | help
>Number: 8498
>Category: kern
>Synopsis: Race condition between unp_gc() and accept().
>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: Fri Oct 30 00:40:00 PST 1998
>Last-Modified:
>Originator: Al Viro
>Organization:
-ENOENT
>Release: FreeBSD 2.2.7-RELEASE i386
>Environment:
Present both in 2.2.7-RELEASE and 3.0-RELEASE
>Description:
Mark phase of unp_gc() doesn't scan the list of pending connections.
Thus if we connect() to a UNIX domain socket, pass a file descriptor via the
obtained connection (connect() doesn't block for UNIX domain) and close that
descriptor unp_gc() will consider it garbage until we accept() the connection.
Sweep phase of unp_gc() will merrily flush the queue of passed file.
So we have a race - unp_gc() may be triggered by event completely
unrelated to sockets in question.
I didn't check other *BSD kernels wrt this bug. Actually I've caught
it when I wrote a fix for Linux - garbage collector in Linux implementation
couldn't handle the circular dependencies. In the first variant of the patch
I've reproduced the bug in question - forgot to scan the queues of listening
sockets. Well, when I finally fixed it and submitted the patch I decided to
look into the FreeBSD kernel. Duh.
>How-To-Repeat:
See above. I have a clear testcase, but it's 100 lines of (sparce) C.
If you need it I'll send it, indeed.
Pseudocode (all sockets are PF_UNIX,SOCK_STREAM) follows:
create a socket A, bind it to some address and listen().
create a socket B, connect() to address of A.
create a pair of sockets (C and D) by socketpair().
write something to C.
send a descriptor of D from A.
close D.
*** trigger unp_gc().
accept a connection (A).
receive a message from resulting socket.
read from the received descriptor.
Triggering unp_gc() may be done by creating another socketpair, passing
an arbitrary descriptor (0 ;-) and closing another end.
Results: if we didn't trigger unp_gc() final read() returns the data
we had written to C. If we did trigger unp_gc() read() will return 0.
>Fix:
The following is the patch against 2.2.7. It applies to 3.0-RELEASE
too.
*** uipc_usrreq.c Thu Oct 29 21:27:35 1998
--- uipc_usrreq.c.new Thu Oct 29 22:03:30 1998
***************
*** 736,742 ****
unp_gc()
{
register struct file *fp, *nextfp;
! register struct socket *so;
struct file **extra_ref, **fpp;
int nunref, i;
--- 736,742 ----
unp_gc()
{
register struct file *fp, *nextfp;
! register struct socket *so, *so1;
struct file **extra_ref, **fpp;
int nunref, i;
***************
*** 793,800 ****
if (fp->f_type != DTYPE_SOCKET ||
(so = (struct socket *)fp->f_data) == 0)
continue;
! if (so->so_proto->pr_domain != &localdomain ||
! (so->so_proto->pr_flags&PR_RIGHTS) == 0)
continue;
#ifdef notdef
if (so->so_rcv.sb_flags & SB_LOCK) {
--- 793,819 ----
if (fp->f_type != DTYPE_SOCKET ||
(so = (struct socket *)fp->f_data) == 0)
continue;
! if (so->so_proto->pr_domain != &localdomain)
! continue;
! if (so->so_options & SO_ACCEPTCONN) {
! /*
! * Duh. There is something in theory that
! * bugs are more natural than standards.
! * 1) Linux implementation reproduced the bug
! * in dealing with circular dependencies
! * almost one-to-one.
! * 2) In the first version of my patch I
! * forgot to scan queues of listening sockets.
! * That is, reproduced another bug of _this_
! * implementation ;-/
! * 29/10/98, viro@math.psu.edu
! */
! TAILQ_FOREACH(so1,&so->so_comp,so_list) {
! unp_scan(so1->so_rcv.sb_mb, unp_mark);
! }
! continue;
! }
! if ((so->so_proto->pr_flags&PR_RIGHTS) == 0)
continue;
#ifdef notdef
if (so->so_rcv.sb_flags & SB_LOCK) {
>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?199810300832.DAA28142>
