From: blacklight on
I'm experiencing a weird behaviour in executing programs in a chroot()
environment. This is the situation.

I have a path like this:

/p +
|--> /p/popen
|--> /p/exe

This is popen.c:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main ( int argc, char *argv[] )
{
FILE *pipe;
char ch;

if (chroot("/p") < 0)
return EXIT_FAILURE;

if (!(pipe = popen("/exe", "r")))
return EXIT_FAILURE;

printf ("RESULT: ");

while (fread(&ch, 1, 1, pipe) > 0)
printf ("%c", ch);
printf ("\n");

pclose(pipe);
return EXIT_SUCCESS;
}


popen() does not fail, but just no character is read. Of course if I do not use
chroot() and i just call popen ("./exe", "r") I have no problem. I also have
tried popen-ing "./exe" and "exe", both without any results. Even calling a
system() on "/exe", "./exe" or "exe" gives no results. So, how do I invoke an
executable file in a chroot() environment?

Thanks,
BlackLight


--
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GAT d? a? C++++ U++++ P++++ L+++++ E--- W+++ !w PS+++ PE-- Y++ PGP++ X++
R+ tv-- b+>+++ DI++ G++ e+++ h* r++ z**
------END GEEK CODE BLOCK------

-ONLY- email me using my PGP key
# http://pgp.mit.edu:11371/pks/lookup?op=get&search=0xE8468AFB46DBC195

Admin of
# http://0x00.ath.cx
From: Nicolas George on
blacklight wrote in message <hq7iro$ch4$1(a)speranza.aioe.org>:
> I have a path like this:
> /p +
> |--> /p/popen
> |--> /p/exe

Statically linked?
From: blacklight on
Hmmm what do you mean? They're ordinary executable files statically generated
by gcc, not symbolic links nor executable relying on external dependencies.

Nicolas George <nicolas$george(a)salle-s.org> wrote:
> blacklight wrote in message <hq7iro$ch4$1(a)speranza.aioe.org>:
>> I have a path like this:
>> /p +
>> |--> /p/popen
>> |--> /p/exe
>
> Statically linked?

--
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GAT d? a? C++++ U++++ P++++ L+++++ E--- W+++ !w PS+++ PE-- Y++ PGP++ X++
R+ tv-- b+>+++ DI++ G++ e+++ h* r++ z**
------END GEEK CODE BLOCK------

-ONLY- email me using my PGP key
# http://pgp.mit.edu:11371/pks/lookup?op=get&search=0xE8468AFB46DBC195

Admin of
# http://0x00.ath.cx
From: guenther on
On Apr 15, 10:36 am, blacklight <blackli...(a)wintermute.blacklight.org>
wrote:
> I'm experiencing a weird behaviour in executing programs in a chroot()
> environment. This is the situation.
....
> popen() does not fail, but just no character is read. Of course if I do not use
> chroot() and i just call popen ("./exe", "r") I have no problem.

popen() is required to support shell syntax in the command line that
it is given to execute. All the systems I know do this by having it
fork and exec the shell (generally /bin/sh, but there are
exceptions). Since you don't have the shell in your chroot tree, the
exec fails and you see EOF immediately on the pipe. If you were to
actually check the result of pclose(), you would find that it
indicated that the command failed, probably with status 127, the
standard status for "command could not be found".

The two obvious options are
1) include the shell (and dependent libraries) in the chroot
2) switch from popen() to doing your own pipe/fork/exec combo


Philip Guenther
From: William Ahern on
blacklight <blacklight(a)wintermute.blacklight.org> wrote:
> I'm experiencing a weird behaviour in executing programs in a chroot()
> environment. This is the situation.
<snip>
> while (fread(&ch, 1, 1, pipe) > 0)
> printf ("%c", ch);
> printf ("\n");
>
> pclose(pipe);
> return EXIT_SUCCESS;
> }
>
> popen() does not fail, but just no character is read.

popen() will only fail if it cannot create a pipe or fork (or perhaps
allocate memory). So popen() will work even if the executable doesn't even
exist, because that won't be determined until the exec() is attempted. If
the exec() fails, then what? That somehow must be communicated to the
process that called popen(), but there's no defined way to do that. pclose()
won't give you the exit value of the process. And you can't generally
distinguish a successful fork+exec which happens to write nothing to stdout
from a failed exec after the fork. Basically, popen() isn't very useful for
debugging your issue; it can't signal the cause of the probable culprit.

There's another more specific issue, which is probably the source of your
troubles. popen() and system() use the command as a parameter to /bin/sh,
which is what they will actually exec() directly (i.e. `/bin/sh -c
"[command]"'). Unless /bin/sh exists in the new root, you can't expect to
use either popen() or system(), no matter what you're ultimately trying to
execute. If there's no /bin/sh, then you need to create your own popen-like
routine using pipe()+fork()+exec(). The code to do this is quite short but
conceptually very dense, so one so should be very familiar with the Unix
process model before attempting it.

Note that system() does return the exit value, and I bet you'll see a
difference if you compare the value from the chroot'd call and the
non-chroot'd call.

> Of course if I do not use chroot() and i just call popen ("./exe", "r") I
> have no problem. I also have tried popen-ing "./exe" and "exe", both
> without any results. Even calling a system() on "/exe", "./exe" or "exe"
> gives no results. So, how do I invoke an executable file in a chroot()
> environment?

The procedure is exactly the same. There are no other side-effects of the
chroot() itself. The problem is likely the absence of /bin/sh, however,
which is a collateral issue.