I was playing around with exec-family functions and I've seen a really strange behavior: they don't seem to work after chroot() system call.
Here's a relevant Quote from manpages:
Special semantics for execlp() and execvp()
The execlp(), execvp(), and execvpe() functions duplicate the actions of the shell in searching for an executable file if the specified filename does not contain a slash (/) character. The file is sought in the colon-separated list of directory pathnames specified in the PATH envi‐ ronment variable. If this variable isn't defined, the path list defaults to the current directory followed by the list of directories returned by confstr(_CS_PATH). (This confstr(3) call typically returns the value "/bin:/usr/bin".)
If the specified filename includes a slash character, then PATH is ignored, and the file at the specified pathname is executed.
That was the theory, now let's see how it behaves:
I have
prog.cfile that will be executed byexeclp:#include <stdio.h> int main() { puts("works!"); return 0; }And I have
exec.cfile which will attempt to executeprog:#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <dirent.h> int main(int argc, char* const argv[]) { const char path[] = "/home/zaffy/cool"; if (argc < 2) return 1; if (argc > 2 && (chdir(path) || chroot(path))) { printf("Cannot chroot(%s): %s\n", path, strerror(errno)); return 1; } /* Clear our environment, including PATH */ clearenv(); if (execlp(argv[1], argv[1], NULL)) { printf("Cannot execlp(%s): %s\n", argv[1], strerror(errno)); /* Well, we failed... let's see contents of the current root */ struct dirent* entry; DIR* dir = opendir("/"); while ( (entry = readdir(dir)) ) printf("%s\n", entry->d_name); closedir(dir); } return 0; }
all tests are done in
/home/zaffy/cool:/home/zaffy/cool ├── exec ├── exec.c ├── prog └── prog.c
Test One: exec without call to chroot:
# /home/zaffy/cool/exec /home/zaffy/cool/prog
works!
Test Two: exec with call to chroot:
# /home/zaffy/cool/exec /prog 1
Cannot execlp(/prog): No such file or directory
.
..
prog.c
prog
exec.c
exec
I'm confused! According to man-pages, if I have passed absolute path to execlp it should not search in PATH, or if the PATH is not set, it should be set also to the current directory so I'm not able to see the problem here.
The file surely exists and is available! Even if I use fopen right before execlp, the fopen finds and opens the file, but execlp still emits the error No such file or directory.
Do you have any idea why this happens ? Why doesn't exec() work after chroot() ?