Skip to content

Commit ff570a3

Browse files
refactor: read SANDBOX_BANNED_HOSTS from file instead of env.
1 parent 1263592 commit ff570a3

File tree

2 files changed

+61
-21
lines changed

2 files changed

+61
-21
lines changed

apps/common/utils/tool_code.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@
88
import socket
99
import uuid_utils.compat as uuid
1010
from django.utils.translation import gettext_lazy as _
11-
1211
from maxkb.const import BASE_DIR, CONFIG
1312
from maxkb.const import PROJECT_DIR
13+
from common.utils.logger import maxkb_logger
1414

1515
python_directory = sys.executable
1616

17-
1817
class ToolExecutor:
1918
def __init__(self, sandbox=False):
2019
self.sandbox = sandbox
@@ -28,15 +27,21 @@ def __init__(self, sandbox=False):
2827
if self.sandbox:
2928
os.system(f"chown -R {self.user}:root {self.sandbox_path}")
3029
self.banned_keywords = CONFIG.get("SANDBOX_PYTHON_BANNED_KEYWORDS", 'nothing_is_banned').split(',');
31-
banned_hosts = CONFIG.get("SANDBOX_PYTHON_BANNED_HOSTS", '').strip()
3230
try:
31+
banned_hosts = CONFIG.get("SANDBOX_PYTHON_BANNED_HOSTS", '').strip()
3332
if banned_hosts:
3433
hostname = socket.gethostname()
3534
local_ip = socket.gethostbyname(hostname)
3635
banned_hosts = f"{banned_hosts},{hostname},{local_ip}"
37-
except Exception:
36+
banned_hosts_file_path = f'{self.sandbox_path}/.SANDBOX_BANNED_HOSTS'
37+
if os.path.exists(banned_hosts_file_path):
38+
os.remove(banned_hosts_file_path)
39+
with open(banned_hosts_file_path, "w") as f:
40+
f.write(banned_hosts)
41+
os.chmod(banned_hosts_file_path, 0o644)
42+
except Exception as e:
43+
maxkb_logger.error(f'Failed to init SANDBOX_BANNED_HOSTS due to exception: {e}', exc_info=True)
3844
pass
39-
self.banned_hosts = banned_hosts
4045

4146
def _createdir(self):
4247
old_mask = os.umask(0o077)
@@ -190,8 +195,7 @@ def get_tool_mcp_config(self, code, params):
190195
],
191196
'cwd': self.sandbox_path,
192197
'env': {
193-
'LD_PRELOAD': '/opt/maxkb-app/sandbox/sandbox.so',
194-
'SANDBOX_BANNED_HOSTS': self.banned_hosts,
198+
'LD_PRELOAD': f'{self.sandbox_path}/sandbox.so',
195199
},
196200
'transport': 'stdio',
197201
}
@@ -210,8 +214,7 @@ def _exec_sandbox(self, _code, _id):
210214
os.system(f"chown {self.user}:root {exec_python_file}")
211215
kwargs = {'cwd': BASE_DIR}
212216
kwargs['env'] = {
213-
'LD_PRELOAD': '/opt/maxkb-app/sandbox/sandbox.so',
214-
'SANDBOX_BANNED_HOSTS': self.banned_hosts,
217+
'LD_PRELOAD': f'{self.sandbox_path}/sandbox.so',
215218
}
216219
subprocess_result = subprocess.run(
217220
['su', '-s', python_directory, '-c', "exec(open('" + exec_python_file + "').read())", self.user],

installer/sandbox.c

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,51 @@
99
#include <unistd.h>
1010
#include <sys/socket.h>
1111
#include <errno.h>
12+
#include <limits.h>
13+
#include <libgen.h>
1214

13-
static const char *ENV_NAME = "SANDBOX_BANNED_HOSTS";
15+
static const char *BANNED_FILE_NAME = ".SANDBOX_BANNED_HOSTS";
16+
17+
/**
18+
* 从 .so 文件所在目录读取 .SANDBOX_BANNED_HOSTS 文件内容
19+
* 返回 malloc 出的字符串(需 free),读取失败则返回空字符串
20+
*/
21+
static char *load_banned_hosts() {
22+
Dl_info info;
23+
if (dladdr((void *)load_banned_hosts, &info) == 0 || !info.dli_fname) {
24+
fprintf(stderr, "[sandbox] ⚠️ Unable to locate shared object path — allowing all hosts\n");
25+
return strdup("");
26+
}
27+
28+
char so_path[PATH_MAX];
29+
strncpy(so_path, info.dli_fname, sizeof(so_path));
30+
so_path[sizeof(so_path) - 1] = '\0';
31+
32+
char *dir = dirname(so_path);
33+
char file_path[PATH_MAX];
34+
snprintf(file_path, sizeof(file_path), "%s/%s", dir, BANNED_FILE_NAME);
35+
36+
FILE *fp = fopen(file_path, "r");
37+
if (!fp) {
38+
fprintf(stderr, "[sandbox] ⚠️ Cannot open %s — allowing all hosts\n", file_path);
39+
return strdup("");
40+
}
41+
42+
char *buf = malloc(4096);
43+
if (!buf) {
44+
fclose(fp);
45+
fprintf(stderr, "[sandbox] ⚠️ Memory allocation failed — allowing all hosts\n");
46+
return strdup("");
47+
}
48+
49+
size_t len = fread(buf, 1, 4095, fp);
50+
buf[len] = '\0';
51+
fclose(fp);
52+
return buf;
53+
}
1454

1555
/**
1656
* 精确匹配黑名单
17-
* target: 待检测字符串
18-
* env_val: 逗号分隔的黑名单列表
19-
* 返回 1 = 匹配,0 = 不匹配
2057
*/
2158
static int match_env_patterns(const char *target, const char *env_val) {
2259
if (!target || !env_val || !*env_val) return 0;
@@ -33,7 +70,6 @@ static int match_env_patterns(const char *target, const char *env_val) {
3370

3471
if (*token) {
3572
regex_t regex;
36-
// 精确匹配,加 ^ 和 $,忽略大小写
3773
char fullpattern[512];
3874
snprintf(fullpattern, sizeof(fullpattern), "^%s$", token);
3975

@@ -48,7 +84,6 @@ static int match_env_patterns(const char *target, const char *env_val) {
4884
fprintf(stderr, "[sandbox] ⚠️ Invalid regex '%s' — allowing host by default\n", token);
4985
}
5086
}
51-
5287
token = strtok(NULL, ",");
5388
}
5489

@@ -62,15 +97,16 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
6297
if (!real_connect)
6398
real_connect = dlsym(RTLD_NEXT, "connect");
6499

65-
const char *banned_env = getenv(ENV_NAME);
100+
static char *banned_env = NULL;
101+
if (!banned_env) banned_env = load_banned_hosts();
66102

67103
char ip[INET6_ADDRSTRLEN] = {0};
68104
if (addr->sa_family == AF_INET)
69105
inet_ntop(AF_INET, &((struct sockaddr_in *)addr)->sin_addr, ip, sizeof(ip));
70106
else if (addr->sa_family == AF_INET6)
71107
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)addr)->sin6_addr, ip, sizeof(ip));
72108

73-
if (banned_env && match_env_patterns(ip, banned_env)) {
109+
if (banned_env && *banned_env && match_env_patterns(ip, banned_env)) {
74110
fprintf(stderr, "[sandbox] 🚫 Access to host %s is banned\n", ip);
75111
errno = EACCES;
76112
return -1;
@@ -87,12 +123,13 @@ int getaddrinfo(const char *node, const char *service,
87123
if (!real_getaddrinfo)
88124
real_getaddrinfo = dlsym(RTLD_NEXT, "getaddrinfo");
89125

90-
const char *banned_env = getenv(ENV_NAME);
126+
static char *banned_env = NULL;
127+
if (!banned_env) banned_env = load_banned_hosts();
91128

92-
if (banned_env && node && match_env_patterns(node, banned_env)) {
129+
if (banned_env && *banned_env && node && match_env_patterns(node, banned_env)) {
93130
fprintf(stderr, "[sandbox] 🚫 Access to host %s is banned\n", node);
94-
return EAI_FAIL; // 模拟 DNS 失败
131+
return EAI_FAIL;
95132
}
96133

97134
return real_getaddrinfo(node, service, hints, res);
98-
}
135+
}

0 commit comments

Comments
 (0)