Bug 8498 - Race condition between unp_gc() and accept().
Summary: Race condition between unp_gc() and accept().
Status: Closed Feedback Timeout
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 2.2.7-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 1998-10-30 08:40 UTC by viro
Modified: 2018-05-21 06:42 UTC (History)
1 user (show)

See Also:


Attachments
file.diff (1.64 KB, patch)
1998-10-30 08:40 UTC, viro
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description viro 1998-10-30 08:40:00 UTC
	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.

Fix: The following is the patch against 2.2.7. It applies to 3.0-RELEASE
too.
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.
Comment 1 iedowse freebsd_committer freebsd_triage 2002-01-19 22:47:11 UTC
State Changed
From-To: open->feedback


Does this problem still exist?
Comment 2 iedowse 2002-01-19 23:17:46 UTC
Adding to the audit trail:

In message <Pine.GSO.4.21.0201191801310.5397-100000@weyl.math.psu.edu>, Alexand
er Viro writes:
>
>
>On Sat, 19 Jan 2002 iedowse@FreeBSD.org wrote:
>
>> Synopsis: Race condition between unp_gc() and accept().
>> 
>> State-Changed-From-To: open->feedback
>> State-Changed-By: iedowse
>> State-Changed-When: Sat Jan 19 14:47:11 PST 2002
>> State-Changed-Why: 
>> 
>> Does this problem still exist?
>
>As far as I can see it's still there in HEAD - analysis from the original
>bug report still applies.
>
>BTW, there is another problem: uipc_userreq.c:1378 has
>        extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
>which can block.  During that time we might get new files opened and sent
>in SCM_RIGHTS cookies.  Notice that
>	a) we will have them _not_ marked, so the code after that will try
>to kill them.
>	b) nfiles might have grown!
>
>The former means that legitimate stuff gets killed.  The latter is a buffer
>overrun in kernel space waiting to happen.
>
>Fix: invert the logics with "marked".  I.e. start with marking everything,
>then unmark those you want to stay around.  Then by the end of the first
>phase you have marked exactly the stuff that needs to die.  New struct
>file won't be marked, so the loop populating extra_ref will skip it...
>
Comment 3 dwmalone freebsd_committer freebsd_triage 2002-01-20 13:39:51 UTC
Responsible Changed
From-To: freebsd-bugs->dwmalone

I'll try to look at this as I have a few discriptor passing PRs to my 
name at the moment. If anyone else wants to look at this (Matt might, 
as he has worked with Al Viro on file discriptor problems before) please 
be my guest.
Comment 4 Gavin Atkinson freebsd_committer freebsd_triage 2007-07-30 11:32:35 UTC
State Changed
From-To: feedback->open

Feedback was received
Comment 5 silby freebsd_committer freebsd_triage 2007-10-07 01:22:55 UTC
Responsible Changed
From-To: dwmalone->silby

I'll take this.
Comment 6 Harrison Grundy 2014-12-17 12:07:38 UTC
Comment on attachment 2952 [details]
file.diff

Does this still occur?
Comment 7 Mark Linimon freebsd_committer freebsd_triage 2015-11-12 01:25:12 UTC
Reassign to the wild with permission of assignee.
Comment 8 Eitan Adler freebsd_committer freebsd_triage 2018-05-20 23:52:32 UTC
For bugs matching the following conditions:
- Status == In Progress
- Assignee == "bugs@FreeBSD.org"
- Last Modified Year <= 2017

Do
- Set Status to "Open"
Comment 9 Andriy Gapon freebsd_committer freebsd_triage 2018-05-21 06:42:06 UTC
No one confirmed that the problem exists in many years.