|
List Info
Thread: Array
|
|
| Array |

|
1969-12-31 18:00:00 |
Hello all!
I wonder if somebody can help me with a strange error I
receive under
systrace on NetBSD. I've included a sample programme below
with
error-checking stripped in non-applicable areas. The
"sys/systrace.h"
header file is current from CVS. Overall system NetBSD 3.0,
GENERIC. I'm
trying to port sysjail (sysjail.bsd.lv) to NetBSD and this
is keeping me
hard up. Suggestions?
Note that this works fine with the OpenBSD systrace (3.9),
which adds to
the mystification.
The "strange error" is EINVAL: Invalid argument.
The below is run as "./a.out 5123", where 5123
is a process doing things (I
have a script looping echo -n '.').
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifdef __NetBSD__
# include <sys/systrace.h>
#elif __OpenBSD__
# include <dev/systrace.h>
#endif
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int
main(int argc, const char *argv[])
{
struct str_message msg;
struct systrace_policy pol;
struct pollfd pfd;
int fd, ofd;
pid_t cpid;
cpid = atoi(argv[1]);
ofd = open("/dev/systrace", O_RDWR |
O_NONBLOCK, 0);
#ifdef __OpenBSD__
ioctl(ofd, STRIOCCLONE, &fd);
close(ofd);
#elif __NetBSD__
fd = ofd;
#endif
fcntl(fd, F_SETFD, FD_CLOEXEC);
memset(&pol, 0, sizeof(pol));
pol.strp_op = SYSTR_POLICY_NEW;
pol.strp_num = -1;
pol.strp_maxents = 512;
ioctl(fd, STRIOCPOLICY, &pol);
ioctl(fd, STRIOCATTACH, &cpid);
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fd;
pfd.events = POLLIN;
poll(&pfd, 1, -1);
/* RETURNS AN ERROR:
* read: /dev/systrace: Invalid argument */
if (read(fd, &msg, sizeof(struct str_message))
!= sizeof(struct str_message)) {
err(1, "read: /dev/systrace");
}
return(0);
}
|
|
| Array |

|
1969-12-31 18:00:00 |
I don't see a check of the return value of the open() call.
Could it be -1 (invalid)?
On Mon, 3 Jul 2006 17:52:08 -0400 (EDT)
Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
>
> Hello all!
>
> I wonder if somebody can help me with a strange error I
receive under
> systrace on NetBSD. I've included a sample programme
below with
> error-checking stripped in non-applicable areas. The
"sys/systrace.h"
> header file is current from CVS. Overall system NetBSD
3.0, GENERIC. I'm
> trying to port sysjail (sysjail.bsd.lv) to NetBSD and
this is keeping me
> hard up. Suggestions?
>
> Note that this works fine with the OpenBSD systrace
(3.9), which adds to
> the mystification.
>
> The "strange error" is EINVAL: Invalid
argument.
>
> The below is run as "./a.out 5123", where
5123 is a process doing things (I
> have a script looping echo -n '.').
>
>
> #include <sys/ioctl.h>
> #include <sys/param.h>
> #include <sys/types.h>
> #include <sys/wait.h>
> #ifdef __NetBSD__
> # include <sys/systrace.h>
> #elif __OpenBSD__
> # include <dev/systrace.h>
> #endif
>
> #include <err.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <poll.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
>
> int
> main(int argc, const char *argv[])
> {
> struct str_message msg;
> struct systrace_policy pol;
> struct pollfd pfd;
> int fd, ofd;
> pid_t cpid;
>
> cpid = atoi(argv[1]);
>
> ofd = open("/dev/systrace", O_RDWR
| O_NONBLOCK, 0);
> #ifdef __OpenBSD__
> ioctl(ofd, STRIOCCLONE, &fd);
> close(ofd);
> #elif __NetBSD__
> fd = ofd;
> #endif
> fcntl(fd, F_SETFD, FD_CLOEXEC);
>
> memset(&pol, 0, sizeof(pol));
> pol.strp_op = SYSTR_POLICY_NEW;
> pol.strp_num = -1;
> pol.strp_maxents = 512;
>
> ioctl(fd, STRIOCPOLICY, &pol);
> ioctl(fd, STRIOCATTACH, &cpid);
>
> memset(&pfd, 0, sizeof(pfd));
> pfd.fd = fd;
> pfd.events = POLLIN;
>
> poll(&pfd, 1, -1);
>
> /* RETURNS AN ERROR:
> * read: /dev/systrace: Invalid argument */
> if (read(fd, &msg, sizeof(struct
str_message))
> != sizeof(struct str_message))
{
> err(1, "read:
/dev/systrace");
> }
>
> return(0);
> }
>
>
|
|
| NetBSD/systrace error: EINVAL |

|
2006-07-04 13:08:11 |
No, it returns with success. I just re-ran with:
$ sudo ./a.out 161
a.out: read: /dev/systrace: Invalid argument
In this case `161' was a shell session (I hit enter in it).
> I don't see a check of the return value of the open()
call. Could it be
> -1 (invalid)?
>
> On Mon, 3 Jul 2006 17:52:08 -0400 (EDT)
> Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
>
>>
>> Hello all!
>>
>> I wonder if somebody can help me with a strange
error I receive under
>> systrace on NetBSD. I've included a sample
programme below with
>> error-checking stripped in non-applicable areas.
The "sys/systrace.h"
>> header file is current from CVS. Overall system
NetBSD 3.0, GENERIC. I'm
>> trying to port sysjail (sysjail.bsd.lv) to NetBSD
and this is keeping me
>> hard up. Suggestions?
>>
>> Note that this works fine with the OpenBSD systrace
(3.9), which adds to
>> the mystification.
>>
>> The "strange error" is EINVAL: Invalid
argument.
>>
>> The below is run as "./a.out 5123",
where 5123 is a process doing things (I
>> have a script looping echo -n '.').
>>
>>
>> #include <sys/ioctl.h>
>> #include <sys/param.h>
>> #include <sys/types.h>
>> #include <sys/wait.h>
>> #ifdef __NetBSD__
>> # include <sys/systrace.h>
>> #elif __OpenBSD__
>> # include <dev/systrace.h>
>> #endif
>>
>> #include <err.h>
>> #include <errno.h>
>> #include <fcntl.h>
>> #include <poll.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <string.h>
>> #include <unistd.h>
>>
>> int
>> main(int argc, const char *argv[])
>> {
>> struct str_message msg;
>> struct systrace_policy pol;
>> struct pollfd pfd;
>> int fd, ofd;
>> pid_t cpid;
>>
>> cpid = atoi(argv[1]);
>>
>> ofd = open("/dev/systrace",
O_RDWR | O_NONBLOCK, 0);
>> #ifdef __OpenBSD__
>> ioctl(ofd, STRIOCCLONE, &fd);
>> close(ofd);
>> #elif __NetBSD__
>> fd = ofd;
>> #endif
>> fcntl(fd, F_SETFD, FD_CLOEXEC);
>>
>> memset(&pol, 0, sizeof(pol));
>> pol.strp_op = SYSTR_POLICY_NEW;
>> pol.strp_num = -1;
>> pol.strp_maxents = 512;
>>
>> ioctl(fd, STRIOCPOLICY, &pol);
>> ioctl(fd, STRIOCATTACH, &cpid);
>>
>> memset(&pfd, 0, sizeof(pfd));
>> pfd.fd = fd;
>> pfd.events = POLLIN;
>>
>> poll(&pfd, 1, -1);
>>
>> /* RETURNS AN ERROR:
>> * read: /dev/systrace: Invalid argument
*/
>> if (read(fd, &msg, sizeof(struct
str_message))
>> != sizeof(struct
str_message)) {
>> err(1, "read:
/dev/systrace");
>> }
>>
>> return(0);
>> }
>>
>>
>
/--
Kristaps Johnson, Chief Technology Officer
Gradient Enterprises Inc.
|
|
| NetBSD/systrace error: EINVAL |

|
2006-07-04 17:29:59 |
On Tue, 4 Jul 2006 09:08:11 -0400 (EDT)
Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
>
> No, it returns with success. I just re-ran with:
In your code, it is not checked, so you can't know that it
returned with success. If the code you are actually running
is different, please post that code. Otherwise, you must
check the return value of open, you can't just assume it is
correct.
>
> $ sudo ./a.out 161
> a.out: read: /dev/systrace: Invalid argument
>
> In this case `161' was a shell session (I hit enter in
it).
>
>
> > I don't see a check of the return value of the
open() call. Could it be
> > -1 (invalid)?
> >
> > On Mon, 3 Jul 2006 17:52:08 -0400 (EDT)
> > Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
> >
> >>
> >> Hello all!
> >>
> >> I wonder if somebody can help me with a
strange error I receive under
> >> systrace on NetBSD. I've included a sample
programme below with
> >> error-checking stripped in non-applicable
areas. The "sys/systrace.h"
> >> header file is current from CVS. Overall
system NetBSD 3.0, GENERIC. I'm
> >> trying to port sysjail (sysjail.bsd.lv) to
NetBSD and this is keeping me
> >> hard up. Suggestions?
> >>
> >> Note that this works fine with the OpenBSD
systrace (3.9), which adds to
> >> the mystification.
> >>
> >> The "strange error" is EINVAL:
Invalid argument.
> >>
> >> The below is run as "./a.out
5123", where 5123 is a process doing things (I
> >> have a script looping echo -n '.').
> >>
> >>
> >> #include <sys/ioctl.h>
> >> #include <sys/param.h>
> >> #include <sys/types.h>
> >> #include <sys/wait.h>
> >> #ifdef __NetBSD__
> >> # include <sys/systrace.h>
> >> #elif __OpenBSD__
> >> # include <dev/systrace.h>
> >> #endif
> >>
> >> #include <err.h>
> >> #include <errno.h>
> >> #include <fcntl.h>
> >> #include <poll.h>
> >> #include <stdio.h>
> >> #include <stdlib.h>
> >> #include <string.h>
> >> #include <unistd.h>
> >>
> >> int
> >> main(int argc, const char *argv[])
> >> {
> >> struct str_message msg;
> >> struct systrace_policy pol;
> >> struct pollfd pfd;
> >> int fd, ofd;
> >> pid_t cpid;
> >>
> >> cpid = atoi(argv[1]);
> >>
> >> ofd =
open("/dev/systrace", O_RDWR | O_NONBLOCK, 0);
> >> #ifdef __OpenBSD__
> >> ioctl(ofd, STRIOCCLONE, &fd);
> >> close(ofd);
> >> #elif __NetBSD__
> >> fd = ofd;
> >> #endif
> >> fcntl(fd, F_SETFD, FD_CLOEXEC);
> >>
> >> memset(&pol, 0, sizeof(pol));
> >> pol.strp_op = SYSTR_POLICY_NEW;
> >> pol.strp_num = -1;
> >> pol.strp_maxents = 512;
> >>
> >> ioctl(fd, STRIOCPOLICY, &pol);
> >> ioctl(fd, STRIOCATTACH, &cpid);
> >>
> >> memset(&pfd, 0, sizeof(pfd));
> >> pfd.fd = fd;
> >> pfd.events = POLLIN;
> >>
> >> poll(&pfd, 1, -1);
> >>
> >> /* RETURNS AN ERROR:
> >> * read: /dev/systrace: Invalid
argument */
> >> if (read(fd, &msg, sizeof(struct
str_message))
> >> != sizeof(struct
str_message)) {
> >> err(1, "read:
/dev/systrace");
> >> }
> >>
> >> return(0);
> >> }
> >>
> >>
> >
>
> /--
> Kristaps Johnson, Chief Technology Officer
> Gradient Enterprises Inc.
>
>
|
|
| NetBSD/systrace error: EINVAL |

|
2006-07-04 17:55:10 |
Seth Kurtzberg wrote:
> On Tue, 4 Jul 2006 09:08:11 -0400 (EDT)
> Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
>
>> No, it returns with success. I just re-ran with:
>
> In your code, it is not checked, so you can't know
that it returned with success. If the code you are actually
running is different, please post that code. Otherwise, you
must check the return value of open, you can't just assume
it is correct.
>
>> $ sudo ./a.out 161
>> a.out: read: /dev/systrace: Invalid argument
>>
>> In this case `161' was a shell session (I hit
enter in it).
>>
>>
>>> I don't see a check of the return value of the
open() call. Could it be
>>> -1 (invalid)?
>>>
>>> On Mon, 3 Jul 2006 17:52:08 -0400 (EDT)
>>> Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
>>>
>>>> Hello all!
>>>>
>>>> I wonder if somebody can help me with a
strange error I receive under
>>>> systrace on NetBSD. I've included a
sample programme below with
>>>> error-checking stripped in non-applicable
areas. The "sys/systrace.h"
>>>> header file is current from CVS. Overall
system NetBSD 3.0, GENERIC. I'm
>>>> trying to port sysjail (sysjail.bsd.lv) to
NetBSD and this is keeping me
>>>> hard up. Suggestions?
>>>>
>>>> Note that this works fine with the OpenBSD
systrace (3.9), which adds to
>>>> the mystification.
>>>>
>>>> The "strange error" is EINVAL:
Invalid argument.
>>>>
>>>> The below is run as "./a.out
5123", where 5123 is a process doing things (I
>>>> have a script looping echo -n '.').
>>>>
>>>>
>>>> #include <sys/ioctl.h>
>>>> #include <sys/param.h>
>>>> #include <sys/types.h>
>>>> #include <sys/wait.h>
>>>> #ifdef __NetBSD__
>>>> # include <sys/systrace.h>
>>>> #elif __OpenBSD__
>>>> # include <dev/systrace.h>
>>>> #endif
>>>>
>>>> #include <err.h>
>>>> #include <errno.h>
>>>> #include <fcntl.h>
>>>> #include <poll.h>
>>>> #include <stdio.h>
>>>> #include <stdlib.h>
>>>> #include <string.h>
>>>> #include <unistd.h>
>>>>
>>>> int
>>>> main(int argc, const char *argv[])
>>>> {
>>>> struct str_message msg;
>>>> struct systrace_policy pol;
>>>> struct pollfd pfd;
>>>> int fd, ofd;
>>>> pid_t cpid;
>>>>
>>>> cpid = atoi(argv[1]);
>>>>
>>>> ofd =
open("/dev/systrace", O_RDWR | O_NONBLOCK, 0);
>>>> #ifdef __OpenBSD__
>>>> ioctl(ofd, STRIOCCLONE, &fd);
>>>> close(ofd);
>>>> #elif __NetBSD__
>>>> fd = ofd;
>>>> #endif
>>>> fcntl(fd, F_SETFD, FD_CLOEXEC);
>>>>
>>>> memset(&pol, 0, sizeof(pol));
>>>> pol.strp_op = SYSTR_POLICY_NEW;
>>>> pol.strp_num = -1;
>>>> pol.strp_maxents = 512;
>>>>
>>>> ioctl(fd, STRIOCPOLICY, &pol);
>>>> ioctl(fd, STRIOCATTACH,
&cpid);
>>>>
>>>> memset(&pfd, 0, sizeof(pfd));
>>>> pfd.fd = fd;
>>>> pfd.events = POLLIN;
>>>>
>>>> poll(&pfd, 1, -1);
>>>>
Why does this compile, when read is supposed to take a char
* as second
arg and you're passing pointer to str_message struct?
>>>> /* RETURNS AN ERROR:
>>>> * read: /dev/systrace: Invalid
argument */
>>>> if (read(fd, &msg,
sizeof(struct str_message))
>>>> != sizeof(struct
str_message)) {
>>>> err(1, "read:
/dev/systrace");
>>>> }
>>>>
>>>> return(0);
>>>> }
>>>>
>>>>
>> /--
>> Kristaps Johnson, Chief Technology Officer
>> Gradient Enterprises Inc.
>>
>>
>
|
|
| NetBSD/systrace error: EINVAL |

|
2006-07-04 20:47:24 |
>> No, it returns with success. I just re-ran with:
>
> In your code, it is not checked, so you can't know
that it returned with
> success. If the code you are actually running is
different, please post
> that code. Otherwise, you must check the return value
of open, you
> can't just assume it is correct.
Seth, the sample code is a mock-up of what was causing me
problems from my
original codebase - namely, EINVAL at read. I duplicated
only the
problem-causing code and the steps required to get there
(originally in
effort to clarify the problem), then removed all ancillary
error-checking
for newspost-ready brevity.
I can re-post the sample code with full error-checking but
it does not
change the results (Invalid argument, meh).
Thanks,
Kristaps
|
|
| NetBSD/systrace error: EINVAL |

|
2006-07-04 20:50:33 |
On Tue, 4 Jul 2006 16:47:24 -0400 (EDT)
Kristaps Johnson <kristaps gradient-enterprises.com> wrote:
>
> >> No, it returns with success. I just re-ran
with:
> >
> > In your code, it is not checked, so you can't
know that it returned with
> > success. If the code you are actually running is
different, please post
> > that code. Otherwise, you must check the return
value of open, you
> > can't just assume it is correct.
>
> Seth, the sample code is a mock-up of what was causing
me problems from my
> original codebase - namely, EINVAL at read. I
duplicated only the
> problem-causing code and the steps required to get
there (originally in
> effort to clarify the problem), then removed all
ancillary error-checking
> for newspost-ready brevity.
>
> I can re-post the sample code with full error-checking
but it does not
> change the results (Invalid argument, meh).
It's better to post the real code. There could be
something significant there that you have missed. It's
unlikely, but it isn't impossible, so I would post the
actual code.
>
> Thanks,
> Kristaps
>
|
|
| NetBSD/systrace error: EINVAL |

|
2006-07-04 21:15:04 |
>> Seth, the sample code is a mock-up of what was
causing me problems from
>> my original codebase - namely, EINVAL at read. I
duplicated only the
>> problem-causing code and the steps required to get
there (originally in
>> effort to clarify the problem), then removed all
ancillary
>> error-checking for newspost-ready brevity.
>>
>> I can re-post the sample code with full
error-checking but it does not
>> change the results (Invalid argument, meh).
>
> It's better to post the real code. There could be
something significant
> there that you have missed. It's unlikely, but it
isn't impossible, so
> I would post the actual code.
I've included it below. It's one of several files so it
won't compile on
its own. But the "problem area", i.e., death on
read after poll, is in
here. As you'll see reading through the code below, the
sample I first
included is a simple "main" function with all
the sysjail-specific stuff
stripped away. Incidentally, "sysjail" is the
main entry function.
I use the same logical chain as systrace.1 to prepare the
device and read
from it, which is one of primary things confusing me. I
keep hoping that
I'm missing a magic fcntl blessing, or maybe that my read
buffer's not
wide enough.
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#if defined(__OpenBSD__)
# include <dev/systrace.h>
#elif defined(__NetBSD__)
# include <sys/systrace.h>
#endif
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "intercept.h"
#include "pidctl.h"
#include "report.h"
#include "sysjail.h"
#include "jaildb.h"
/**
* Sentinel for SIGUSR1 synchronisation between child &
parent.
*/
static volatile int got_sigusr1 = 0;
/**
* Global jail structure. TODO. Put in function calls.
*/
struct sysjail* jail;
/**
* Master process's return code, should it return
out-of-state.
*/
static int masterrc = -1;
/**
* Set that a SIGUSR1 has been detected, do nothing
otherwise.
*/
static void sigfunction(int signum);
/**
* Register a process with the systrace device.
*
* param sfd The systrace descriptor.
* param pid The process to attach.
*
* return -1 on failure, 0 on success.
*/
static int systrace_pidreg(int sfd, pid_t pid);
/**
* Initialise the systrace subsystem.
*
* param sfd A pointer to the systrace file descriptor
(output).
*
* return -1 on failure, 0 on success.
*/
static int systrace_init(int *sfd);
/**
* Read a systrace message when a child has started or
stopped.
*
* param msg The systrace message.
*
* return -1 on failure, 0 on success, 1 to indicate
that no children
* are left in the PID database.
*/
static int readmsg_child(struct str_message *msg);
/**
* Read & route a systrace message.
*
* param sfd The systrace file descriptor.
*
* return -1 on failure, 0 on success, 1 to indicate
that the system may
* safely exit.
*/
static int readmsg(int sfd);
/**
* Loop on the systrace descriptor waiting for messages.
*
* param sfd The systrace file descriptor.
*
* return 0 on success, -1 on failure.
*/
static int loop(int sfd);
/**
* Wait on the master process. Waits without blocking,
kills with
* SIGKILL if the process hangs.
*
* param rc Pointer to the master process's return
code.
*
* return 0 on success, -1 on failure (rc will not be
set).
*/
static int waitmaster(int *rc);
int
waitmaster(int *rc)
{
int ret, status;
pid_t pid;
pid = pidctl_getmaster();
assert(pid >= 0);
if ((ret = waitpid(pid, &status, WNOHANG)) == -1) {
rep_error("waitpid: %d", pid);
return(-1);
} else if (ret == 0) {
rep_errorx("waitpid: %d (hung)", pid);
if (kill(pid, SIGKILL) == -1) {
rep_error("kill: %d, SIGKILL", pid);
}
return(-1);
}
if (WIFEXITED(status)) {
*rc = WEXITSTATUS(status);
} else {
*rc = 127;
}
return(0);
}
void
sigfunction(int signum)
{
if (signum == SIGUSR1) {
got_sigusr1 = 1;
} else {
rep_errorx("intercepted signal %d", signum);
}
}
int
systrace_pidreg(int sfd, pid_t pid)
{
assert(pid >= 0);
assert(sfd >= 0);
/* Install pid & policy. */
if (ioctl(sfd, STRIOCATTACH, &pid) == -1) {
rep_error("ioctl: STRIOCATTACH");
return(-1);
}
/* Prepare our intercepts. */
if (intercept_init(sfd, pid) == -1) {
return(-1);
}
return(0);
}
int
readmsg_child(struct str_message *msg)
{
struct str_msg_child *chld;
assert(msg);
chld = &msg->msg_data.msg_child;
if (chld->new_pid == -1) {
rep_reap(msg->msg_pid);
(void)pidctl_delpid(msg->msg_pid);
/* Check if we've processes left to harvest. */
if (pidctl_isempty()) {
return(1);
}
if (pidctl_getmaster() == msg->msg_pid) {
rep_errorx("master %d exited with extant
children",
msg->msg_pid);
assert(masterrc == -1);
if (waitmaster(&masterrc) == -1) {
return(-1);
}
}
return(0);
}
rep_spawn(chld->new_pid, msg->msg_pid);
return(pidctl_addpid(chld->new_pid));
}
int
readmsg(int sfd)
{
struct str_message msg;
int rc;
ssize_t sz;
assert(sfd >= 0);
sz = read(sfd, &msg, sizeof(struct str_message));
if (sz == -1) {
rep_error("read (%d): /dev/systrace", sfd);
return(-1);
} else if (sz != sizeof(msg)) {
rep_errorx("read: %d, wanted %d", sz,
sizeof(msg));
return(-1);
}
switch (msg.msg_type) {
case(SYSTR_MSG_RES):
/* FALLTHROUGH */
case(SYSTR_MSG_ASK):
if ((rc = intercept(sfd, &msg)) == -1) {
return(-1);
} else if (rc == 1) {
return(1);
}
break;
case(SYSTR_MSG_CHILD):
if ((rc = readmsg_child(&msg)) == -1) {
return(-1);
} else if (rc == 1) {
return(1);
}
break;
default:
/* We should not get here. */
assert(0);
return(-1);
}
return(0);
}
/* Nearly verbatim from systrace/intercept.c. */
int
loop(int sfd)
{
struct pollfd fd;
int ret, rc;
assert(sfd >= 0);
fd.fd = sfd;
fd.events = POLLIN;
ret = -1;
for (;;) { /* Infinite loop. */
if (poll(&fd, 1, -1) == -1) {
if (errno == EINTR) {
ret = 0;
break;
}
rep_error("poll: /dev/systrace");
break;
}
if (fd.revents & (POLLIN | POLLRDNORM)) {
if ((rc = readmsg(sfd)) == -1) {
break;
} else if (rc == 1) {
ret = 0;
break;
}
continue;
}
return(-1);
} /* Infinite loop. */
return(ret);
}
int
sysjail_postinit(int sfd, pid_t *pid, struct sysjail *sjail)
{
sigset_t none, set, oset;
sig_t ohandler;
assert(sjail != NULL);
assert(pid != NULL);
/* Block signals. */
sigemptyset(&none);
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) {
rep_error("sigprocmask: SIG_BLOCK");
return(-1);
}
if ((ohandler = signal(SIGUSR1, sigfunction)) == SIG_ERR)
{
rep_error("signal: SIGUSR1");
return(-1);
}
/* This needs to be done before the fork so the child has
the
* modified JID. */
if (jaildb_add(sjail) == -1) {
rep_error("unable to modify jaildb: %s",
_PATH_JAILDB);
return(-1);
}
*pid = fork();
if (*pid == -1) {
(void)jaildb_del(sjail);
rep_error("fork");
return(-1);
} else if (*pid == 0) {
/* In child process. */
/* Return control immediately after procsesing. */
if (kill(getppid(), SIGUSR1) == -1) {
rep_error("kill: %d, SIGUSR1", getppid());
return(-1);
}
if (close(sfd) == -1) {
rep_error("close: /dev/systrace");
return(-1);
}
/* Carefully chroot & set privileges. */
assert(sjail->path != NULL);
if (chroot(sjail->path) != 0) {
rep_error("chroot: %s", sjail->path);
return(-1);
}
if (chdir("/") != 0) {
rep_error("chdir: /");
return(-1);
}
/* Wait for synchronisation signal. */
sigsuspend(&none);
if ( ! got_sigusr1) {
rep_errorx("signal: intercepted wrong
signal");
return(-1);
}
if (signal(SIGUSR1, ohandler) == SIG_ERR) {
rep_error("signal: SIGUSR1");
return(-1);
}
if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
rep_error("sigprocmask: SIG_SETMASK");
return(-1);
}
return(0);
}
if (signal(SIGTERM, sigfunction) == SIG_ERR) {
rep_error("signal: SIGTERM");
return(-1);
}
if (signal(SIGINT, sigfunction) == SIG_ERR) {
rep_error("signal: SIGINT");
return(-1);
}
if (siginterrupt(SIGINT, 1) == -1) {
rep_error("siginterrupt: SIGINT");
return(-1);
}
if (siginterrupt(SIGTERM, 1) == -1) {
rep_error("siginterrupt: SIGTERM");
return(-1);
}
sigsuspend(&none);
if ( ! got_sigusr1) {
rep_errorx("signal: intercepted wrong
signal");
return(-1);
}
/* Still in parent process. */
/* Register the initial pid. */
rep_begin(*pid);
if (systrace_pidreg(sfd, *pid) == -1) {
rep_errorx("systrace_pidreg: %d", *pid);
return(-1);
}
pidctl_setmaster(*pid);
if (pidctl_addpid(*pid) == -1) {
rep_errorx("pidctl_addpid: %d", *pid);
return(-1);
}
/* Restore the child handler. */
if (signal(SIGUSR1, ohandler) == SIG_ERR) {
rep_error("signal: SIGUSR1");
return(-1);
}
if (sigprocmask(SIG_SETMASK, &oset, NULL) == -1) {
rep_error("sigprocmask: SIG_SETMASK");
return(-1);
}
/* Signal the child that we're ready. */
if (kill(*pid, SIGUSR1) == -1) {
rep_error("kill: %d, SIGUSR1", *pid);
return(-1);
}
return(loop(sfd));
}
int
systrace_init(int *sfd)
{
int fd;
assert(sfd != NULL);
if ((fd = open("/dev/systrace", O_RDWR |
O_NONBLOCK, 0)) == -1) {
rep_error("open: /dev/systrace");
}
#if defined(__OpenBSD__)
/* OpenBSD requires us to clone the device descriptor. */
if (ioctl(fd, STRIOCCLONE, sfd) == -1) {
rep_error("ioctl: STRIOCCLONE");
if (close(fd) == -1) {
rep_error("close: /dev/systrace");
}
return(-1);
}
if (close(fd) == -1) {
rep_error("close: /dev/systrace");
if (close(*sfd)) {
rep_error("close: /dev/systrace");
}
return(-1);
}
#endif
#if defined(__NetBSD__)
/* NetBSD needn't clone the device descriptor. */
*sfd = fd;
#endif
if (fcntl(*sfd, F_SETFD, 1) == -1) {
rep_error("fcntl: F_SETFD, 1");
if (close(*sfd)) {
rep_error("close: /dev/systrace");
}
return(-1);
}
if (fcntl(*sfd, F_SETFL, O_NONBLOCK) == -1) {
rep_error("fcntl: F_SETFL, 1");
if (close(*sfd)) {
rep_error("close: /dev/systrace");
}
return(-1);
}
return(0);
}
/*----------------------------------------------------------
-----------
* Main entrance to sysjail library.
*-----------------------------------------------------------
--------*/
int
sysjail(struct sysjail *sjail)
{
int rc, sfd;
pid_t pid;
assert(sjail != NULL);
jail = sjail;
sfd = -1;
jail->master = getpid();
if (systrace_init(&sfd) == -1) {
return(-1);
}
assert(sfd >= 0);
pid = -1;
rc = sysjail_postinit(sfd, &pid, sjail);
if (pid <= 0) {
/* We return control if we're the child. */
return(rc);
}
/*
* We're in the parent's exit sequence. This must be
done very
* carefully. Cleanup our environment then reap the child
* process. Return the child's exit code if set, else
127 if
* the child exits with a signal, else 255 in case of
error.
*/
if (sjail->jid > 0) {
(void)jaildb_del(sjail);
}
if (close(sfd) == -1) {
rep_error("close: /dev/systrace");
rc = 255;
}
if (masterrc == -1) {
if (waitmaster(&masterrc) == -1) {
rc = 255;
} else {
rc = masterrc;
}
} else {
rc = masterrc;
}
rep_exit(pid, rc);
exit(rc);
/* NOTREACHED */
}
|
|
[1-8]
|
|