summaryrefslogtreecommitdiff
path: root/ext/socket/socket.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-25 14:39:15 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-25 14:39:15 +0000
commit52a6728bd2eff3707c459c79262b48be9c19340e (patch)
tree55752977df26a2d6a61f730c57b02ccbbb1c39e3 /ext/socket/socket.c
parent5f305864e5f5067f6f3a123b986ef1473ea45ebb (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.c62
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,