Skip to content

Commit 479701a

Browse files
security: fix sandbox escape via ctypes and Unhooked SYS_pkey_mprotect.
1 parent 2d61834 commit 479701a

File tree

2 files changed

+32
-4
lines changed

2 files changed

+32
-4
lines changed

apps/common/utils/tool_code.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def init_sandbox_dir():
7171
os.remove(sandbox_conf_file_path)
7272
banned_hosts = CONFIG.get("SANDBOX_PYTHON_BANNED_HOSTS", '').strip()
7373
allow_dl_paths = CONFIG.get("SANDBOX_PYTHON_ALLOW_DL_PATHS",'').strip()
74+
allow_dl_open = CONFIG.get("SANDBOX_PYTHON_ALLOW_DL_OPEN",'0')
7475
allow_subprocess = CONFIG.get("SANDBOX_PYTHON_ALLOW_SUBPROCESS", '0')
7576
allow_syscall = CONFIG.get("SANDBOX_PYTHON_ALLOW_SYSCALL", '0')
7677
if banned_hosts:
@@ -81,6 +82,7 @@ def init_sandbox_dir():
8182
with open(sandbox_conf_file_path, "w") as f:
8283
f.write(f"SANDBOX_PYTHON_BANNED_HOSTS={banned_hosts}\n")
8384
f.write(f"SANDBOX_PYTHON_ALLOW_DL_PATHS={','.join(sorted(set(filter(None, sys.path + _sandbox_python_sys_path + allow_dl_paths.split(',')))))}\n")
85+
f.write(f"SANDBOX_PYTHON_ALLOW_DL_OPEN={allow_dl_open}\n")
8486
f.write(f"SANDBOX_PYTHON_ALLOW_SUBPROCESS={allow_subprocess}\n")
8587
f.write(f"SANDBOX_PYTHON_ALLOW_SYSCALL={allow_syscall}\n")
8688
os.system(f"chmod -R 550 {_sandbox_path}")

installer/sandbox.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,18 @@
2222
#include <pty.h>
2323
#include <stdint.h>
2424
#include <stdbool.h>
25+
#include <execinfo.h>
2526

2627
#define CONFIG_FILE ".sandbox.conf"
2728
#define KEY_BANNED_HOSTS "SANDBOX_PYTHON_BANNED_HOSTS"
2829
#define KEY_ALLOW_DL_PATHS "SANDBOX_PYTHON_ALLOW_DL_PATHS"
30+
#define KEY_ALLOW_DL_OPEN "SANDBOX_PYTHON_ALLOW_DL_OPEN"
2931
#define KEY_ALLOW_SUBPROCESS "SANDBOX_PYTHON_ALLOW_SUBPROCESS"
3032
#define KEY_ALLOW_SYSCALL "SANDBOX_PYTHON_ALLOW_SYSCALL"
3133

3234
static char *banned_hosts = NULL;
3335
static char *allow_dl_paths = NULL;
36+
static int allow_dl_open = 0;
3437
static int allow_subprocess = 0; // 默认禁止
3538
static int allow_syscall = 0;
3639

@@ -39,6 +42,7 @@ static void load_sandbox_config() {
3942
if (dladdr((void *)load_sandbox_config, &info) == 0 || !info.dli_fname) {
4043
banned_hosts = strdup("");
4144
allow_dl_paths = strdup("");
45+
allow_dl_open = 0;
4246
allow_subprocess = 0;
4347
allow_syscall = 0;
4448
return;
@@ -53,6 +57,7 @@ static void load_sandbox_config() {
5357
if (!fp) {
5458
banned_hosts = strdup("");
5559
allow_dl_paths = strdup("");
60+
allow_dl_open = 0;
5661
allow_subprocess = 0;
5762
allow_syscall = 0;
5863
return;
@@ -62,6 +67,7 @@ static void load_sandbox_config() {
6267
if (allow_dl_paths) { free(allow_dl_paths); allow_dl_paths = NULL; }
6368
banned_hosts = strdup("");
6469
allow_dl_paths = strdup("");
70+
allow_dl_open = 0;
6571
allow_subprocess = 0;
6672
allow_syscall = 0;
6773
while (fgets(line, sizeof(line), fp)) {
@@ -80,6 +86,8 @@ static void load_sandbox_config() {
8086
} else if (strcmp(key, KEY_ALLOW_DL_PATHS) == 0) {
8187
free(allow_dl_paths);
8288
allow_dl_paths = strdup(value); // 逗号分隔字符串
89+
} else if (strcmp(key, KEY_ALLOW_DL_OPEN) == 0) {
90+
allow_dl_open = atoi(value);
8391
} else if (strcmp(key, KEY_ALLOW_SUBPROCESS) == 0) {
8492
allow_subprocess = atoi(value);
8593
} else if (strcmp(key, KEY_ALLOW_SYSCALL) == 0) {
@@ -519,6 +527,7 @@ long syscall(long number, ...) {
519527
#endif
520528
case SYS_fchmodat:
521529
case SYS_mprotect:
530+
case SYS_pkey_mprotect:
522531
#ifdef SYS_open
523532
case SYS_open:
524533
#endif
@@ -543,7 +552,24 @@ long syscall(long number, ...) {
543552
/**
544553
* 限制加载动态链接库
545554
*/
546-
static int is_in_allow_dl_paths(const char *filename) {
555+
static int called_from_python_import() {
556+
if (allow_dl_open) return 1;
557+
void *buf[32];
558+
int n = backtrace(buf, 32);
559+
for (int i = 0; i < n; i++) {
560+
Dl_info info;
561+
if (dladdr(buf[i], &info) && info.dli_sname) {
562+
if (strstr(info.dli_sname, "PyImport") ||
563+
strstr(info.dli_sname, "_PyImport")) {
564+
return 1;
565+
}
566+
}
567+
}
568+
throw_permission_denied_err(true, "open dynamic link library");
569+
return 0;
570+
}
571+
static int is_allow_dl(const char *filename) {
572+
if (!called_from_python_import()) return 0;
547573
if (!filename || !*filename) return 1;
548574
ensure_config_loaded();
549575
if (!allow_dl_paths || !*allow_dl_paths) return 0;
@@ -570,7 +596,7 @@ static int is_in_allow_dl_paths(const char *filename) {
570596
}
571597
void *dlopen(const char *filename, int flag) {
572598
RESOLVE_REAL(dlopen);
573-
if (is_sandbox_user() && !is_in_allow_dl_paths(filename)) {
599+
if (is_sandbox_user() && !is_allow_dl(filename)) {
574600
throw_permission_denied_err(true, "access file %s", filename);
575601
}
576602
return real_dlopen(filename, flag);
@@ -580,7 +606,7 @@ void *__dlopen(const char *filename, int flag) {
580606
}
581607
void *dlmopen(Lmid_t lmid, const char *filename, int flags) {
582608
RESOLVE_REAL(dlmopen);
583-
if (is_sandbox_user() && !is_in_allow_dl_paths(filename)) {
609+
if (is_sandbox_user() && !is_allow_dl(filename)) {
584610
throw_permission_denied_err(true, "access file %s", filename);
585611
}
586612
return real_dlmopen(lmid, filename, flags);
@@ -602,7 +628,7 @@ void* mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) {
602628
throw_permission_denied_err(true, "mmap(readlink failed)");
603629
}
604630
real_path[n] = '\0';
605-
if (!is_in_allow_dl_paths(real_path)) {
631+
if (!is_allow_dl(real_path)) {
606632
throw_permission_denied_err(true, "mmap %s", real_path);
607633
}
608634
}

0 commit comments

Comments
 (0)