1111#include <errno.h>
1212#include <limits.h>
1313#include <libgen.h>
14+ #include <pwd.h>
15+ #include <stdarg.h>
16+ #include <spawn.h>
17+ #include <sys/syscall.h>
18+ #include <sys/types.h>
19+ #include <time.h>
20+ #include <execinfo.h>
21+ #include <dlfcn.h>
1422
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 );
23+ #define CONFIG_FILE ".sandbox.conf"
3524
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- }
25+ static char * banned_hosts = NULL ;
26+ static int allow_subprocess = 0 ; // 默认禁止
4127
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 ("" );
28+ static void load_sandbox_config () {
29+ Dl_info info ;
30+ if (dladdr ((void * )load_sandbox_config , & info ) == 0 || !info .dli_fname ) {
31+ banned_hosts = strdup ("" );
32+ allow_subprocess = 0 ;
33+ return ;
34+ }
35+ char so_path [PATH_MAX ];
36+ strncpy (so_path , info .dli_fname , sizeof (so_path ));
37+ so_path [sizeof (so_path ) - 1 ] = '\0' ;
38+ char * dir = dirname (so_path );
39+ char config_path [PATH_MAX ];
40+ snprintf (config_path , sizeof (config_path ), "%s/%s" , dir , CONFIG_FILE );
41+ FILE * fp = fopen (config_path , "r" );
42+ if (!fp ) {
43+ banned_hosts = strdup ("" );
44+ allow_subprocess = 0 ;
45+ return ;
46+ }
47+ char line [512 ];
48+ banned_hosts = strdup ("" );
49+ allow_subprocess = 0 ;
50+ while (fgets (line , sizeof (line ), fp )) {
51+ char * key = strtok (line , "=" );
52+ char * value = strtok (NULL , "\n" );
53+ if (!key || !value ) continue ;
54+ while (* key == ' ' || * key == '\t' ) key ++ ;
55+ char * kend = key + strlen (key ) - 1 ;
56+ while (kend > key && (* kend == ' ' || * kend == '\t' )) * kend -- = '\0' ;
57+ while (* value == ' ' || * value == '\t' ) value ++ ;
58+ char * vend = value + strlen (value ) - 1 ;
59+ while (vend > value && (* vend == ' ' || * vend == '\t' )) * vend -- = '\0' ;
60+ if (strcmp (key , "SANDBOX_PYTHON_BANNED_HOSTS" ) == 0 ) {
61+ free (banned_hosts );
62+ banned_hosts = strdup (value );
63+ } else if (strcmp (key , "SANDBOX_PYTHON_ALLOW_SUBPROCESS" ) == 0 ) {
64+ allow_subprocess = atoi (value );
65+ }
4766 }
48-
49- size_t len = fread (buf , 1 , 4095 , fp );
50- buf [len ] = '\0' ;
5167 fclose (fp );
52- return buf ;
5368}
54-
69+ static void ensure_config_loaded () {
70+ if (!banned_hosts ) load_sandbox_config ();
71+ }
72+ static int is_sandbox_user () {
73+ uid_t uid = getuid ();
74+ struct passwd * pw = getpwuid (uid );
75+ if (!pw || !pw -> pw_name ) {
76+ return 1 ; // 无法识别用户 → 认为是sandbox
77+ }
78+ if (strcmp (pw -> pw_name , "sandbox" ) == 0 ) {
79+ return 1 ;
80+ }
81+ return 0 ;
82+ }
5583/**
5684 * 精确匹配黑名单
5785 */
5886static int match_env_patterns (const char * target , const char * env_val ) {
5987 if (!target || !env_val || !* env_val ) return 0 ;
60-
6188 char * patterns = strdup (env_val );
6289 char * token = strtok (patterns , "," );
6390 int matched = 0 ;
64-
6591 while (token ) {
66- // 去掉前后空格
6792 while (* token == ' ' || * token == '\t' ) token ++ ;
6893 char * end = token + strlen (token ) - 1 ;
6994 while (end > token && (* end == ' ' || * end == '\t' )) * end -- = '\0' ;
70-
7195 if (* token ) {
7296 regex_t regex ;
7397 char fullpattern [512 ];
7498 snprintf (fullpattern , sizeof (fullpattern ), "^%s$" , token );
75-
7699 if (regcomp (& regex , fullpattern , REG_EXTENDED | REG_NOSUB | REG_ICASE ) == 0 ) {
77100 if (regexec (& regex , target , 0 , NULL , 0 ) == 0 ) {
78101 matched = 1 ;
79102 regfree (& regex );
80103 break ;
81104 }
82105 regfree (& regex );
83- } else {
84- fprintf (stderr , "[sandbox] ⚠️ Invalid regex '%s' — allowing host by default\n" , token );
85106 }
86107 }
87108 token = strtok (NULL , "," );
88109 }
89-
90110 free (patterns );
91111 return matched ;
92112}
@@ -96,22 +116,17 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
96116 static int (* real_connect )(int , const struct sockaddr * , socklen_t ) = NULL ;
97117 if (!real_connect )
98118 real_connect = dlsym (RTLD_NEXT , "connect" );
99-
100- static char * banned_env = NULL ;
101- if (!banned_env ) banned_env = load_banned_hosts ();
102-
119+ ensure_config_loaded ();
103120 char ip [INET6_ADDRSTRLEN ] = {0 };
104121 if (addr -> sa_family == AF_INET )
105122 inet_ntop (AF_INET , & ((struct sockaddr_in * )addr )-> sin_addr , ip , sizeof (ip ));
106123 else if (addr -> sa_family == AF_INET6 )
107124 inet_ntop (AF_INET6 , & ((struct sockaddr_in6 * )addr )-> sin6_addr , ip , sizeof (ip ));
108-
109- if (banned_env && * banned_env && match_env_patterns (ip , banned_env )) {
125+ if (is_sandbox_user () && banned_hosts && * banned_hosts && match_env_patterns (ip , banned_hosts )) {
110126 fprintf (stderr , "[sandbox] 🚫 Access to host %s is banned\n" , ip );
111127 errno = EACCES ; // EACCES 的值是 13, 意思是 Permission denied
112128 return -1 ;
113129 }
114-
115130 return real_connect (sockfd , addr , addrlen );
116131}
117132
@@ -122,23 +137,183 @@ int getaddrinfo(const char *node, const char *service,
122137 const struct addrinfo * , struct addrinfo * * ) = NULL ;
123138 if (!real_getaddrinfo )
124139 real_getaddrinfo = dlsym (RTLD_NEXT , "getaddrinfo" );
125-
126- static char * banned_env = NULL ;
127- if (!banned_env ) banned_env = load_banned_hosts ();
128-
129- if (banned_env && * banned_env && node ) {
140+ ensure_config_loaded ();
141+ if (banned_hosts && * banned_hosts && node ) {
130142 // 检测 node 是否是 IP
131143 struct in_addr ipv4 ;
132144 struct in6_addr ipv6 ;
133145 int is_ip = (inet_pton (AF_INET , node , & ipv4 ) == 1 ) ||
134146 (inet_pton (AF_INET6 , node , & ipv6 ) == 1 );
135-
136147 // 只对“非IP的域名”进行屏蔽
137- if (!is_ip && match_env_patterns (node , banned_env )) {
148+ if (is_sandbox_user () && !is_ip && match_env_patterns (node , banned_hosts )) {
138149 fprintf (stderr , "[sandbox] 🚫 Access to host %s is banned (DNS blocked)\n" , node );
139150 return EAI_FAIL ; // 模拟 DNS 层禁止
140151 }
141152 }
142-
143153 return real_getaddrinfo (node , service , hints , res );
144154}
155+ /* ------------------ 禁止创建子进程------------------ */
156+ static int allow_create_subprocess () {
157+ ensure_config_loaded ();
158+ return allow_subprocess || !is_sandbox_user ();
159+ }
160+ static int return_deny () {
161+ fprintf (stderr , "[sandbox] Permission denied to create subprocess in sandbox.\n" );
162+ _exit (1 );
163+ return -1 ;
164+ }
165+ int execve (const char * filename , char * const argv [], char * const envp []) {
166+ if (!allow_create_subprocess ()) {
167+ return return_deny ();
168+ }
169+ static int (* real_execve )(const char * , char * const [], char * const []) = NULL ;
170+ if (!real_execve ) real_execve = dlsym (RTLD_NEXT , "execve" );
171+ return real_execve (filename , argv , envp );
172+ }
173+
174+ int execveat (int dirfd , const char * pathname ,
175+ char * const argv [], char * const envp [], int flags ) {
176+ if (!allow_create_subprocess ()) {
177+ return return_deny ();
178+ }
179+ static int (* real_execveat )(int , const char * , char * const [], char * const [], int ) = NULL ;
180+ if (!real_execveat ) real_execveat = dlsym (RTLD_NEXT , "execveat" );
181+ return real_execveat (dirfd , pathname , argv , envp , flags );
182+ }
183+
184+ pid_t fork (void ) {
185+ if (!allow_create_subprocess ()) {
186+ return return_deny ();
187+ }
188+ static pid_t (* real_fork )(void ) = NULL ;
189+ if (!real_fork ) real_fork = dlsym (RTLD_NEXT , "fork" );
190+ return real_fork ();
191+ }
192+
193+ pid_t vfork (void ) {
194+ if (!allow_create_subprocess ()) {
195+ return return_deny ();
196+ }
197+ static pid_t (* real_vfork )(void ) = NULL ;
198+ if (!real_vfork ) real_vfork = dlsym (RTLD_NEXT , "vfork" );
199+ return real_vfork ();
200+ }
201+
202+ int clone (int (* fn )(void * ), void * child_stack , int flags , void * arg , ...) {
203+ if (!allow_create_subprocess ()) {
204+ return return_deny ();
205+ }
206+ static int (* real_clone )(int (* )(void * ), void * , int , void * , ...) = NULL ;
207+ if (!real_clone ) real_clone = dlsym (RTLD_NEXT , "clone" );
208+ va_list ap ;
209+ va_start (ap , arg );
210+ int ret = real_clone (fn , child_stack , flags , arg , ap );
211+ va_end (ap );
212+ return ret ;
213+ }
214+
215+ int posix_spawn (pid_t * pid , const char * path ,
216+ const posix_spawn_file_actions_t * file_actions ,
217+ const posix_spawnattr_t * attrp ,
218+ char * const argv [], char * const envp []) {
219+ if (!allow_create_subprocess ()) {
220+ return return_deny ();
221+ }
222+ static int (* real_posix_spawn )(pid_t * , const char * , const posix_spawn_file_actions_t * ,
223+ const posix_spawnattr_t * , char * const [], char * const []) = NULL ;
224+ if (!real_posix_spawn ) real_posix_spawn = dlsym (RTLD_NEXT , "posix_spawn" );
225+ return real_posix_spawn (pid , path , file_actions , attrp , argv , envp );
226+ }
227+
228+ int posix_spawnp (pid_t * pid , const char * file ,
229+ const posix_spawn_file_actions_t * file_actions ,
230+ const posix_spawnattr_t * attrp ,
231+ char * const argv [], char * const envp []) {
232+ if (!allow_create_subprocess ()) {
233+ return return_deny ();
234+ }
235+ static int (* real_posix_spawnp )(pid_t * , const char * , const posix_spawn_file_actions_t * ,
236+ const posix_spawnattr_t * , char * const [], char * const []) = NULL ;
237+ if (!real_posix_spawnp ) real_posix_spawnp = dlsym (RTLD_NEXT , "posix_spawnp" );
238+ return real_posix_spawnp (pid , file , file_actions , attrp , argv , envp );
239+ }
240+ int __posix_spawn (pid_t * pid , const char * path ,
241+ const posix_spawn_file_actions_t * file_actions ,
242+ const posix_spawnattr_t * attrp ,
243+ char * const argv [], char * const envp []) {
244+ if (!allow_create_subprocess ()) {
245+ return return_deny ();
246+ }
247+
248+ static int (* real___posix_spawn )(pid_t * , const char * ,
249+ const posix_spawn_file_actions_t * ,
250+ const posix_spawnattr_t * ,
251+ char * const [], char * const []) = NULL ;
252+
253+ if (!real___posix_spawn )
254+ real___posix_spawn = dlsym (RTLD_NEXT , "__posix_spawn" );
255+
256+ return real___posix_spawn (pid , path , file_actions , attrp , argv , envp );
257+ }
258+
259+ int __posix_spawnp (pid_t * pid , const char * file ,
260+ const posix_spawn_file_actions_t * file_actions ,
261+ const posix_spawnattr_t * attrp ,
262+ char * const argv [], char * const envp []) {
263+ if (!allow_create_subprocess ()) {
264+ return return_deny ();
265+ }
266+
267+ static int (* real___posix_spawnp )(pid_t * , const char * ,
268+ const posix_spawn_file_actions_t * ,
269+ const posix_spawnattr_t * ,
270+ char * const [], char * const []) = NULL ;
271+
272+ if (!real___posix_spawnp )
273+ real___posix_spawnp = dlsym (RTLD_NEXT , "__posix_spawnp" );
274+
275+ return real___posix_spawnp (pid , file , file_actions , attrp , argv , envp );
276+ }
277+
278+ int system (const char * command ) {
279+ if (!allow_create_subprocess ()) {
280+ return return_deny ();
281+ }
282+ static int (* real_system )(const char * ) = NULL ;
283+ if (!real_system ) real_system = dlsym (RTLD_NEXT , "system" );
284+ return real_system (command );
285+ }
286+ int __libc_system (const char * command ) {
287+ if (!allow_create_subprocess ()) {
288+ return return_deny ();
289+ }
290+ static int (* real___libc_system )(const char * ) = NULL ;
291+ if (!real___libc_system )
292+ real___libc_system = dlsym (RTLD_NEXT , "__libc_system" );
293+
294+ return real___libc_system (command );
295+ }
296+ long (* real_syscall )(long , ...) = NULL ;
297+
298+ long syscall (long number , ...) {
299+ if (!real_syscall ) real_syscall = dlsym (RTLD_NEXT , "syscall" );
300+
301+ va_list ap ;
302+ va_start (ap , number );
303+ long a1 = va_arg (ap , long );
304+ long a2 = va_arg (ap , long );
305+ long a3 = va_arg (ap , long );
306+ long a4 = va_arg (ap , long );
307+ long a5 = va_arg (ap , long );
308+ long a6 = va_arg (ap , long );
309+ va_end (ap );
310+
311+ if (number == SYS_execve || number == SYS_execveat ||
312+ number == SYS_fork || number == SYS_vfork || number == SYS_clone ) {
313+ if (!allow_create_subprocess ()) {
314+ return return_deny ();
315+ }
316+ }
317+
318+ return real_syscall (number , a1 , a2 , a3 , a4 , a5 , a6 );
319+ }
0 commit comments