Skip to content

Commit 9b621bc

Browse files
fix: handle long arguments in sandbox.
1 parent d83d70a commit 9b621bc

File tree

1 file changed

+17
-39
lines changed

1 file changed

+17
-39
lines changed

apps/common/utils/tool_code.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import socket
88
import subprocess
99
import sys
10-
import signal
11-
import time
10+
import tempfile
11+
import pwd
1212
import uuid_utils.compat as uuid
1313
from common.utils.logger import maxkb_logger
1414
from django.utils.translation import gettext_lazy as _
@@ -82,6 +82,7 @@ def exec_code(self, code_str, keywords, function_name=None):
8282
err = '{"code":500,"msg":str(e),"data":None}'
8383
action_function = f'({function_name !a}, locals_v.get({function_name !a}))' if function_name else 'locals_v.popitem()'
8484
python_paths = CONFIG.get_sandbox_python_package_paths().split(',')
85+
target_user = f'os.setgid({pwd.getpwnam(self.user).pw_gid});os.setuid({pwd.getpwnam(self.user).pw_uid});' if self.sandbox else ''
8586
_exec_code = f"""
8687
try:
8788
import os, sys, json, base64, builtins
@@ -92,19 +93,21 @@ def exec_code(self, code_str, keywords, function_name=None):
9293
keywords={keywords}
9394
globals_v={'{}'}
9495
os.environ.clear()
96+
{target_user}
9597
exec({dedent(code_str)!a}, globals_v, locals_v)
9698
f_name, f = {action_function}
9799
for local in locals_v:
98100
globals_v[local] = locals_v[local]
99101
exec_result=f(**keywords)
100-
builtins.print("\\n{_id}:"+base64.b64encode(json.dumps({success}, default=str).encode()).decode())
102+
builtins.print("\\n{_id}:"+base64.b64encode(json.dumps({success}, default=str).encode()).decode(), flush=True)
101103
except Exception as e:
102-
builtins.print("\\n{_id}:"+base64.b64encode(json.dumps({err}, default=str).encode()).decode())
104+
builtins.print("\\n{_id}:"+base64.b64encode(json.dumps({err}, default=str).encode()).decode(), flush=True)
103105
"""
104-
if self.sandbox:
105-
subprocess_result = self._exec_sandbox(_exec_code)
106-
else:
107-
subprocess_result = self._exec(_exec_code)
106+
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=True) as f:
107+
maxkb_logger.debug(f"Sandbox execute code: {_exec_code}")
108+
f.write(_exec_code)
109+
f.flush()
110+
subprocess_result = self._exec(f.name)
108111
if subprocess_result.returncode != 0:
109112
raise Exception(subprocess_result.stderr or subprocess_result.stdout or "Unknown exception occurred")
110113
lines = subprocess_result.stdout.splitlines()
@@ -225,40 +228,18 @@ def get_tool_mcp_config(self, code, params):
225228
}
226229
return tool_config
227230

228-
def _exec_sandbox(self, _code):
231+
def _exec(self, execute_file):
229232
kwargs = {'cwd': BASE_DIR, 'env': {
230233
'LD_PRELOAD': self.sandbox_so_path,
231234
}}
232-
maxkb_logger.debug(f"Sandbox execute code: {_code}")
233-
compressed_and_base64_encoded_code_str = base64.b64encode(gzip.compress(_code.encode())).decode()
234-
cmd = [
235-
'su', '-s', python_directory, '-c',
236-
f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())',
237-
self.user
238-
]
239235
try:
240-
proc = subprocess.Popen(
241-
cmd,
242-
stdout=subprocess.PIPE,
243-
stderr=subprocess.PIPE,
236+
subprocess_result = subprocess.run(
237+
[python_directory, execute_file],
238+
timeout=self.process_timeout_seconds,
244239
text=True,
245-
**kwargs,
246-
start_new_session=True
247-
)
248-
proc.wait(timeout=self.process_timeout_seconds)
249-
return subprocess.CompletedProcess(
250-
proc.args,
251-
proc.returncode,
252-
proc.stdout.read(),
253-
proc.stderr.read()
254-
)
240+
capture_output=True, **kwargs)
241+
return subprocess_result
255242
except subprocess.TimeoutExpired:
256-
pgid = os.getpgid(proc.pid)
257-
os.killpg(pgid, signal.SIGTERM) #温和终止
258-
time.sleep(1) #留出短暂时间让进程清理
259-
if proc.poll() is None: #如果仍未终止,强制终止
260-
os.killpg(pgid, signal.SIGKILL)
261-
proc.wait()
262243
raise Exception(_(f"Process execution timed out after {self.process_timeout_seconds} seconds."))
263244

264245
def validate_mcp_transport(self, code_str):
@@ -267,6 +248,3 @@ def validate_mcp_transport(self, code_str):
267248
if config.get('transport') not in ['sse', 'streamable_http']:
268249
raise Exception(_('Only support transport=sse or transport=streamable_http'))
269250

270-
@staticmethod
271-
def _exec(_code):
272-
return subprocess.run([python_directory, '-c', _code], text=True, capture_output=True)

0 commit comments

Comments
 (0)