Date: Thu, 27 Jul 2006 15:06:40 -0700 (PDT) From: Young Hyun <youngh@caida.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: kern/100940: passing file descriptor over datagram UNIX domain socket crashes kernel Message-ID: <200607272206.k6RM6euW001616@brak.caida.org> Resent-Message-ID: <200607272210.k6RMAHk6083982@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 100940 >Category: kern >Synopsis: passing file descriptor over datagram UNIX domain socket crashes kernel >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: Thu Jul 27 22:10:16 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Young Hyun >Release: FreeBSD 6.1-STABLE-200607 i386 >Organization: CAIDA/UCSD >Environment: System: FreeBSD brak.caida.org 6.1-STABLE-200607 FreeBSD 6.1-STABLE-200607 #0: Wed Jul 26 18:32:47 PDT 2006 root@brak.caida.org:/usr/src/sys/i386/compile/SMP i386 >Description: Passing file descriptors over a SOCK_DGRAM UNIX domain socket crashes the kernel with "Fatal trap 12: page fault while in kernel mode". This bug is probably closely related to (but not identical with) PR kern/93914. In PR 93914, the sample code passes file descriptors over a SOCK_STREAM socket, and it no longer causes a kernel crash under 6.1-STABLE. My own SOCK_STREAM-based test program that crashes the 5.4 kernel also fails to crash the 6.1 kernel. In the present case, the kernel crashes in code specific to the handling of SOCK_DGRAM sockets (though, of course, that doesn't exclude the possibility of the same underlying problem behind this and PR 93914 and which somehow only got masked for the SOCK_STREAM case in 6.1-STABLE). #0 doadump () at pcpu.h:165 #1 0xc06632ca in boot (howto=260) at ../../../kern/kern_shutdown.c:409 #2 0xc0663621 in panic (fmt=0xc08913da "%s") at ../../../kern/kern_shutdown.c:565 #3 0xc085bfd6 in trap_fatal (frame=0xde946b54, eva=8) at ../../../i386/i386/trap.c:836 #4 0xc085bcdf in trap_pfault (frame=0xde946b54, usermode=0, eva=8) at ../../../i386/i386/trap.c:744 #5 0xc085b8d5 in trap (frame= {tf_fs = -1017839608, tf_es = -1014300632, tf_ds = 40, tf_edi = -1016513388, tf_esi = -1017187284, tf_ebp = -560698452, tf_isp = -560698496, tf_ebx = 0, tf_edx = 0, tf_ecx = 0, tf_eax = 0, tf_trapno = 12, tf_err = 0, tf_eip = -1066768486, tf_cs = 32, tf_eflags = 66118, tf_esp = -560698440, tf_ss = -1065577831}) at ../../../i386/i386/trap.c:434 #6 0xc08484da in calltrap () at ../../../i386/i386/exception.s:139 #7 0xc06a679a in uipc_send (so=0xc35ef42c, flags=0, m=0xc38f3500, nam=0xc35474f0, control=0xc351b900, td=0xc3552900) at ../../../kern/uipc_usrreq.c:432 #8 0xc069dc8f in sosend (so=0xc35ef42c, addr=0xc35474f0, uio=0xde946c3c, top=0xc38f3500, control=0xc351d600, flags=0, td=0xc3552900) at ../../../kern/uipc_socket.c:836 #9 0xc06a36a5 in kern_sendit (td=0xc3552900, s=3, mp=0xde946cb4, flags=0, control=0xc351d600, segflg=UIO_USERSPACE) at ../../../kern/uipc_syscalls.c:772 #10 0xc06a355f in sendit (td=0xc3552900, s=3, mp=0xde946cb4, flags=0) at ../../../kern/uipc_syscalls.c:712 #11 0xc06a3976 in sendmsg (td=0xc3552900, uap=0xde946d04) at ../../../kern/uipc_syscalls.c:920 #12 0xc085c31b in syscall (frame= {tf_fs = 671350843, tf_es = -1078001605, tf_ds = -1078001605, tf_edi = 671410632, tf_esi = -1077940984, tf_ebp = -1077941096, tf_isp = -560698012, tf_ebx = 1, tf_edx = 17, tf_ecx = 17, tf_eax = 28, tf_trapno = 32, tf_err = 2, tf_eip = 672073267, tf_cs = 51, tf_eflags = 658, tf_esp = -1077941300, tf_ss = 59}) at ../../../i386/i386/trap.c:981 #13 0xc084852f in Xint0x80_syscall () at ../../../i386/i386/exception.s:200 #14 0x00000033 in ?? () Previous frame inner to this frame (corrupt stack?) (kgdb) up 7 #7 0xc06a679a in uipc_send (so=0xc35ef42c, flags=0, m=0xc38f3500, nam=0xc35474f0, control=0xc351b900, td=0xc3552900) at ../../../kern/uipc_usrreq.c:432 432 so2 = unp->unp_conn->unp_socket; (kgdb) p unp->unp_conn $1 = (struct unpcb *) 0x0 (kgdb) p *unp $2 = {unp_link = {le_next = 0xc3693a64, le_prev = 0xc09a7098}, unp_socket = 0xc35ef42c, unp_vnode = 0xc38d2660, unp_ino = 0, unp_conn = 0x0, unp_refs = {lh_first = 0x0}, unp_reflink = {le_next = 0x0, le_prev = 0xc36938d8}, unp_addr = 0xc3547390, unp_cc = 0, unp_mbcnt = 0, unp_gencnt = 100, unp_flags = 0, unp_peercred = {cr_version = 0, cr_uid = 0, cr_ngroups = 0, cr_groups = {0 <repeats 16 times>}, _cr_unused1 = 0x0}} (kgdb) >How-To-Repeat: Execute the attached sample code, and let it run for a few minutes. The sample code is the same one supplied for PR kern/91224, except there it caused a crash in a different part of the kernel (PR 91224 is closed). >Fix: --- AF_UNIX-FreeBSD-crash.c begins here --- #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <fcntl.h> #include <unistd.h> #define PATH "/tmp/123" #define PATH_TMP "/tmp/123.tmp" #define SOME_FILE "/etc/passwd" struct mycmsghdr { struct cmsghdr hdr; int fd; }; extern errno; void server(); void client(); int main() { switch ( fork()) { case -1: printf( "fork error %d\n",errno); break; case 0: for (;;) client(); default: server(); } } void server() { struct sockaddr_un addr; struct msghdr mymsghdr; struct mycmsghdr ancdbuf; char data[ 1]; int sockfd, len, fd; if ( unlink( PATH) == -1) printf( "unlink error %d\n",errno); if (( sockfd = socket( AF_UNIX,SOCK_DGRAM,0)) == -1) printf( "socket error %d\n",errno); strcpy( addr.sun_path,PATH); addr.sun_len = sizeof( addr.sun_len) + sizeof( addr.sun_family) + strlen( addr.sun_path); addr.sun_family = AF_UNIX; if ( bind( sockfd,(struct sockaddr *) &addr,addr.sun_len) == -1) printf( "bind error %d\n",errno); for (;;) { if (( fd = open( SOME_FILE,O_RDONLY)) == -1) printf( "open file error %d\n",errno); len = sizeof( addr.sun_path); if ( recvfrom( sockfd,&data,sizeof( data),0, (struct sockaddr *) &addr,&len) == -1) printf( "recvfrom error %d\n",errno); ancdbuf.hdr.cmsg_len = sizeof( ancdbuf); ancdbuf.hdr.cmsg_level = SOL_SOCKET; ancdbuf.hdr.cmsg_type = SCM_RIGHTS; ancdbuf.fd = fd; mymsghdr.msg_name = (caddr_t) &addr; mymsghdr.msg_namelen = len; mymsghdr.msg_iov = NULL; mymsghdr.msg_iovlen = 0; mymsghdr.msg_control = (caddr_t) &ancdbuf; mymsghdr.msg_controllen = ancdbuf.hdr.cmsg_len; mymsghdr.msg_flags = 0; if ( sendmsg( sockfd,&mymsghdr,0) == -1) printf( "sendmsg error %d\n",errno); close( fd); } } void client() { struct sockaddr_un addr_s, addr_c; struct mycmsghdr ancdbuf; struct msghdr mymsghdr; char data[ 1]; int sockfd, len, fd; if (( sockfd = socket( AF_UNIX,SOCK_DGRAM,0)) == -1) printf( "socket error %d\n",errno); if ( unlink( PATH_TMP) == -1) printf( "unlink error %d\n",errno); strcpy( addr_c.sun_path,PATH_TMP); addr_c.sun_len = sizeof( addr_c.sun_len) + sizeof(addr_c.sun_family) + strlen( addr_c.sun_path); addr_c.sun_family = AF_UNIX; strcpy( addr_s.sun_path,PATH); addr_s.sun_len = sizeof( addr_s.sun_len) + sizeof(addr_s.sun_family) + strlen( addr_s.sun_path); addr_s.sun_family = AF_UNIX; if ( bind( sockfd,(struct sockaddr*) &addr_c,addr_c.sun_len) == -1) printf( "bind error %d\n",errno); if ( sendto( sockfd,&data,sizeof( data),0,(struct sockaddr *) &addr_s, addr_s.sun_len) == -1) printf( "sendto error %d\n",errno); len = addr_s.sun_len; ancdbuf.hdr.cmsg_len = sizeof( ancdbuf); ancdbuf.hdr.cmsg_level = SOL_SOCKET; ancdbuf.hdr.cmsg_type = SCM_RIGHTS; mymsghdr.msg_name = NULL; mymsghdr.msg_namelen = 0; mymsghdr.msg_iov = NULL; mymsghdr.msg_iovlen = 0; mymsghdr.msg_control = (caddr_t) &ancdbuf; mymsghdr.msg_controllen = ancdbuf.hdr.cmsg_len; mymsghdr.msg_flags = 0; if ( recvmsg( sockfd,&mymsghdr,0) == -1) printf( "recvmsg error %d\n",errno); fd = ancdbuf.fd; close(fd); close( sockfd); } --- AF_UNIX-FreeBSD-crash.c ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200607272206.k6RM6euW001616>