From owner-freebsd-bugs@FreeBSD.ORG Thu Feb 19 15:20:01 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 705211065678 for ; Thu, 19 Feb 2009 15:20:01 +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 4A1908FC1B for ; Thu, 19 Feb 2009 15:20: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 n1JFK1ec034575 for ; Thu, 19 Feb 2009 15:20:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.3/8.14.3/Submit) id n1JFK1LN034574; Thu, 19 Feb 2009 15:20:01 GMT (envelope-from gnats) Resent-Date: Thu, 19 Feb 2009 15:20:01 GMT Resent-Message-Id: <200902191520.n1JFK1LN034574@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, Tanaka Akira Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 3746710656C2 for ; Thu, 19 Feb 2009 15:18:18 +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 23AD38FC15 for ; Thu, 19 Feb 2009 15:18:18 +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 n1JFIHNC006982 for ; Thu, 19 Feb 2009 15:18:17 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.14.3/8.14.3/Submit) id n1JFIHQm006981; Thu, 19 Feb 2009 15:18:17 GMT (envelope-from nobody) Message-Id: <200902191518.n1JFIHQm006981@www.freebsd.org> Date: Thu, 19 Feb 2009 15:18:17 GMT From: Tanaka Akira To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Cc: Subject: kern/131876: FD leak by receiving SCM_RIGHTS by recvmsg with small control message buffer 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: Thu, 19 Feb 2009 15:20:01 -0000 >Number: 131876 >Category: kern >Synopsis: FD leak by receiving SCM_RIGHTS by recvmsg with small control message buffer >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: Thu Feb 19 15:20:00 UTC 2009 >Closed-Date: >Last-Modified: >Originator: Tanaka Akira >Release: FreeBSD 6.4-RELEASE amd64 >Organization: AIST >Environment: FreeBSD freebsd.tky.aist.go.jp 6.4-RELEASE FreeBSD 6.4-RELEASE #0: Wed Nov 26 08:21:48 UTC 2008 root@palmer.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64 >Description: When recvmsg receives SCM_RIGHTS control message, it allocates file descriptors and report them in the control message buffer given by the application. If the buffer is too small to record the FDs, recvmsg allocates FDs but doesn't record them. This means the application cannot close those FDs which is not reported. i.e. FDs leaks. >How-To-Repeat: % cat tst.c #include #include #include #include #include #include #define MAX_FDS 10 #define SEND_FDS 10 #define RECV_FDS 3 int main(int argc, char **argv) { int ret; int sv[2]; struct msghdr msg; struct iovec iov; union { struct cmsghdr header; char bytes[CMSG_SPACE(sizeof(int)*MAX_FDS)]; } cmsg; struct cmsghdr *cmh = &cmsg.header, *c; int *fds; int i; char buf[1024]; char cmdline[1024]; snprintf(cmdline, sizeof(cmdline), "fstat -p %u", (unsigned)getpid()); ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); if (ret == -1) { perror("socketpair"); exit(1); } iov.iov_base = "a"; iov.iov_len = 1; cmh->cmsg_len = CMSG_LEN(sizeof(int)*SEND_FDS); cmh->cmsg_level = SOL_SOCKET; cmh->cmsg_type = SCM_RIGHTS; fds = (int *)CMSG_DATA(cmh); for (i = 0; i < SEND_FDS; i++) { fds[i] = 0; /* stdin */ } msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmh; msg.msg_controllen = CMSG_SPACE(sizeof(int)*SEND_FDS); msg.msg_flags = 0; ret = sendmsg(sv[0], &msg, 0); if (ret == -1) { perror("sendmsg"); exit(1); } system(cmdline); /* fstat -p $$ before recvmsg */ iov.iov_base = buf; iov.iov_len = sizeof(buf); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmh; msg.msg_controllen = CMSG_SPACE(sizeof(int)*RECV_FDS); msg.msg_flags = 0; printf("before recvmsg: msg_controllen=%d\n", msg.msg_controllen); ret = recvmsg(sv[1], &msg, 0); if (ret == -1) { perror("sendmsg"); exit(1); } printf("after recvmsg: msg_controllen=%d\n", msg.msg_controllen); for (c = CMSG_FIRSTHDR(&msg); c != NULL; c = CMSG_NXTHDR(&msg, c)) { if (c->cmsg_len == 0) { printf("cmsg_len is zero\n"); exit(1); } if (c->cmsg_level == SOL_SOCKET && c->cmsg_type == SCM_RIGHTS) { int *fdp, *end; printf("cmsg_len=%d\n", c->cmsg_len); fdp = (int *)CMSG_DATA(c); end = (int *)((char *)c + c->cmsg_len); for (i = 0; fdp+i < end; i++) { printf("fd[%d]=%d\n", i, fdp[i]); } } } system(cmdline); /* fstat -p $$ after recvmsg */ return 0; } % gcc -Wall tst.c % ./a.out USER CMD PID FD MOUNT INUM MODE SZ|DV R/W akr a.out 9822 root / 2 drwxr-xr-x 512 r akr a.out 9822 wd / 32142 drwxr-xr-x 512 r akr a.out 9822 text / 32138 -rwxr-xr-x 9286 r akr a.out 9822 0 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 1 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 2 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 3* local stream ffffff00613da320 <-> ffffff00613da258 akr a.out 9822 4* local stream ffffff00613da258 <-> ffffff00613da320 before recvmsg: msg_controllen=32 after recvmsg: msg_controllen=32 cmsg_len=56 fd[0]=5 fd[1]=6 fd[2]=7 fd[3]=8 fd[4]=0 fd[5]=0 fd[6]=0 fd[7]=0 fd[8]=0 fd[9]=0 USER CMD PID FD MOUNT INUM MODE SZ|DV R/W akr a.out 9822 root / 2 drwxr-xr-x 512 r akr a.out 9822 wd / 32142 drwxr-xr-x 512 r akr a.out 9822 text / 32138 -rwxr-xr-x 9286 r akr a.out 9822 0 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 1 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 2 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 3* local stream ffffff00613da320 <-> ffffff00613da258 akr a.out 9822 4* local stream ffffff00613da258 <-> ffffff00613da320 akr a.out 9822 5 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 6 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 7 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 8 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 9 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 10 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 11 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 12 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 13 /dev 97 crw--w---- ttyp0 rw akr a.out 9822 14 /dev 97 crw--w---- ttyp0 rw This program sends 10 file descriptors via UNIX domain socket pair and receives some of them using a small buffer. This result shows * recvmsg allocates 10 FDs (5-14) * 4 of them (5-8) are reported to the application * 6 of them (9-14) are not reported to the application So the application cannot close the 6 file descriptors. >Fix: >Release-Note: >Audit-Trail: >Unformatted: