Calling sendmsg() from Ruby

A

Andre Nathan

Hello

I'm trying to call the sendmsg() system call from ruby in a way that
allocates space for the kernel to set the user credentials in the
appropriate structures (this is in FreeBSD i386).

I'm using the code below, which gives me an EFAULT (bad address) error,
and I cannot see what I'm doing wrong here... any help would be awesome.

The equivalent C code (which works) follows after the ruby attempt.

def pointer(buf)
[buf].pack("P").unpack("L_").first
end

def sendmsg(fd, buf)
iov = [buf, buf.length].pack("PI_")

cmsg_len = 96 # CMSG_LEN(sizeof(struct cmsgcred))
cmsg_space = 96 # CMSG_SPACE(sizeof(struct cmsgcred))
cmsg_level = 0xffff # SOL_SOCKET
cmsg_type = 0x03 # SCM_CREDS
cmsg_data = ["\x00" * cmsg_space].pack("P")

cmsghdr = [
cmsg_len,
cmsg_level,
cmsg_type,
cmsg_data
].pack("I_i_i_P")

msg_control_ptr = pointer(cmsghdr)
msg_controllen = cmsg_space

msghdr = [
0, # msg_name
0, # msg_namelen
pointer(iov), # msg_iov
1, # msg_iovlen
pointer(cmsghdr), # msg_control
cmsg_space, # msg_controllen
0 # msg_flags
].pack("L_i_L_i_L_i_i_")

syscall(28, pointer(msghdr), 0) # 28 is sendmsg()
end

Here's the C snippet:

union {
struct cmsghdr hdr;
char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
} cmsg;
struct iovec iov[1];

struct msghdr msg;
iov[0].iov_base = (void *)buf;
iov[0].iov_len = count;

memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 1;

msg.msg_control = (caddr_t)&cmsg;
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
memset(&cmsg, 0, sizeof(cmsg));
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_CREDS;

sendmsg(fd, &msg, 0);

Thanks in advance,
Andre
 
A

Andre Nathan

I'm trying to call the sendmsg() system call from ruby in a way that
allocates space for the kernel to set the user credentials in the
appropriate structures (this is in FreeBSD i386).

For the record, this is how I got it to work. I was wrong in the way I
was packing cmsg_data, and I also had forgotten passing an argument to
the syscall (duh).

def sendmsg(fd, buf)
iov = [buf, buf.length].pack("pI_")

cmsg_len = 96 # CMSG_LEN(sizeof(struct cmsgcred))
cmsg_space = 96 # CMSG_SPACE(sizeof(struct cmsgcred))
cmsg_level = 0xffff # SOL_SOCKET
cmsg_type = 0x03 # SCM_CREDS
cmsg_data_len = 84

cmsghdr = ([
cmsg_len,
cmsg_level,
cmsg_type
] + [0] * cmsg_data_len).pack("I_i_i_C#{cmsg_data_len}")

msg_control_ptr = pointer(cmsghdr)
msg_controllen = cmsg_space

msghdr = [
0, # msg_name
0, # msg_namelen
pointer(iov), # msg_iov
1, # msg_iovlen
pointer(cmsghdr), # msg_control
cmsg_space, # msg_controllen
0 # msg_flags
].pack("L_i_L_i_L_i_i_")

syscall(28, fd.fileno, pointer(msghdr), 0)
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top