Date: Fri, 18 Jan 2008 17:28:52 GMT From: James Juran <james.juran@baesystems.com> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/119778: unp_connect() locking problems with early returns Message-ID: <200801181728.m0IHSqHt000904@www.freebsd.org> Resent-Message-ID: <200801181740.m0IHe00s044699@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 119778 >Category: kern >Synopsis: unp_connect() locking problems with early returns >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Jan 18 17:40:00 UTC 2008 >Closed-Date: >Last-Modified: >Originator: James Juran >Release: 7.0-RC1 >Organization: BAE Systems >Environment: N/A >Description: There are two early returns in unp_connect() that need to re-acquire the UNP global lock before returning. I tested on the December snapshot of CURRENT-8.0, but the same problem occurs in RELENG_7. I posted this problem to freebsd-net (http://lists.freebsd.org/pipermail/freebsd-net/2008-January/016392.html) but did not receive a response. >How-To-Repeat: This program will trigger a panic on a WITNESS-enabled system: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/un.h> int main(void) { int s; struct sockaddr_un un; s = socket(PF_LOCAL, SOCK_STREAM, 0); if (s == -1) { perror("socket"); exit(1); } memset(&un, 0, sizeof(un)); un.sun_family = AF_UNIX; if ((connect(s, (struct sockaddr *)&un, 2)) == -1) { perror("connect"); exit(1); } return 0; } >Fix: I believe this patch will fix the problem, but unfortunately I do not have time to test it. Could someone please try this out? Instead of this approach, it may be possible to move the unlocking to after the early returns are done, but I have not analyzed what impact this would have. Index: uipc_usrreq.c =================================================================== RCS file: /home/ncvs/src/sys/kern/uipc_usrreq.c,v retrieving revision 1.210 diff -u -p -r1.210 uipc_usrreq.c --- uipc_usrreq.c 1 Jan 2008 01:46:42 -0000 1.210 +++ uipc_usrreq.c 3 Jan 2008 02:53:51 -0000 @@ -1129,13 +1129,16 @@ unp_connect(struct socket *so, struct so KASSERT(unp != NULL, ("unp_connect: unp == NULL")); len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); - if (len <= 0) + if (len <= 0) { + UNP_GLOBAL_WLOCK(); return (EINVAL); + } strlcpy(buf, soun->sun_path, len + 1); UNP_PCB_LOCK(unp); if (unp->unp_flags & UNP_CONNECTING) { UNP_PCB_UNLOCK(unp); + UNP_GLOBAL_WLOCK(); return (EALREADY); } unp->unp_flags |= UNP_CONNECTING; >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801181728.m0IHSqHt000904>