safeify
safeify copied to clipboard
在沙箱里调用方法会阻塞主线程,导致 timeout 失效
描述
在下面的代码中,在沙箱中调用 add 方法时,通过 while (true) {}
阻塞主进程,按理说只应该阻塞子进程,在 timeout 后报错,但并没有,这段代码会一直卡住,阻塞主进程。
const {Safeify} = require('./lib')
let debug = require('debug');
debug.enable('safeify');
const safeVm = new Safeify({
timeout: 50, //超时时间,默认 50ms
asyncTimeout: 1000, //包含异步操作的超时时间,默认 500ms
quantity: 2, //沙箱进程数量,默认同 CPU 核数
memoryQuota: 100, //沙箱最大能使用的内存(单位 m),默认 500m
cpuQuota: 0.1, //沙箱的 cpu 资源配额(百分比),默认 50%
});
const context = {
a: 1,
b: 1,
add(a, b) {
while (true){
// console.log(b)
}
return a + b;
}
};
(async function f() {
setTimeout(()=>{
console.log('????')
}, 2000)
const rs = await Promise.all(
[
safeVm.run(`return add(a,1)`, context),
safeVm.run(`return add(a,2)`, context),
// safeVm.run(`return add(a,2)`, context),
// safeVm.run(`return add(a,3)`, context),
// safeVm.run(`return add(a,4)`, context),
// safeVm.run(`return add(a,5)`, context),
// safeVm.run(`return add(a,6)`, context),
// safeVm.run(`return add(a,7)`, context),
// safeVm.run(`return add(a,8)`, context),
// safeVm.run(`return add(a,9)`, context),
// safeVm.run(`return add(a,10)`, context),
// safeVm.run(`return add(a,11)`, context)
]
)
console.log('result', rs);
// 释放资源
safeVm.destroy();
})();
原因
源码中为了限制方法的使用或者是由于进程通信必须序列化的原因,在沙箱子线程中调用 context 的方法时,会回传给主进程,让主线程调用方法并将结果回传给子进程
建议
暂无比较完善的解决方案,望思考
context是给沙箱的上下文,不应该在这里死循环。同时上下文是可选的 run(code: string | Function, sandbox?: any): Promise<any>
另外,线程与进程是两回事。
是我表达有误,应该全是进程而不是线程,已修改。二者,虽然上下文是主进程提供的,但是在运行的时候,由于引入了子进程的概念,我们更希望所有代码的执行都放在子进程中运行,这样才能将二者分开,不会因为子进程(恶意地调用某个上下文的方法)导致主进程异常。
例子:
const {Safeify} = require('safeify')
const safeVm = new Safeify({
timeout: 50, //超时时间,默认 50ms
asyncTimeout: 1000, //包含异步操作的超时时间,默认 500ms
quantity: 4, //沙箱进程数量,默认同 CPU 核数
memoryQuota: 100, //沙箱最大能使用的内存(单位 m),默认 500m
cpuQuota: 0.1, //沙箱的 cpu 资源配额(百分比),默认 50%
});
const context = {
/**
* 计算总和 (一个很正常的函数,由主进程提供)
* @param arr
* @return {number}
*/
sum(arr = []) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i]
}
return sum
}
};
(async function f() {
const sum = await safeVm.run(`
// 恶意代码,恶意调用主进程的方法
return sum({ length: 10e307 })
`, context);
// 会卡住主进程,即便 timeout 也不会强制结束
console.log('result', sum);
// 释放资源
safeVm.destroy();
})();