From nobody@FreeBSD.org  Sat Jan 24 00:49:15 2009
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 62D291065670
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 24 Jan 2009 00:49:15 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 516CF8FC1A
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 24 Jan 2009 00:49:15 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n0O0nFeY050037
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 24 Jan 2009 00:49:15 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id n0O0nFZx050036;
	Sat, 24 Jan 2009 00:49:15 GMT
	(envelope-from nobody)
Message-Id: <200901240049.n0O0nFZx050036@www.freebsd.org>
Date: Sat, 24 Jan 2009 00:49:15 GMT
From: Kurt Miller <kurt@intricatesoftware.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: poll() system call overwrites complete pollfd struct instead of just revents
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         130924
>Category:       kern
>Synopsis:       [kernel] poll(2) system call overwrites complete pollfd struct instead of just revents
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    rwatson
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jan 24 00:50:01 UTC 2009
>Closed-Date:    Mon Apr 13 13:09:04 UTC 2009
>Last-Modified:  Mon Apr 13 13:09:04 UTC 2009
>Originator:     Kurt Miller
>Release:        7.0-release
>Organization:
Intricate Software
>Environment:
FreeBSD fbsd-i386-70.intricatesoftware.com 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Sun Feb 24 19:59:52 UTC 2008     root@logan.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
poll() system call overwrites complete pollfd struct instead of just revents.

This can cause threaded programs to 'loose' new events set while another thread is blocked and waiting in poll(). For example the JDK allows one thread to change the pollfd events field while a second thread is blocked in poll(). After waking up the blocked thread and returning to poll, the new event is lost by the poll system call overwriting the complete pollfd struct instead of just revents.
>How-To-Repeat:
#include <err.h>
#include <poll.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

struct pollfd fds[2];
int pipefds[2];

static void *
thread(void *arg) {
  sleep(1);
  fds[1].events = POLLIN | POLLOUT;
  write(pipefds[0], "", 1);
  return NULL;
}

int
main(int argc, char *argv[]) {
  pthread_t tid;

  if (pipe(pipefds) != 0)
    err(1, "pipe failed");

  fds[0].fd = pipefds[0];
  fds[0].events = POLLIN;

  fds[1].fd = pipefds[1];
  fds[1].events = POLLIN;

  if (pthread_create(&tid, NULL, thread, NULL) != 0)
    err(1, "pthread_create failed");

  poll(fds, 2, -1);

  if (fds[1].events != (POLLIN | POLLOUT)) {
    printf("events overwritten by kernel!\n");
    return 1;
  }

  return 0;
}
>Fix:
change the poll system call to copyout just the revents value instead of the full pollfd struct.

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->analyzed 
State-Changed-By: rwatson 
State-Changed-When: Tue Feb 10 09:22:36 UTC 2009 
State-Changed-Why:  
This seems like a reasonable request; however, I'm not convinced 
applications should rely on this behavior--while Linux provides it (for 
example), Solaris doesn't appear to, so I'm a bit surprised that the 
JDK depends on it. 



Responsible-Changed-From-To: freebsd-bugs->rwatson 
Responsible-Changed-By: rwatson 
Responsible-Changed-When: Tue Feb 10 09:22:36 UTC 2009 
Responsible-Changed-Why:  
Grab ownership as I can look at this PR. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130924 

From: Mike Jakubik <mike.jakubik@intertainservices.com>
To: bug-followup@FreeBSD.org, kurt@intricatesoftware.com
Cc:  
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete
 pollfd struct instead of just revents
Date: Wed, 11 Mar 2009 11:01:45 -0400

 Has anyone had a chance to look at this or create a patch? If so i would 
 love to test it as i have a java application that seems to be throwing 
 an exception because of this.

From: Kurt Miller <kurt@intricatesoftware.com>
To: bug-followup@freebsd.org, kurt@intricatesoftware.com
Cc:  
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete pollfd struct instead of just revents
Date: Wed, 11 Mar 2009 12:17:43 -0400

 --Boundary-00=_oQ+tJpKg7UuAN3l
 Content-Type: text/plain;
   charset="us-ascii"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline
 
 The attached patch only updates revents upon completion of the poll syscall.
 
 --Boundary-00=_oQ+tJpKg7UuAN3l
 Content-Type: text/x-diff;
   charset="iso 8859-15";
   name="fbsdpoll.diff"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
 	filename="fbsdpoll.diff"
 
 --- sys_generic.c.orig	2009-03-09 18:47:28.000000000 -0400
 +++ sys_generic.c	2009-03-11 11:34:09.000000000 -0400
 @@ -73,6 +73,7 @@
  static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
  MALLOC_DEFINE(M_IOV, "iov", "large iov's");
  
 +static int	pollout(struct pollfd *, struct pollfd *, u_int);
  static int	pollscan(struct thread *, struct pollfd *, u_int);
  static int	selscan(struct thread *, fd_mask **, fd_mask **, int);
  static int	dofileread(struct thread *, int, struct file *, struct uio *,
 @@ -976,7 +977,7 @@
  	if (error == EWOULDBLOCK)
  		error = 0;
  	if (error == 0) {
 -		error = copyout(bits, uap->fds, ni);
 +		error = pollout(bits, uap->fds, nfds);
  		if (error)
  			goto out;
  	}
 @@ -988,6 +989,25 @@
  }
  
  static int
 +pollout(fds, ufds, nfd)
 +	struct pollfd *fds;
 +	struct pollfd *ufds;
 +	u_int nfd;
 +{
 +	int error = 0;
 +	u_int i = 0;
 +
 +	while (!error && i++ < nfd) {
 +		error = copyout(&fds->revents, &ufds->revents,
 +		    sizeof(ufds->revents));
 +		fds++;
 +		ufds++;
 +	}
 +
 +	return (error);
 +}
 +
 +static int
  pollscan(td, fds, nfd)
  	struct thread *td;
  	struct pollfd *fds;
 
 --Boundary-00=_oQ+tJpKg7UuAN3l--

From: Robert Watson <rwatson@FreeBSD.org>
To: Kurt Miller <kurt@intricatesoftware.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete
 pollfd struct instead of just revents
Date: Wed, 11 Mar 2009 17:44:42 +0000 (GMT)

 On Wed, 11 Mar 2009, Kurt Miller wrote:
 
 > The attached patch only updates revents upon completion of the poll syscall.
 
 Thanks for the patch -- I'll see about doing a bit of benchmarking (etc); if 
 all goes well I'll attempt to get this in stable/7 by 7.2.
 
 Robert N M Watson
 Computer Laboratory
 University of Cambridge

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130924: commit references a PR
Date: Wed, 11 Mar 2009 22:00:15 +0000 (UTC)

 Author: rwatson
 Date: Wed Mar 11 22:00:03 2009
 New Revision: 189708
 URL: http://svn.freebsd.org/changeset/base/189708
 
 Log:
   When writing out updated pollfd records when returning from
   poll(), only copy out the revents field, not the whole pollfd
   structure.  Otherwise, if the events field is updated
   concurrently by another thread, that update may be lost.
   
   This issue apparently causes problems for the JDK on FreeBSD,
   which expects the Linux behavior of not updating all fields
   (somewhat oddly, Solaris does not implement the required
   behavior, but presumably our adaptation of the JDK is based
   on the Linux port?).
   
   MFC after:      2 weeks
   PR:		kern/130924
   Submitted by:   Kurt Miller <kurt @ intricatesoftware.com>
   Discussed with:	kib
 
 Modified:
   head/sys/kern/sys_generic.c
 
 Modified: head/sys/kern/sys_generic.c
 ==============================================================================
 --- head/sys/kern/sys_generic.c	Wed Mar 11 21:48:36 2009	(r189707)
 +++ head/sys/kern/sys_generic.c	Wed Mar 11 22:00:03 2009	(r189708)
 @@ -76,6 +76,7 @@ static MALLOC_DEFINE(M_IOCTLOPS, "ioctlo
  static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
  MALLOC_DEFINE(M_IOV, "iov", "large iov's");
  
 +static int	pollout(struct pollfd *, struct pollfd *, u_int);
  static int	pollscan(struct thread *, struct pollfd *, u_int);
  static int	pollrescan(struct thread *);
  static int	selscan(struct thread *, fd_mask **, fd_mask **, int);
 @@ -1128,7 +1129,7 @@ done:
  	if (error == EWOULDBLOCK)
  		error = 0;
  	if (error == 0) {
 -		error = copyout(bits, uap->fds, ni);
 +		error = pollout(bits, uap->fds, nfds);
  		if (error)
  			goto out;
  	}
 @@ -1183,6 +1184,26 @@ pollrescan(struct thread *td)
  
  
  static int
 +pollout(fds, ufds, nfd)
 +	struct pollfd *fds;
 +	struct pollfd *ufds;
 +	u_int nfd;
 +{
 +	int error = 0;
 +	u_int i = 0;
 +
 +	for (i = 0; i < nfd; i++) {
 +		error = copyout(&fds->revents, &ufds->revents,
 +		    sizeof(ufds->revents));
 +		if (error)
 +			return (error);
 +		fds++;
 +		ufds++;
 +	}
 +	return (0);
 +}
 +
 +static int
  pollscan(td, fds, nfd)
  	struct thread *td;
  	struct pollfd *fds;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: analyzed->patched 
State-Changed-By: rwatson 
State-Changed-When: Wed Mar 11 22:10:14 UTC 2009 
State-Changed-Why:  
Transition to patched until MFC. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130924 

From: Mike Jakubik <mike.jakubik@intertainservices.com>
To: bug-followup@FreeBSD.org, kurt@intricatesoftware.com
Cc:  
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete
 pollfd struct instead of just revents
Date: Mon, 16 Mar 2009 15:16:54 -0400

 This unfortunately does not solve my problem as posted here:
 
 http://docs.freebsd.org/cgi/getmsg.cgi?fetch=9303+0+current/freebsd-java
 
 However i did not notice any new problems.

From: Kurt Miller <kurt@intricatesoftware.com>
To: Mike Jakubik <mike.jakubik@intertainservices.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete
 pollfd struct instead of just revents
Date: Mon, 16 Mar 2009 16:12:12 -0400

 Mike Jakubik wrote:
 > This unfortunately does not solve my problem as posted here:
 > 
 > http://docs.freebsd.org/cgi/getmsg.cgi?fetch=9303+0+current/freebsd-java
 > 
 > However i did not notice any new problems.
 
 The change to poll(2) is not related to the problem in the message
 above.
 
 It is intended to fix the problem described here:
 
 http://www.freebsd.org/cgi/query-pr.cgi?pr=105482
 
 and
 
 http://mail.openjdk.java.net/pipermail/bsd-port-dev/2009-January/000403.html
 
 Regards,
 -Kurt

From: Mike Jakubik <mike.jakubik@intertainservices.com>
To: bug-followup@FreeBSD.org, kurt@intricatesoftware.com
Cc:  
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete
 pollfd struct instead of just revents
Date: Mon, 16 Mar 2009 16:50:10 -0400

 I'm sorry that was the wrong link. Here is the correct one.
 
 http://docs.freebsd.org/cgi/getmsg.cgi?fetch=9303+0+archive/2009/freebsd-java/20090315.freebsd-java
 

From: Kurt Miller <kurt@intricatesoftware.com>
To: Mike Jakubik <mike.jakubik@intertainservices.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/130924: [kernel] poll(2) system call overwrites complete
 pollfd struct instead of just revents
Date: Mon, 16 Mar 2009 17:45:37 -0400

 Mike Jakubik wrote:
 > I'm sorry that was the wrong link. Here is the correct one.
 > 
 > http://docs.freebsd.org/cgi/getmsg.cgi?fetch=9303+0+archive/2009/freebsd-java/20090315.freebsd-java
 > 
 > 
 
 Ahh - ok. That appears to be an unrelated bug in the application
 you are running.
 
 "IllegalBlockingModeException - if this socket has an associated
 channel, the channel is in non-blocking mode, and there is no connection
 ready to be accepted."
 
 Most likely this is due to the application incorrectly calling
 serversocketchannel.socket().accept() instead of correctly calling
 serversocketchannel.accept().
 
 Regards,
 -Kurt

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/130924: commit references a PR
Date: Mon, 13 Apr 2009 12:50:53 +0000 (UTC)

 Author: rwatson
 Date: Mon Apr 13 11:54:22 2009
 New Revision: 190997
 URL: http://svn.freebsd.org/changeset/base/190997
 
 Log:
   Merge r190996 from head to stable/7:
   
     When writing out updated pollfd records when returning from
     poll(), only copy out the revents field, not the whole pollfd
     structure.  Otherwise, if the events field is updated
     concurrently by another thread, that update may be lost.
   
     This issue apparently causes problems for the JDK on FreeBSD,
     which expects the Linux behavior of not updating all fields
     (somewhat oddly, Solaris does not implement the required
     behavior, but presumably our adaptation of the JDK is based
     on the Linux port?).
   
     MFC after:      2 weeks
     PR:             kern/130924
     Submitted by:   Kurt Miller <kurt @ intricatesoftware.com>
     Discussed with: kib
   
   Approved by:	re (kib)
 
 Modified:
   stable/7/sys/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
   stable/7/sys/dev/ath/ath_hal/   (props changed)
   stable/7/sys/dev/cxgb/   (props changed)
   stable/7/sys/kern/sys_generic.c
 
 Modified: stable/7/sys/kern/sys_generic.c
 ==============================================================================
 --- stable/7/sys/kern/sys_generic.c	Mon Apr 13 10:41:41 2009	(r190996)
 +++ stable/7/sys/kern/sys_generic.c	Mon Apr 13 11:54:22 2009	(r190997)
 @@ -73,6 +73,7 @@ static MALLOC_DEFINE(M_IOCTLOPS, "ioctlo
  static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
  MALLOC_DEFINE(M_IOV, "iov", "large iov's");
  
 +static int	pollout(struct pollfd *, struct pollfd *, u_int);
  static int	pollscan(struct thread *, struct pollfd *, u_int);
  static int	selscan(struct thread *, fd_mask **, fd_mask **, int);
  static int	dofileread(struct thread *, int, struct file *, struct uio *,
 @@ -992,7 +993,7 @@ done_nosellock:
  	if (error == EWOULDBLOCK)
  		error = 0;
  	if (error == 0) {
 -		error = copyout(bits, uap->fds, ni);
 +		error = pollout(bits, uap->fds, nfds);
  		if (error)
  			goto out;
  	}
 @@ -1004,6 +1005,26 @@ done2:
  }
  
  static int
 +pollout(fds, ufds, nfd)
 +	struct pollfd *fds;
 +	struct pollfd *ufds;
 +	u_int nfd;
 +{
 +	int error = 0;
 +	u_int i = 0;
 +
 +	for (i = 0; i < nfd; i++) {
 +		error = copyout(&fds->revents, &ufds->revents,
 +		    sizeof(ufds->revents));
 +		if (error)
 +			return (error);
 +		fds++;
 +		ufds++;
 +	}
 +	return (0);
 +}
 +
 +static int
  pollscan(td, fds, nfd)
  	struct thread *td;
  	struct pollfd *fds;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: rwatson 
State-Changed-When: Mon Apr 13 13:08:36 UTC 2009 
State-Changed-Why:  
Patch now merged to 7.x for inclusion in FreeBSD 7.2.  Thanks for the 
problem report and fix! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=130924 
>Unformatted:
