-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsandbox.cpp
More file actions
145 lines (119 loc) · 4.47 KB
/
Copy pathsandbox.cpp
File metadata and controls
145 lines (119 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "sandbox.h"
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <fstream>
#include <ctime>
#include <iostream>
#include <cstring>
// Helper to log events to a file
void Sandbox::logEvent(const std::string& message) {
std::ofstream logFile("sandbox_exec.log", std::ios_base::app);
std::time_t now = std::time(nullptr);
char* dt = std::ctime(&now);
if (dt) dt[strlen(dt)-1] = '\0'; // Remove newline
logFile << "[" << (dt ? dt : "Time") << "] " << message << "\n";
}
ExecutionResult Sandbox::execute(const std::string& binaryPath) {
ExecutionResult result;
result.timeout = false;
result.exitCode = -1;
result.signal = 0;
logEvent("------------------------------------------------");
logEvent("Initiating Sandboxed Execution for: " + binaryPath);
int pipefd[2];
if (pipe(pipefd) == -1) {
logEvent("Error: Failed to create output pipe.");
return result;
}
pid_t pid = fork();
if (pid == 0) {
// --- CHILD PROCESS ---
close(pipefd[0]); // Close read end
// Redirect stdout/stderr
if (dup2(pipefd[1], STDOUT_FILENO) == -1) _exit(1);
if (dup2(pipefd[1], STDERR_FILENO) == -1) _exit(1);
close(pipefd[1]); // Close write end after dup
// 1. CPU Time Limit (1s soft, 2s hard)
struct rlimit cpuLimit = {1, 2};
setrlimit(RLIMIT_CPU, &cpuLimit);
// 2. Memory Limit (64MB)
struct rlimit memLimit = {64 * 1024 * 1024, 64 * 1024 * 1024};
setrlimit(RLIMIT_AS, &memLimit);
// 3. Process Limit (Prevent Fork Bombs)
// We set this to 0 to prevent the child from creating NEW processes.
struct rlimit nprocLimit = {0, 0};
setrlimit(RLIMIT_NPROC, &nprocLimit);
// 4. File Size Limit (1MB)
struct rlimit fsizeLimit = {1024 * 1024, 1024 * 1024};
setrlimit(RLIMIT_FSIZE, &fsizeLimit);
// 5. Disable Core Dumps
struct rlimit coreLimit = {0, 0};
setrlimit(RLIMIT_CORE, &coreLimit);
// Execute
execl(binaryPath.c_str(), binaryPath.c_str(), NULL);
// If execl fails
_exit(1);
}
// --- PARENT PROCESS ---
close(pipefd[1]); // Close write end immediately
logEvent("Child process spawned with PID: " + std::to_string(pid));
const int TIMEOUT_MS = 2000;
int elapsed = 0;
int status;
bool killedByTimeout = false;
while (true) {
pid_t res = waitpid(pid, &status, WNOHANG);
if (res == pid) {
// Child exited naturally
break;
}
if (res == -1) {
// Error in waitpid
break;
}
if (elapsed >= TIMEOUT_MS) {
logEvent("Timeout reached. Killing process.");
kill(pid, SIGKILL);
killedByTimeout = true;
result.timeout = true;
// CRITICAL: Must wait for the kill to finish
waitpid(pid, &status, 0);
break;
}
usleep(100000); // 100ms
elapsed += 100;
}
// Read remaining output
char buffer[128];
ssize_t n;
while ((n = read(pipefd[0], buffer, sizeof(buffer) - 1)) > 0) {
buffer[n] = '\0';
result.output += buffer;
}
close(pipefd[0]);
// Interpret Status
if (WIFSIGNALED(status)) {
result.signal = WTERMSIG(status);
result.rawStatus = "Terminated by signal " + std::to_string(result.signal);
logEvent("Process terminated by signal: " + std::to_string(result.signal));
if (result.signal == SIGSYS) {
result.interpretation = "SECURITY VIOLATION: Blocked system call attempted";
result.rawStatus += " (SIGSYS)";
}
else if (result.signal == SIGSEGV) result.interpretation = "Invalid memory access";
else if (result.signal == SIGXCPU) result.interpretation = "CPU time limit exceeded";
else if (result.signal == SIGXFSZ) result.interpretation = "File output size limit exceeded";
else if (result.signal == SIGKILL && killedByTimeout) result.interpretation = "Time limit exceeded";
else result.interpretation = "Abnormal termination";
}
else if (WIFEXITED(status)) {
result.exitCode = WEXITSTATUS(status);
result.rawStatus = "Completed";
logEvent("Process exited normally with code: " + std::to_string(result.exitCode));
}
return result;
}