|
8 | 8 | import subprocess |
9 | 9 | import sys |
10 | 10 | import signal |
| 11 | +import time |
11 | 12 | import uuid_utils.compat as uuid |
12 | 13 | from common.utils.logger import maxkb_logger |
13 | 14 | from django.utils.translation import gettext_lazy as _ |
@@ -221,26 +222,40 @@ def get_tool_mcp_config(self, code, params): |
221 | 222 | return tool_config |
222 | 223 |
|
223 | 224 | def _exec_sandbox(self, _code): |
224 | | - kwargs = {'cwd': BASE_DIR} |
225 | | - kwargs['env'] = { |
| 225 | + kwargs = {'cwd': BASE_DIR, 'env': { |
226 | 226 | 'LD_PRELOAD': self.sandbox_so_path, |
227 | | - } |
| 227 | + }} |
228 | 228 | maxkb_logger.debug(f"Sandbox execute code: {_code}") |
229 | 229 | compressed_and_base64_encoded_code_str = base64.b64encode(gzip.compress(_code.encode())).decode() |
| 230 | + cmd = [ |
| 231 | + 'su', '-s', python_directory, '-c', |
| 232 | + f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())', |
| 233 | + self.user |
| 234 | + ] |
230 | 235 | try: |
231 | | - subprocess_result = subprocess.run( |
232 | | - ['su', '-s', python_directory, '-c', |
233 | | - f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())', |
234 | | - self.user], |
| 236 | + proc = subprocess.Popen( |
| 237 | + cmd, |
| 238 | + stdout=subprocess.PIPE, |
| 239 | + stderr=subprocess.PIPE, |
235 | 240 | text=True, |
236 | | - capture_output=True, |
237 | | - timeout=self.process_timeout_seconds, |
238 | | - preexec_fn=os.setsid, |
239 | | - **kwargs) |
240 | | - except subprocess.TimeoutExpired as e: |
241 | | - os.killpg(e.pid, signal.SIGKILL) |
| 241 | + **kwargs, |
| 242 | + start_new_session=True |
| 243 | + ) |
| 244 | + proc.wait(timeout=self.process_timeout_seconds) |
| 245 | + return subprocess.CompletedProcess( |
| 246 | + proc.args, |
| 247 | + proc.returncode, |
| 248 | + proc.stdout.read(), |
| 249 | + proc.stderr.read() |
| 250 | + ) |
| 251 | + except subprocess.TimeoutExpired: |
| 252 | + pgid = os.getpgid(proc.pid) |
| 253 | + os.killpg(pgid, signal.SIGTERM) #温和终止 |
| 254 | + time.sleep(1) #留出短暂时间让进程清理 |
| 255 | + if proc.poll() is None: #如果仍未终止,强制终止 |
| 256 | + os.killpg(pgid, signal.SIGKILL) |
| 257 | + proc.wait() |
242 | 258 | raise Exception(_("Sandbox process execution timeout, consider increasing MAXKB_SANDBOX_PYTHON_PROCESS_TIMEOUT_SECONDS.")) |
243 | | - return subprocess_result |
244 | 259 |
|
245 | 260 | def validate_mcp_transport(self, code_str): |
246 | 261 | servers = json.loads(code_str) |
|
0 commit comments