The redirection isn't actually occurring inside
> /tmp/test is handled by whatever shell you are using. If you actually passed
> /tmp/test to
chroot, then it would get passed to
echo and you'd see
this is a test > /tmp/test
on your terminal. You shell, of course, isn't getting
chrooted, so it's perfectly fine with opening
/tmp/test. Then, the shell
chroot executable, which calls the
chroot system call and then
echo, which finally writes to the fd. All through this, the original file descriptor that your (un
chrooted) shell opened is never modified, so your
echo is able to write to it.
This is a deliberate feature. A process outside the
chroot is allowed to open files, and then its
chrooted children can only access those files outside the
chroot that the parent process deigned to pass to them.
If you want the redirection to take place inside the chroot, you need to spawn a shell that knows how to interpret it:
chroot $dir bash -c "echo this is a test > /tmp/test"
The order of operations is now:
fork (with default stdin, stdout, and stderr),
chroot (now inside chroot),
bash (knows how to handle redirection),
fork (implementation detail of
bash), open file,
echo (with new stdout).