[netfilter-cvslog] r4320 - trunk/nfsim/core
rusty at netfilter.org
rusty at netfilter.org
Thu Oct 6 20:21:58 CEST 2005
Author: rusty at netfilter.org
Date: 2005-10-06 20:21:57 +0200 (Thu, 06 Oct 2005)
New Revision: 4320
Modified:
trunk/nfsim/core/fakesockopt.c
trunk/nfsim/core/message.c
trunk/nfsim/core/nfsockopt.h
Log:
Glibc seems to randomize mallocs now, so replay fails. Make --failtest use fd passing (from K42 test code via Chris Yeoh) instead of trying to replay. Should be faster, too.
Modified: trunk/nfsim/core/fakesockopt.c
===================================================================
--- trunk/nfsim/core/fakesockopt.c 2005-10-06 12:30:45 UTC (rev 4319)
+++ trunk/nfsim/core/fakesockopt.c 2005-10-06 18:21:57 UTC (rev 4320)
@@ -33,6 +33,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <sys/wait.h>
#include <dlfcn.h>
@@ -126,10 +127,40 @@
(*__close)(sd);
}
+static int recv_fd(int from_fd)
+{
+ struct iovec iov[1];
+ struct msghdr msg;
+ char buf[1];
+ char cmsgbuf[1000];
+ struct cmsghdr *cmsg;
+ int ret;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof(buf);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof(cmsgbuf);
+ msg.msg_flags = MSG_WAITALL;
+
+ ret = recvmsg(from_fd, &msg, 0);
+ if (ret < 0) {
+ perror("recv_fd failed");
+ exit(EXIT_FAILURE);
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ return *((int*)CMSG_DATA(cmsg));
+}
+
static void handle_kernelop(int fd, struct nf_userspace_message *msg)
{
struct nf_userspace_message *reply;
- int m_offset = sizeof(struct nf_userspace_message);
+ int pid, m_offset = sizeof(struct nf_userspace_message);
assert(msg->type = UM_KERNELOP);
@@ -150,7 +181,21 @@
reply->len = msg->args[2];
break;
-
+ case KOP_FORK:
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ }
+ reply = msg;
+ if (pid != 0) {
+ /* Retval for parent is status of child. */
+ waitpid(pid, &msg->retval, 0);
+ break;
+ }
+ reply->retval = getpid();
+ break;
+
default:
fprintf(stderr, "Invalid kernelop opcode\n");
return;
@@ -165,6 +210,14 @@
if (reply != msg)
free(reply);
+
+ if (msg->opcode == KOP_FORK && pid == 0) {
+ /* Child: get own fd for output. */
+ int newfd = recv_fd(sd);
+ dup2(newfd, STDOUT_FILENO);
+ dup2(newfd, STDERR_FILENO);
+ close(newfd);
+ }
}
/* send a syscall and wait for a response, processing any kernelops
Modified: trunk/nfsim/core/message.c
===================================================================
--- trunk/nfsim/core/message.c 2005-10-06 12:30:45 UTC (rev 4319)
+++ trunk/nfsim/core/message.c 2005-10-06 18:21:57 UTC (rev 4320)
@@ -32,10 +32,40 @@
#include <linux/netfilter_ipv4/ip_tables.h>
static int sock[2]; /* socket for messages. 0 = parent, 1 = child */
+static bool forked;
static void send_userspace_message(struct nf_userspace_message *msg);
-static void handle_userspace_message(void);
+static void send_fd(int dest_fd, int fd)
+{
+ struct iovec iov[1];
+ struct cmsghdr *cmsg;
+ struct msghdr msg;
+ char buf[1];
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof(buf);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = malloc(CMSG_SPACE(sizeof(fd)));
+ msg.msg_controllen = CMSG_SPACE(sizeof(fd));
+ msg.msg_flags = 0;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int*)CMSG_DATA(cmsg) = fd;
+
+ msg.msg_controllen = CMSG_SPACE(sizeof(fd));
+
+ if (sendmsg(dest_fd, &msg, 0) < 0)
+ barf_perror("sendfd failed");
+}
+
void message_init(void)
{
sigset_t ss;
@@ -70,42 +100,23 @@
sigprocmask(SIG_UNBLOCK, &ss, NULL);
}
-struct message
-{
- struct list_head list;
- bool outgoing;
- struct nf_userspace_message msg;
- char data[0];
-};
-
struct program
{
- char *name;
- struct list_head messages;
pid_t pid;
+ int status;
int fd;
- int argc;
- char *argv[0];
};
static struct program *currprog;
void start_program(const char *name, int argc, char *argv[])
{
- int i, childfd[2];
+ int childfd[2];
assert(!currprog);
- currprog = talloc_size(NULL, sizeof(*currprog)
- + (argc+1)*sizeof(char *));
+ currprog = talloc(NULL, struct program);
- currprog->name = talloc_strdup(currprog, name);
- currprog->argc = argc;
- for (i = 0; i < argc; i++)
- currprog->argv[i] = talloc_strdup(currprog, argv[i]);
- currprog->argv[argc] = NULL;
- INIT_LIST_HEAD(&currprog->messages);
-
if (pipe(childfd) != 0)
- barf_perror("%s pipe", currprog->name);
+ barf_perror("%s pipe", name);
fflush(stdout);
currprog->pid = fork();
@@ -117,23 +128,37 @@
dup2(childfd[1], STDERR_FILENO);
if (setenv("LD_PRELOAD", "fakesockopt.so.1.0", 1))
barf("putenv failed");
- execvp(currprog->name, currprog->argv);
- fprintf(stderr, "Could not exec %s!\n", currprog->name);
+ execvp(name, argv);
+ fprintf(stderr, "Could not exec %s!\n", name);
exit(EXIT_FAILURE);
}
close(childfd[1]);
currprog->fd = childfd[0];
+ currprog->status = -1;
}
int end_program(const char *name)
{
int status;
- while (waitpid(currprog->pid, &status, 0) <= 0)
- if (errno != EINTR)
- barf_perror("Waiting for child %s", name);
+ if (forked) {
+ /* Damn UNIX! Not our child. */
+ /* Might have been read already. */
+ status = currprog->status;
+ if (status == -1) {
+ struct nf_userspace_message msg;
+ if (read(sock[0], &msg, sizeof(msg)) != sizeof(msg))
+ barf_perror("Reading child status");
+ status = msg.retval;
+ }
+ } else {
+ while (waitpid(currprog->pid, &status, 0) <= 0)
+ if (errno != EINTR)
+ barf_perror("Waiting for child %s", name);
+ }
+
close(currprog->fd);
talloc_free(currprog);
currprog = NULL;
@@ -141,43 +166,6 @@
return status;
}
-static void add_message(bool outgoing, struct nf_userspace_message *msg,
- int datalen, const void *data)
-{
- struct message *new;
-
- assert(currprog);
- new = talloc_size(currprog, sizeof(*new) + datalen);
- new->outgoing = outgoing;
- new->msg = *msg;
- memcpy(new->data, data, datalen);
- list_add_tail(&new->list, &currprog->messages);
-}
-
-static void replay_messages(struct program *old)
-{
- struct message *i, *in;
- int totlen;
-
- list_for_each_entry(i, &old->messages, list) {
- add_message(i->outgoing, &i->msg, i->msg.len, &i->msg+1);
- totlen = sizeof(i->msg) + i->msg.len;
- if (i->outgoing) {
- write(sock[0], &i->msg, totlen);
- continue;
- }
-
- in = talloc_size(NULL, sizeof(*in) + i->msg.len);
- /* Read in two parts: can be written that way. */
- if (read(sock[0], &in->msg, sizeof(in->msg)) != sizeof(in->msg)
- || read(sock[0], in->data, i->msg.len) != i->msg.len)
- barf_perror("read during replay");
- if (memcmp(&in->msg, &i->msg, totlen) != 0)
- barf_perror("replay turned out different");
- talloc_free(in);
- }
-}
-
static const char *protofamily(int pf)
{
switch (pf) {
@@ -258,7 +246,7 @@
return errstr;
}
-void handle_userspace_message(void)
+static void handle_userspace_message(void)
{
int len;
struct nf_userspace_message msg;
@@ -269,7 +257,6 @@
barf_perror("reading userspace message");
if (msg.type == UM_SYSCALL) {
- add_message(false, &msg, 0, NULL);
switch (msg.opcode) {
case SYS_GETSOCKOPT:
@@ -289,7 +276,6 @@
" getsockopt -> %s (len %i)",
err(msg.retval), msg.args[3]);
write(sock[0], &msg, sizeof(msg));
- add_message(true, &msg, 0, NULL);
break;
case SYS_SETSOCKOPT:
if (strace)
@@ -307,7 +293,6 @@
nfsim_log(LOG_USERSPACE, " setsockopt -> %s",
err(msg.retval));
write(sock[0], &msg, sizeof(msg));
- add_message(true, &msg, 0, NULL);
break;
default:
barf("Invalid syscall opcode %d\n", msg.opcode);
@@ -319,13 +304,18 @@
if (complete_read(sock[0], (char *)msg.args[0],
msg.args[2]) != msg.args[2])
barf_perror("read");
- add_message(false, &msg, msg.args[2],
- (char *)msg.args[0]);
break;
case KOP_COPY_TO_USER:
- add_message(false, &msg, 0, NULL);
/* copying has been done */
break;
+
+ case KOP_FORK:
+ if (!currprog->pid)
+ currprog->pid = msg.retval;
+ else
+ currprog->status = msg.retval;
+ break;
+
default:
barf("Invalid kernelop opcode %d\n", msg.opcode);
}
@@ -336,7 +326,7 @@
void send_userspace_message(struct nf_userspace_message *msg)
{
write(sock[0], msg, sizeof(struct nf_userspace_message) + msg->len);
- add_message(true, msg, msg->len, msg+1);
+// add_message(true, msg, msg->len, msg+1);
/* expect a reply */
handle_userspace_message();
}
@@ -412,20 +402,36 @@
/* This child wants a fresh program to play with */
void fork_other_program(void)
{
- struct program *old;
+ struct nf_userspace_message msg;
+ int newsock[2];
- /* Guarantee new socket for this child. */
- message_cleanup();
- message_init();
-
if (!currprog)
return;
- old = currprog;
- currprog = NULL;
- start_program(old->name, old->argc, old->argv);
- replay_messages(old);
- talloc_free(old);
+ if (socketpair(PF_UNIX, SOCK_STREAM, PF_UNSPEC, newsock))
+ barf_perror("socket");
+
+ forked = true;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = UM_KERNELOP;
+ msg.opcode = KOP_FORK;
+ if (strace)
+ nfsim_log(LOG_USERSPACE, " fork()");
+
+ /* Child will tell us pid. */
+ currprog->pid = 0;
+ currprog->status = -1;
+ send_userspace_message(&msg);
+
+ /* Now child expects us to supply new fd for stdout/stderr.
+ * We use this to tell when it died. */
+ send_fd(sock[0], newsock[1]);
+
+ /* And use the new socket pair. */
+ close(currprog->fd);
+ close(newsock[1]);
+ currprog->fd = newsock[0];
}
/* Loop accepting messages from fakesockopt. If child talks, return. */
Modified: trunk/nfsim/core/nfsockopt.h
===================================================================
--- trunk/nfsim/core/nfsockopt.h 2005-10-06 12:30:45 UTC (rev 4319)
+++ trunk/nfsim/core/nfsockopt.h 2005-10-06 18:21:57 UTC (rev 4320)
@@ -28,6 +28,7 @@
#define KOP_COPY_TO_USER 1
#define KOP_COPY_FROM_USER 2
+#define KOP_FORK 3
#define MAX_MESSAGE_ARGS 4
More information about the netfilter-cvslog
mailing list