From owner-freebsd-bugs@FreeBSD.ORG Sat Jan 10 17:40:02 2009 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 088DB1065672 for ; Sat, 10 Jan 2009 17:40:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id D803D8FC12 for ; Sat, 10 Jan 2009 17:40:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.3/8.14.3) with ESMTP id n0AHe1Rn031000 for ; Sat, 10 Jan 2009 17:40:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n0AHe1lw030999; Sat, 10 Jan 2009 17:40:01 GMT (envelope-from gnats) Resent-Date: Sat, 10 Jan 2009 17:40:01 GMT Resent-Message-Id: <200901101740.n0AHe1lw030999@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Ivan Shcheklein Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C6D141065672 for ; Sat, 10 Jan 2009 17:39:07 +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 B3DF08FC2C for ; Sat, 10 Jan 2009 17:39:07 +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 n0AHd7Zw049482 for ; Sat, 10 Jan 2009 17:39:07 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.3/8.14.3/Submit) id n0AHd7t3049481; Sat, 10 Jan 2009 17:39:07 GMT (envelope-from nobody) Message-Id: <200901101739.n0AHd7t3049481@www.freebsd.org> Date: Sat, 10 Jan 2009 17:39:07 GMT From: Ivan Shcheklein To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: kern/130348: [socket] accept() prematurely allocates an inheritable descriptor X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 10 Jan 2009 17:40:02 -0000 >Number: 130348 >Category: kern >Synopsis: [socket] accept() prematurely allocates an inheritable descriptor >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Jan 10 17:40:01 UTC 2009 >Closed-Date: >Last-Modified: >Originator: Ivan Shcheklein >Release: FreeBSD 7.1 >Organization: ISP RAS >Environment: FreeBSD freebsd2.localdomain 7.1-RELEASE FreeBSD 7.1-RELEASE #0: Fri Jan 9 23:36:55 MSK 2009 modis@freebsd2.localdomain:/usr/obj/usr/src/sys/GENERIC i386 >Description: kern_accept() allocates a file descriptor before it is blocked until a connection is present. This descriptor could be unexpectedly inherited if the process calls exec() in a different thread. It means that the child process may obtain a connected descriptor it doesn't know anything about. Moreover, parent process also doesn't expect that there are references on this descriptor in the system. Seems this behaviour appeared first in 1.186 revision: http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/uipc_syscalls.c#rev1.186: "Reorganize the optimistic concurrency behavior in accept1() to always allocate a file descriptor with falloc() so that if we do find a socket, we don't have to encounter the "Oh, there wasn't a socket" race that can occur if falloc() sleeps in the current code, which broke inbound accept() ordering, not to mention requiring backing out socket state changes in a way that raced with the protocol level. We may want to add a lockless read of the queue state if polling of empty queues proves to be important to optimize." >How-To-Repeat: 1. Build (cc -Wall server.c -o server) the following code: #include #include #include #include #include #include #include #include #include int main() { int fd, error = 0; struct sockaddr_in in; struct hostent *hp; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); error = -1; goto done; } if((hp = gethostbyname("0.0.0.0")) == NULL) { perror("gethostbyname"); error = -2; goto done; } memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(5050); memcpy(&in.sin_addr, hp->h_addr, hp->h_length); if (bind(fd, (struct sockaddr *)&in, sizeof(in)) < 0) { perror("bind"); error = -3; goto done; } if (listen(fd, 10) < 0) { perror("listen"); error = -4; goto done; } if (accept(fd,0,0) < 0) { perror("accept"); error = -5; } done: close(fd); return error; } 2. Run "lsof | grep server". You will see a number of file descriptors and among them should be something like this: server 1076 root 3u IPv4 0xc50ec910 0t0 TCP *:mmcc (LISTEN) server 1076 root 4 0xc584b090 file struct, ty=0, op=0xc0979ec0 The first one (3u) is the descriptor we call accept() on. The second one (4) is a file struct which is allocated by falloc() in kern_accept(). It is inheritable. Therefore child may obtain a connection it doesn't expect. >Fix: >Release-Note: >Audit-Trail: >Unformatted: