diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-25 14:39:15 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-02-25 14:39:15 +0000 |
commit | 52a6728bd2eff3707c459c79262b48be9c19340e (patch) | |
tree | 55752977df26a2d6a61f730c57b02ccbbb1c39e3 /ext/socket/socket.c | |
parent | 5f305864e5f5067f6f3a123b986ef1473ea45ebb (diff) |
* 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
Diffstat (limited to 'ext/socket/socket.c')
-rw-r--r-- | ext/socket/socket.c | 62 |
1 files changed, 45 insertions, 17 deletions
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, |