Issue #5075 has been reported by Yui NARUSE.

----------------------------------------
Bug #5075: invalid *fdp in Mac OS X and FreeBSD over recvmsg with SCM_RIGHTS
http://redmine.ruby-lang.org/issues/5075

Author: Yui NARUSE
Status: Assigned
Priority: Normal
Assignee: Akira Tanaka
Category: ext
Target version: 1.9.3
ruby -v: ruby 1.9.4dev (2011-07-22 trunk 32604) [x86_64-freebsd8.2]


Mac OS X と FreeBSD にて、存在しない fd を close してしまう問題について、
現在 r32598 で応急処置が施されていますが、根本的な原因について、
sys/kern/uipc_socket.c を見るに、
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/uipc_socket.c?rev=1.340.2.6.2.1;content-type=text%2Fplain;only_with_tag=RELENG_8_2_0_RELEASE

	 * Process one or more MT_CONTROL mbufs present before any data mbufs
	 * in the first mbuf chain on the socket buffer.  If MSG_PEEK, we
	 * just copy the data; if !MSG_PEEK, we call into the protocol to
	 * perform externalization (or freeing if controlp == NULL).

とあるので、recvmsg に MSG_PEEK を与えた場合は invalid なものが返ってくると思うのですが。

ちなみに、以下のような printf パッチをあてて走らせると、discard_cmsg() に来たものは全て invalid になっています。

diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c
index 61e0576..ad44fb4 100644
--- a/ext/socket/ancdata.c
+++ b/ext/socket/ancdata.c
@@ -1379,6 +1379,7 @@ rb_recvmsg(int fd, struct msghdr *msg, int flags)
 static void
 discard_cmsg(struct cmsghdr *cmh, char *msg_end)
 {
+    fprintf(stderr, "discard_cmsg-begin\n");
     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);
@@ -1391,12 +1392,18 @@ discard_cmsg(struct cmsghdr *cmh, char *msg_end)
              */
             struct stat buf;
             if (fstat(*fdp, &buf) == 0) {
+           fprintf(stderr, "fdp: %d is valid   (%p %p %p)\n", *fdp,fdp,end,msg_end);
                 rb_update_max_fd(*fdp);
                 close(*fdp);
             }
+           else {
+               fprintf(stderr, "fdp: %d is invalid (%p %p %p)\n", *fdp,fdp,end,msg_end);
+               rb_backtrace();
+           }
             fdp++;
         }
     }
+    fprintf(stderr, "discard_cmsg-end\n");
 }
 #endif
 
@@ -1432,6 +1439,7 @@ make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
               (char *)fdp + sizeof(int) <= msg_end) {
             int fd = *fdp;
             struct stat stbuf;
+  fprintf(stderr,"makeiounixr: %d (%p %p %p)\n", *fdp,fdp,end,msg_end);
             VALUE io;
             if (fstat(fd, &stbuf) == -1)
                 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");


-- 
http://redmine.ruby-lang.org