From 52a6728bd2eff3707c459c79262b48be9c19340e Mon Sep 17 00:00:00 2001 From: akr Date: Wed, 25 Feb 2009 14:39:15 +0000 Subject: * ext/socket/socket.c (unix_recv_io): prevent FD leak when 2 fd is sent on LP64 platform. (rsock_discard_cmsg_resource): new function. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@22633 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ ext/socket/socket.c | 62 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13738fdd51..78733f210a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Feb 25 23:37:56 2009 Tanaka Akira + + * ext/socket/socket.c (unix_recv_io): prevent FD leak when 2 fd is + sent on LP64 platform. + (rsock_discard_cmsg_resource): new function. + Wed Feb 25 22:54:13 2009 NAKAMURA Usaku * win32/Makefile.sub (config.status): use un.rb as cp instead of diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 4a9857cca0..1b12cdd092 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -1950,15 +1950,15 @@ unix_recvfrom(argc, argv, sock) } #if defined(HAVE_ST_MSG_CONTROL) && defined(SCM_RIGHTS) -#define FD_PASSING_BY_MSG_CONTROL 1 +# define FD_PASSING_BY_MSG_CONTROL 1 #else -#define FD_PASSING_BY_MSG_CONTROL 0 +# define FD_PASSING_BY_MSG_CONTROL 0 #endif #if defined(HAVE_ST_MSG_ACCRIGHTS) -#define FD_PASSING_BY_MSG_ACCRIGHTS 1 +# define FD_PASSING_BY_MSG_ACCRIGHTS 1 #else -#define FD_PASSING_BY_MSG_ACCRIGHTS 0 +# define FD_PASSING_BY_MSG_ACCRIGHTS 0 #endif static VALUE @@ -2027,6 +2027,28 @@ unix_send_io(sock, val) #endif } +#if defined(HAVE_RECVMSG) && FD_PASSING_BY_MSG_CONTROL +void +rsock_discard_cmsg_resource(struct msghdr *mh) +{ + struct cmsghdr *cmh; + + if (mh->msg_controllen == 0) + return; + + for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) { + if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) { + int *fdp = (int *)CMSG_DATA(cmh); + int *end = (int *)((char *)cmh + cmh->cmsg_len); + while (fdp < end) { + close(*fdp); + fdp++; + } + } + } +} +#endif + #if defined(HAVE_RECVMSG) && (FD_PASSING_BY_MSG_CONTROL || FD_PASSING_BY_MSG_ACCRIGHTS) static void thread_read_select(fd) @@ -2097,20 +2119,10 @@ unix_recv_io(argc, argv, sock) rb_sys_fail("recvmsg(2)"); #if FD_PASSING_BY_MSG_CONTROL - if (msg.msg_controllen < CMSG_LEN(sizeof(int))) { + if (msg.msg_controllen < sizeof(struct cmsghdr)) { rb_raise(rb_eSocket, - "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)", - (int)msg.msg_controllen, (int)CMSG_LEN(sizeof(int))); - } - if (CMSG_SPACE(sizeof(int)) < msg.msg_controllen) { - rb_raise(rb_eSocket, - "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)", - (int)msg.msg_controllen, (int)CMSG_SPACE(sizeof(int))); - } - if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) { - rb_raise(rb_eSocket, - "file descriptor was not passed (cmsg_len=%d, %d expected)", - cmsg.hdr.cmsg_len, CMSG_LEN(sizeof(int))); + "file descriptor was not passed (msg_controllen=%d smaller than sizeof(struct cmsghdr)=%d)", + (int)msg.msg_controllen, (int)sizeof(struct cmsghdr)); } if (cmsg.hdr.cmsg_level != SOL_SOCKET) { rb_raise(rb_eSocket, @@ -2122,6 +2134,22 @@ unix_recv_io(argc, argv, sock) "file descriptor was not passed (cmsg_type=%d, %d expected)", cmsg.hdr.cmsg_type, SCM_RIGHTS); } + if (msg.msg_controllen < CMSG_LEN(sizeof(int))) { + rb_raise(rb_eSocket, + "file descriptor was not passed (msg_controllen=%d smaller than CMSG_LEN(sizeof(int))=%d)", + (int)msg.msg_controllen, (int)CMSG_LEN(sizeof(int))); + } + if (CMSG_SPACE(sizeof(int)) < msg.msg_controllen) { + rb_raise(rb_eSocket, + "file descriptor was not passed (msg_controllen=%d bigger than CMSG_SPACE(sizeof(int))=%d)", + (int)msg.msg_controllen, (int)CMSG_SPACE(sizeof(int))); + } + if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) { + rsock_discard_cmsg_resource(&msg); + rb_raise(rb_eSocket, + "file descriptor was not passed (cmsg_len=%d, %d expected)", + (int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int))); + } #else if (msg.msg_accrightslen != sizeof(fd)) { rb_raise(rb_eSocket, -- cgit v1.2.3