Skip to content

Commit 71f1e26

Browse files
refactor: run python code without su -.
1 parent 39d4ebc commit 71f1e26

File tree

3 files changed

+27
-47
lines changed

3 files changed

+27
-47
lines changed

apps/common/utils/tool_code.py

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ def _generate_mcp_server_code(self, _code, params):
186186
def generate_mcp_server_code(self, code_str, params):
187187
python_paths = CONFIG.get_sandbox_python_package_paths().split(',')
188188
code = self._generate_mcp_server_code(code_str, params)
189+
set_run_user = f'os.setgid({pwd.getpwnam(self.user).pw_gid});os.setuid({pwd.getpwnam(self.user).pw_uid});' if self.sandbox else ''
189190
return f"""
190191
import os, sys, logging
191192
logging.basicConfig(level=logging.WARNING)
@@ -194,6 +195,7 @@ def generate_mcp_server_code(self, code_str, params):
194195
path_to_exclude = ['/opt/py3/lib/python3.11/site-packages', '/opt/maxkb-app/apps']
195196
sys.path = [p for p in sys.path if p not in path_to_exclude]
196197
sys.path += {python_paths}
198+
{set_run_user}
197199
os.environ.clear()
198200
exec({dedent(code)!a})
199201
"""
@@ -202,30 +204,17 @@ def get_tool_mcp_config(self, code, params):
202204
_code = self.generate_mcp_server_code(code, params)
203205
maxkb_logger.debug(f"Python code of mcp tool: {_code}")
204206
compressed_and_base64_encoded_code_str = base64.b64encode(gzip.compress(_code.encode())).decode()
205-
if self.sandbox:
206-
tool_config = {
207-
'command': 'su',
208-
'args': [
209-
'-s', sys.executable,
210-
'-c',
211-
f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())',
212-
self.user,
213-
],
214-
'cwd': self.sandbox_path,
215-
'env': {
216-
'LD_PRELOAD': self.sandbox_so_path,
217-
},
218-
'transport': 'stdio',
219-
}
220-
else:
221-
tool_config = {
222-
'command': sys.executable,
223-
'args': [
224-
'-c',
225-
f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())',
226-
],
227-
'transport': 'stdio',
228-
}
207+
tool_config = {
208+
'command': sys.executable,
209+
'args': [
210+
'-c',
211+
f'import base64,gzip; exec(gzip.decompress(base64.b64decode(\'{compressed_and_base64_encoded_code_str}\')).decode())',
212+
],
213+
'env': {
214+
'LD_PRELOAD': self.sandbox_so_path,
215+
},
216+
'transport': 'stdio',
217+
}
229218
return tool_config
230219

231220
def _exec(self, execute_file):

installer/Dockerfile-base

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
2929
mkdir -p /opt/maxkb-app/sandbox/lib && chmod -R 550 /opt/maxkb-app/sandbox && \
3030
useradd --no-create-home --home /opt/maxkb-app/sandbox sandbox -g root && \
3131
chmod g-xr /usr/local/bin/* /usr/bin/* /bin/* /usr/sbin/* /sbin/* /usr/lib/postgresql/17/bin/* && \
32-
chmod g+xr /usr/bin/ld.so && \
33-
chmod g+x /usr/local/bin/python* && \
3432
chmod -R g-rwx /tmp /var/tmp /var/lock && \
3533
apt-get clean all && \
3634
rm -rf /var/lib/postgresql /var/lib/apt/lists/* /usr/share/doc/* /usr/share/man/* /usr/share/info/* /usr/share/locale/* /usr/share/lintian/* /usr/share/linda/* /var/cache/* /var/log/* /var/tmp/* /tmp/*

installer/sandbox.c

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -212,34 +212,19 @@ static int not_supported(const char *function_name) {
212212
_exit(1);
213213
return -1;
214214
}
215-
static pid_t ppid = 0;
216-
// 在进程初始化时保存 PID
217-
__attribute__((constructor)) static void init_sandbox() {
218-
ppid = getpid();
219-
}
220215
#define RESOLVE_REAL(func) \
221216
static typeof(func) *real_##func = NULL; \
222217
if (!real_##func) { \
223218
real_##func = dlsym(RTLD_NEXT, #func); \
224219
}
225220
int execv(const char *path, char *const argv[]) {
226221
RESOLVE_REAL(execv);
227-
// fprintf(stdout, "execv path: %s ppid=%d pid=%d\n", path, sandbox_pid, getpid());
228-
if (!allow_create_subprocess()) {
229-
// 只允许创建python进程,但不允许python进程替换(用os.execvp里又启动另一个python进程)
230-
if (strstr(path, "bin/python") == NULL || getpid() == ppid) {
231-
return deny();
232-
}
233-
}
222+
if (!allow_create_subprocess()) return deny();
234223
return real_execv(path, argv);
235224
}
236225
int __execv(const char *path, char *const argv[]) {
237226
RESOLVE_REAL(__execv);
238-
if (!allow_create_subprocess()) {
239-
if (strstr(path, "bin/python") == NULL || getpid() == ppid) {
240-
return deny();
241-
}
242-
}
227+
if (!allow_create_subprocess()) return deny();
243228
return real___execv(path, argv);
244229
}
245230
int execve(const char *filename, char *const argv[], char *const envp[]) {
@@ -259,16 +244,24 @@ int execveat(int dirfd, const char *pathname,
259244
return real_execveat(dirfd, pathname, argv, envp, flags);
260245
}
261246
int execvpe(const char *file, char *const argv[], char *const envp[]) {
262-
return not_supported("execvpe");
247+
RESOLVE_REAL(execvpe);
248+
if (!allow_create_subprocess()) return deny();
249+
return real_execvpe(file, argv, envp);
263250
}
264251
int __execvpe(const char *file, char *const argv[], char *const envp[]) {
265-
return not_supported("__execvpe");
252+
RESOLVE_REAL(__execvpe);
253+
if (!allow_create_subprocess()) return deny();
254+
return real___execvpe(file, argv, envp);
266255
}
267256
int execvp(const char *file, char *const argv[]) {
268-
return not_supported("execvp");
257+
RESOLVE_REAL(execvp);
258+
if (!allow_create_subprocess()) return deny();
259+
return real_execvp(file, argv);
269260
}
270261
int __execvp(const char *file, char *const argv[]) {
271-
return not_supported("__execvp");
262+
RESOLVE_REAL(__execvp);
263+
if (!allow_create_subprocess()) return deny();
264+
return real___execvp(file, argv);
272265
}
273266
int execl(const char *path, const char *arg, ...) {
274267
return not_supported("execl");

0 commit comments

Comments
 (0)