Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,3 @@ target_include_directories(test-dlmopen PUBLIC)
target_link_libraries(test-dlmopen PRIVATE virtual-library-context)
target_compile_options(test-dlmopen PRIVATE -fPIC -ldl -g)
target_compile_features(test-dlmopen PUBLIC cxx_std_23)

59 changes: 29 additions & 30 deletions include/VLC/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ class Runtime {

/**
* intialization VLC runtime.
*
*
* A fork will happen, where parent process becomes VLC manager,
* application continues on child process.
*
*
* Manager process will not exit until application process is finished.
*/
void initialize() {
Expand All @@ -67,15 +67,15 @@ class Runtime {
std::exit(EXIT_FAILURE);
} else if (pid == 0) {
// this is application process (child)

// set a BPF filter on specific syscall for ptrace
configure_seccomp_bpf();
raise(SIGSTOP); // stop and let monitor process know

// return to the application's main()
std::cout << "VLC: application start." << std::endl;
return;
} else {
} else {
// this is manager process (parent)
std::cout << "VLC: manager start." << std::endl;
application_pid = pid;
Expand Down Expand Up @@ -105,7 +105,7 @@ class Runtime {
intercept_syscall();

// exit when the application finished
std::exit(EXIT_SUCCESS);
std::exit(EXIT_SUCCESS);
}
}

Expand All @@ -118,11 +118,10 @@ class Runtime {
std::unordered_map<pid_t, cpu_set_t> virtual_cpu_sets;
pid_t application_pid = 0;
std::unordered_map<pid_t, ChildState> application_child_states; // map of child to states of the application process (including itself)
int forge_sched_getaffinity_count = 0;

/**
* Configure a BPF filter for ptrace + seccomp.
*
*
* Will mark the caller process as tracee.
* This allows the tracer only stop on specific syscall
* that related to resouces query rather than all of them.
Expand Down Expand Up @@ -186,7 +185,7 @@ class Runtime {
if (child_waited == -1) {
VLC_DIE("VLC: unable to intercept syscall, %s", strerror(errno));
}

VLC_DEBUG("VLC: stop application, pid=%d.", child_waited);

// if haven't seen this pid before
Expand All @@ -211,7 +210,7 @@ class Runtime {
VLC_DIE("VLC: unable to intercept syscall, %s", strerror(errno));
}
long syscall = regs.orig_rax;

if (syscall == SYS_openat) { // capture openat()
forge_openat(child_waited, &regs.rsi);
ptrace(PTRACE_SETREGS, child_waited, NULL, &regs);
Expand All @@ -228,7 +227,7 @@ class Runtime {
}

/*** Phase 3: leaving syscall **/

// retrive syscall arguments
if (ptrace(PTRACE_GETREGS, child_waited, NULL, &regs) == -1) {
VLC_DIE("VLC: unable to intercept syscall, %s", strerror(errno));
Expand Down Expand Up @@ -266,10 +265,10 @@ class Runtime {
} else {
// if the child stop event is already caputured
assert(application_child_states[new_child] == ChildState::NEW_STOPPED && "Child state invalid");

// trace and let child continue
if (ptrace(PTRACE_SETOPTIONS, new_child, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACESECCOMP | PTRACE_O_EXITKILL) == -1) {

}

VLC_DEBUG("VLC: child is traced and resumed, pid=%d", new_child);
Expand All @@ -282,7 +281,7 @@ class Runtime {
} else if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) {
// a child is stopped after created, and fork event already recived
assert(application_child_states[child_waited] == ChildState::NEW_FORKED && "Child state is invalid");

// trace and let child continue
if (ptrace(PTRACE_SETOPTIONS, child_waited, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACESECCOMP | PTRACE_O_EXITKILL) == -1) {
VLC_DIE("VLC: unable to config tracer");
Expand All @@ -298,20 +297,20 @@ class Runtime {
}

if (WIFSIGNALED(status)) {
VLC_DEBUG("VLC: child terminated by signal %d (%s) %s, pid=%d", WTERMSIG(status), strsignal(WTERMSIG(status)),
VLC_DEBUG("VLC: child terminated by signal %d (%s) %s, pid=%d", WTERMSIG(status), strsignal(WTERMSIG(status)),
(WCOREDUMP(status) ? " (core dumped)" : ""), child_waited);
}

// child has exited or terminated
application_child_states.erase(child_waited);

if (application_child_states.size() == 0) {
std::cout << "VLC: manager exit since application has exited (NOT A ERROR)." << std::endl;
break;
}
}

// child already exist, skip the rest
continue;
// child already exist, skip the rest
continue;
} else if (status >> 8 == SIGUSR1) {
// this is a signal for communication between monitor and application
VLC_DEBUG("VLC: recive SIGUSR1, continued, pid=%d", child_waited);
Expand All @@ -337,7 +336,7 @@ class Runtime {
* modify the result of sched_getaffinity().
* will replace original content in `user_mask_ptr`
* with a virtualized cpu affinity.
*
*
* @param len the number of bytes for user_mask_ptr
* @param user_mask_ptr a remote address of application's cpu set buffer
* Its content will be modified.
Expand All @@ -357,7 +356,7 @@ class Runtime {

virtual_cpu_sets[pid] = std::move(virtual_cpu_set);
}

// copy the virtual cpu set into application's memory
iovec local_iov[1];
local_iov[0].iov_base = &(virtual_cpu_sets[pid]);
Expand All @@ -376,17 +375,17 @@ class Runtime {

/**
* modify the result of openat().
*
*
* if it opening a cpu resouce file
* will replace filename so it will open a forged file instead.
*
*
* @param user_mask_ptr a remote address of filename
* Its content will be modified.
*/
void forge_openat(pid_t pid, unsigned long long *filename_ptr) {
char *filename_str = ptrace_peak_string(pid, *filename_ptr);
VLC_DEBUG("VLC: application try to open %s", filename_str);

// check if the path is cpu resouce file
// modify the pointer value to a pre defined str in the application space
if (strcmp(filename_str, "/sys/devices/system/cpu") == 0) {
Expand All @@ -395,12 +394,12 @@ class Runtime {
*filename_ptr = (unsigned long long) FORGED_CPU_ONLINE_FILE;
} else if (strcmp(filename_str, "/proc/cpuinfo") == 0) {
*filename_ptr = (unsigned long long) FORGED_CPU_INFO_FILE;
}
}
// else if (strcmp(filename_str, "/proc/meminfo") == 0) {
// resource.set_avaliable_mem(0, 8);
// resource.generate_mem_info_file(0, FORGED_MEM_INFO_FILE_BUFFER);
// *filename_ptr = (unsigned long long) FORGED_MEM_INFO_FILE_BUFFER;
// }
// }
else {
free(filename_str);
return;
Expand All @@ -412,12 +411,12 @@ class Runtime {

/**
* read string from remote address space
*
*
* @param pid id of target process
* @param addr remote address in target process's address space
*
*
* @return the pointer to the string
*
*
* @note caller is responsible to free the returned string
*/
char *ptrace_peak_string(pid_t pid, unsigned long long addr) {
Expand Down Expand Up @@ -452,12 +451,12 @@ class Runtime {
return str;
}
};

// void enable() {
// std::thread::id this_id = std::this_thread::get_id();
// }

// void register_thread(pthread_t thread, int id);

}
#endif // _VLC_RUNTIME_H_
#endif // _VLC_RUNTIME_H_