Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The use of eval in vm is restricted #425

Open
LoyDgIk opened this issue Dec 10, 2024 · 11 comments
Open

The use of eval in vm is restricted #425

LoyDgIk opened this issue Dec 10, 2024 · 11 comments

Comments

@LoyDgIk
Copy link

LoyDgIk commented Dec 10, 2024

runtime.getExecutor("""
    const vm = require('node:vm');
    const script = new vm.Script("eval('1+1')");
    script.runInNewContext();
""".trimIndent()).setModule(true).executeVoid()

It's normal to write like this.
But

runtime.getExecutor("""
    const vm = require('node:vm');
    const script = new vm.Script("eval('1+1')");
    script.runInNewContext();
""".trimIndent()).compileV8Module().execute();

Will throw an error:EvalError: Code generation from strings disallowed for this context

So this is a bug?

@LoyDgIk LoyDgIk changed the title Eval function is disabled in vm module The use of eval in vm is restricted Dec 10, 2024
@caoccao
Copy link
Owner

caoccao commented Dec 10, 2024

It seems you are using the engine pool which disables eval() by default. Please check this page out to allow eval().

@LoyDgIk
Copy link
Author

LoyDgIk commented Dec 11, 2024

IMG_20241211_080834
I set allowEval to true, but it doesn't seem to work.

@caoccao
Copy link
Owner

caoccao commented Dec 11, 2024

It's more like a JS trick as follows.

nodeRuntime.allowEval(true);
nodeRuntime.getExecutor("const vm = require(\"node:vm\");\n" +
        "const script = new vm.Script(\"eval('1+1')\");\n" +
        "console.log(script.runInThisContext());\n" +
        "console.log(script.runInNewContext(vm.createContext({eval})));").executeVoid();
// Output
2
2

@LoyDgIk
Copy link
Author

LoyDgIk commented Dec 11, 2024

Have you tried .compileV8Module().execute()? This is when an error would be thrown, whereas .executeVoid() works without issues. I needed to use .compileV8Module() in IV8ModuleResolver.resolve() and that's how I discovered this problem.

@caoccao
Copy link
Owner

caoccao commented Dec 11, 2024

Those API require certain understanding on how V8 works internally. Please let your code.

@LoyDgIk
Copy link
Author

LoyDgIk commented Dec 11, 2024

fun resolve(runtime: V8Runtime, resourceName: String, v8ModuleReferrer: IV8Module): Any? {
    return when {
        resourceName.startsWith("/") || resourceName.startsWith("./") || resourceName.startsWith("../") -> {
            val parentModuleName = v8ModuleReferrer.getResourceName()
            val moduleRelativePath = Paths.get(parentModuleName).parent.resolve(resourceName).normalize()
            val moduleFile = Paths.get(localRelativePath).resolve(moduleRelativePath).toFile()

            if (moduleFile.exists() && moduleFile.isFile) {
                val url = "file://${moduleFile.canonicalPath}"
                val code = readFile(url)
                runtime.getExecutor("import.meta.url=${Json.encodeToString(url)};$code")
                    .setResourceName(moduleRelativePath.toString()).compileV8Module()
            } else {
                null
            }
        }
        resourceName.startsWith("node:") -> nodeResolve.resolve(runtime, resourceName, v8ModuleReferrer)
        else -> {
            val moduleObject = runtime.getNodeModule(resourceName, nodeModuleAnyClazz).getModuleObject()
            moduleObject.set("default", moduleObject)
            runtime.createV8Module(resourceName, moduleObject)
        }
    }
}

This is my code.
So, how do we address the issues with eval?

@caoccao
Copy link
Owner

caoccao commented Dec 11, 2024

It doesn't seem to be a complete reproducible code. Could you leave a repo with the issue?

@LoyDgIk LoyDgIk closed this as not planned Won't fix, can't repro, duplicate, stale Dec 12, 2024
@LoyDgIk
Copy link
Author

LoyDgIk commented Dec 16, 2024

It's more like a JS trick as follows.

nodeRuntime.allowEval(true);
nodeRuntime.getExecutor("const vm = require(\"node:vm\");\n" +
        "const script = new vm.Script(\"eval('1+1')\");\n" +
        "console.log(script.runInThisContext());\n" +
        "console.log(script.runInNewContext(vm.createContext({eval})));").executeVoid();
// Output
2
2

I just realized that this eval is manually injected into the vm context, while in fact, native Node.js does not require such an operation.
native Node.js:
IMG_20241216_113508
javet:
Screenshot_2024-12-16-11-34-02-150_com whl quickjs wrapper sample

@LoyDgIk LoyDgIk reopened this Dec 16, 2024
@LoyDgIk
Copy link
Author

LoyDgIk commented Dec 17, 2024

It's more like a JS trick as follows.

nodeRuntime.allowEval(true);
nodeRuntime.getExecutor("const vm = require(\"node:vm\");\n" +
        "const script = new vm.Script(\"eval('1+1')\");\n" +
        "console.log(script.runInThisContext());\n" +
        "console.log(script.runInNewContext(vm.createContext({eval})));").executeVoid();
// Output
2
2

Can you take a look at it for me?

@FoxNick
Copy link

FoxNick commented Dec 17, 2024

const vm = require('vm');

// 创建一个沙箱上下文
const sandbox = { x: 1, y: 2 };

// 创建一个虚拟机上下文,允许执行 eval
vm.createContext(sandbox);

// 使用 vm.runInContext 执行代码
const code = 'eval("x + y")'; // 使用 eval 来执行动态代码
const result = vm.runInContext(code, sandbox);

console.log(result); // 输出: 3
在这个例子中,通过 vm.createContext 创建了一个沙箱,并在该上下文中执行了一个包含 eval() 的动态代码。正常环境 这个代码被允许执行,因为 eval 在上下文中没有被禁用。但是javet 运行结果是eval不能正确执行, 可能是处于禁用。

Repository owner deleted a comment from FoxNick Dec 18, 2024
@FoxNick
Copy link

FoxNick commented Dec 18, 2024

v8Isolate->SetModifyCodeGenerationFromStringsCallback(nullptr);
不知道这段代码是用来干什么的 注释掉 vm eavl 开启和禁用 问题解决

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants