I am trying to make a c++ program that runs a binary in jail. There is three files that we are working with
#include <unistd.h>
#include <iostream>
#include <cstdlib>
#include <string>
class Runner {
public:
const char* jailRoot;
explicit Runner(const char* jr): jailRoot(jr) {}
void run(const std::string& cmd) const {
if (jailRoot != nullptr) {
if (chroot(jailRoot) != 0) {
perror("chroot failed");
exit(EXIT_FAILURE);
}
if (chdir("/") != 0) {
perror("chdir failed");
exit(EXIT_FAILURE);
}
}
execl(cmd.c_str(), cmd.c_str(), nullptr);
perror("execl failed");
exit(EXIT_FAILURE);
}
};
#include <iostream>
#include "../utils/config.hpp"
#include "../utils/runner.hpp"
int main(int argc, char* argv[]){
const Runner sandbox(argv[1]);
sandbox.run("./test");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
void listDir(const char *path) {
printf("Listing directory: %s\n", path);
DIR *dir = opendir(path);
if (!dir) {
perror("opendir");
return;
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
char fullpath[4096];
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
struct stat st;
if (stat(fullpath, &st) == 0) {
if (S_ISDIR(st.st_mode)) {
printf("[DIR] %s\n", entry->d_name);
} else if (S_ISREG(st.st_mode)) {
printf("[FILE] %s\n", entry->d_name);
} else {
printf("[OTHER] %s\n", entry->d_name);
}
}
}
closedir(dir);
printf("\n");
}
int main(void) {
char cwd[4096];
if (!getcwd(cwd, sizeof(cwd))) {
perror("getcwd");
return 1;
}
listDir(cwd);
// Parent dir (..)
char parent[4096];
snprintf(parent, sizeof(parent), "%s/..", cwd);
listDir(parent);
return 0;
}
after compiling main.cpp
to ./penaur
./penaur
works fine (without specifying jail path so no chroot happening):
Listing directory: /home/chocolate/penaur/build
[DIR] .
[DIR] ..
[DIR] CMakeFiles
[DIR] _deps
[FILE] CMakeCache.txt
[FILE] Makefile
[FILE] cmake_install.c
But after specifying a jail path:
build $ sudo ./penaur .
[sudo] password for chocolate:
execl failed: No such file or directory
Things that i checked
./test
is in . and it is executableldd ./test
shows no dynamic dependency (compiled to full static binary)ls
in build directory:
CMakeCache.txt CMakeFiles cmake_install.cmake _deps Makefile penaur test testing
Thank you for your time and help.
I found the root cause of the issue.
Even though the executable file exists inside the chroot jail and is fully static (confirmed by ldd showing no dynamic dependencies), running it inside the jail failed with:
execl failed: No such file or directory
This error occurs despite the binary being present and statically linked. The reason is that the chroot environment is missing some essential system components or setup that the binary expects at runtime even static binaries sometimes rely on minimal system features or device files.
The problem was resolved when I copied a statically linked BusyBox binary into the jail and ran commands from it. BusyBox, being a fully self-contained executable that includes a shell and common utilities, works smoothly inside minimal environments without extra dependencies.