criyle / go-judge

Sandbox Server in REST / gRPC API. Based on Linux container technologies.
MIT License
419 stars 67 forks source link

go-judge使用场景 #56

Closed laotoutou closed 1 year ago

laotoutou commented 1 year ago

除了用于oj评测,比如是否可用于faas运行时?

criyle commented 1 year ago

go-judge 是为 oj 评测专门优化的容器运行环境,用于 faas 运行时会有很多需要考量的部分

  1. 容器默认没有开启网络访问,通常来说 faas 需要访问云服务商提供的 saas 。虽然可以通过参数 -net-share 使用本机网络,这同时允许函数访问任意内网。需要二次开发的 side car 容器来提供受限制的网络(例如不同于本机的vlan)给容器
  2. 容器使用后即销毁,通常来说 faas 需要长时间运行来提供多次服务来减小冷启动时延。go-judge 并没有使用或者提供 freezer cgroup 接口来暂停容器节省空闲时 cpu 资源
  3. go-judge 的运行隔离技术使用的时 Linux 提供的 namespace 和 cgroup 容器技术,如提供给多租户环境使用,可能会受到潜在的容器逃逸漏洞影响
  4. go-judge 并不检查或者分配请求中给定的资源限制(包括 cpu share 和 内存限制),在超售情况下无法保证资源可用性和公平性
JML-CELL commented 10 months ago

请问可以使用PITest进行变异测试吗?我发送JSON后报错 java.net.SocketException: Network is unreachable (connect failed),原因是命令中有12:09:36 PIT >> INFO : Sending 1 test classes to minion 12:09:36 PIT >> INFO : Sent tests to minion这两个Send指令,请问如果想实现这个功能需要开启什么权限?或者还需要配置什么?

criyle commented 10 months ago

没有使用过PITest,网络不可达可能是沙箱默认监听 localhost 不可被外部访问

JML-CELL commented 10 months ago

如何能够开放沙箱的全部端口呢?有命令行设置吗?

JML-CELL commented 10 months ago

如何能够开放沙箱的全部端口呢?有命令行设置吗?

criyle commented 10 months ago

-http-addr=:5050

JML-CELL commented 10 months ago

-http-addr=:5050不是只能开放5050端口吗?我的代码里存在serversocket(0),端口会随机,我想将沙盒的端口都开放可以实现吗?

criyle commented 10 months ago

不明白要达到什么目的,沙箱只会监听给定的端口。都开放具体指什么?

JML-CELL commented 10 months ago

我利用GO-JUDGE的目的不是为了oj判题,而是想进行测试判题如单元测试,变异测试,但是变异测试中需要创建多个Serversocket并且是任意端口(PITest的源码中定义的),相当于在沙箱内需要找到相应的(localhost+port)进行发送文件让它进行变异测试,但是在编辑完命令后遇到发送文件的时候,就报错显示“java.net.Socket.connect(Socket.java:589)\n4:42:42 AM PIT >> FINE : MINION : \tat java.net.Socket.connect(Socket.java:538)”,这个意思就是无法向MINION 发送文件执行。/ws接口可以解决这个问题吗?我没有找到案例,按照Request的格式发送localhost:5050/ws,显示404page not found 。请问能提供帮助嘛,谢谢。假如您有时间,可以直接通过邮箱(1670898356@qq.com)跟我交流吗?我将感激不尽。

criyle commented 10 months ago

go-judge 为了安全,在每个容器中使用的独立的网络命名空间,因此容器内不能连接主机的服务。如果需要连接网络,可以使用 -net-share 命令行参数使容器和主机共享网络。在这种使用条件下,需要信任执行的内容,而不是任意用户上传的可能恶意代码。

JML-CELL commented 10 months ago

我打开了-net-share,但似乎依然无法在代码中使用serversocket

criyle commented 10 months ago

可以尝试使用 127.0.0.1 而不是 localhost

JML-CELL commented 10 months ago

请问您在设计该项目的时候允许在沙箱里运行Serversocket和socket吗?因为我的运行会设计这两个东西,相当于在沙箱里存在“服务器”和“客户端”两个端,需要发送文件进行通信,使用的端口是随机的。请问这个有考虑到吗?可以实现这个功能吗?

criyle commented 10 months ago

可以在同一个容器中使用bash 脚本同时运行两个进程。如果端口是随机的,那么同时需要某种手段让客户端知道端口号来连接。

JML-CELL commented 10 months ago

可以详细说一下具体应该怎么做吗?非常感谢

criyle commented 10 months ago

比方说假设服务端程序和客户端程序分别为 server client, 那么

./server -port=8080 & # 指定一个特定端口后台运行
./client -port=8080 # 连接这个特定端口
JML-CELL commented 10 months ago

这个服务实际在几个jar包中,不是单独独立的,下面是我的JSON格式:{ "cmd": [ { "args": [ "java", "-cp", "/usr/lib/pitest/jar2/org.pitest.pitclipse.runner_2.2.1.v20230330-0839.jar:/usr/lib/pitest/jar2/org.pitest.pitclipse.runner_2.2.1.v20230330-0839.jar:target/classes:/usr/lib/pitest/jar2/pitest.jar:/usr/lib/pitest/jar2/pitest-entry.jar:/usr/lib/pitest/jar2/pitest-command-line.jar:/usr/lib/Pitest/jar2/pitest-html-report.jar:/usr/lib/pitest/jar2/org.pitest.pitclipse.listeners_2.2.1.v20230330-0839.jar:/usr/lib/pitest/jar2/org.pitest.pitclipse.listeners_2.2.1.v20230330-0839.jar/target/classes:/usr/lib/pitest/jar2/junit-4.13.2.jar:/usr/lib/pitest/jar2/hamcrest-core-1.3.jar /w/target/classes /w/target/test-classes", "org.pitest.mutationtest.commandline.MutationCoverageReport", "--reportDir", "/usr/lib/pitest/jar2/report", "--targetClasses", "net.mooctest.*", "--targetTests", "net.mooctest.BPlusTreeTest", "--sourceDirs", "", "--mutators", "DEFAULTS", "--verbose", "true", "ES_NET_SHARE" ], "env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/junit:/bin:/usr/local/jdk1.8.0_181/bin:/bin:/usr/lib/pitest/jar2:/bin", "LANG=en_US.UTF-8", "LC_ALL=en_US.UTF-8", "LANGUAGE=en_US:en", "HOME=/w", "ES_NET_SHARE" ], "files": [ {"content": ""}, {"name": "stdout", "max": 3355449932}, {"name": "stderr", "max": 2335524432} ], "cpuLimit": 10000000000, "clockLimit": 20000000000, "memoryLimit": 536870000000000200, "procLimit": 128, "stackLimit": 268435400, "copyIn": { "/w/target/classes/net/mooctest/BPlusTree.class": { "fileId": "BPP32GQO" }, "/w/target/test-classes/net/mooctest/BPlusTreeTest.class": { "fileId": "52SKKOGM" } }, "ES_NET_SHARE":true, "copyOut": ["stdout", "stderr"], "copyOutCached": ["pitest/SimpleAlgorithms/target/test-classes/BPlusTreeTest.class"]

}

] } 在jar包执行的时候内部会使用serversocket进行通信,也因此报错

criyle commented 10 months ago

ES_NET_SHARE 在 env 里面并不生效,需要在启动沙箱的时候提供。

JML-CELL commented 10 months ago

已经在沙箱里启动了-net-share,并且能看到已经是true了,但是没有作用

---原始邮件--- 发件人: "Yang @.> 发送时间: 2023年12月13日(周三) 上午10:33 收件人: @.>; 抄送: @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

ES_NET_SHARE 在 env 里面并不生效,需要在启动沙箱的时候提供。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

所以你的 Serversocket 是 unix domain socket 吗?

JML-CELL commented 10 months ago

PITest的jar使用的是java.net.serversocket

---原始邮件--- 发件人: "Yang @.> 发送时间: 2023年12月13日(周三) 下午4:24 收件人: @.>; 抄送: @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

所以你的 Serversocket 是 unix domain socket 吗?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

我来描述一下场景,看看对不对

  1. 在主机上有一个 ServerSocket 运行,端口号未知
  2. 在沙箱里面程序使用 new Socket("127.0.0.1", 端口号) 来连接
  3. 沙箱开启了 -net-share 并且输出的日志证实开启有效

如果描述的没有问题,请提供详细的日志作为参考

JML-CELL commented 10 months ago

这里net-share为打开状态 “root@LAPTOP-P85V7M8H:/opt# ./executorserver -net-share 2023-12-14T08:59:05.472Z INFO executorserver/main.go:61 config loaded: &{ContainerInitPath: PreFork:1 TmpFsParam:size=128m,nr_inodes=4k NetShare:true MountConf:mount.yaml SeccompConf:seccomp.yaml Parallelism:16 CgroupPrefix:executor_server ContainerCredStart:0 SrcPrefix:[] Dir: TimeLimitCheckerInterval:100ms ExtraMemoryLimit:16.0 KiB OutputLimit:256.0 MiB CopyOutLimit:256.0 MiB OpenFileLimit:256 Cpuset: EnableCPURate:false CPUCfsPeriod:100ms FileTimeout:0s HTTPAddr:localhost:5050 EnableGRPC:false GRPCAddr:localhost:5051 MonitorAddr:localhost:5052 AuthToken: EnableDebug:false EnableMetrics:false Release:false Silent:false ForceGCTarget:20.0 MiB ForceGCInterval:5s Version:false} 2023-12-14T08:59:05.472Z INFO executorserver/main.go:282 random seed: -7900969498012547074 2023-12-14T08:59:05.472Z INFO env/env_linux.go:59 Created container mount at:Mounts: bind[/bin:bin:ro], bind[/lib:lib:ro], bind[/lib64:lib64:ro], bind[/usr:usr:ro], bind[/etc/ld.so.cache:etc/ld.so.cache:ro], bind[/etc/alternatives:etc/alternatives:ro], bind[/dev/null:dev/null:rw], bind[/dev/urandom:dev/urandom:rw], bind[/dev/random:dev/random:rw], bind[/dev/zero:dev/zero:rw], bind[/dev/full:dev/full:rw], tmpfs[w], tmpfs[tmp], proc[ro] 2023-12-14T08:59:05.472Z INFO env/env_linux.go:97 Creating container builder: hostName=executor_server, domainName=executor_server, workDir=/w 2023-12-14T08:59:05.472Z INFO env/env_linux.go:129 Test created cgroup builder with: cgroup builder(v1): [cpuset, cpuacct, memory, pids] 2023-12-14T08:59:05.473Z INFO executorserver/main.go:290 create 1 prefork containers 2023-12-14T08:59:05.485Z INFO executorserver/main.go:72 Started worker with parallelism=16, workdir=/dev/shm/executorserver4203325841, timeLimitCheckInterval=100ms [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.

[GIN-debug] GET /version --> main.generateHandleVersion.func1 (3 handlers) [GIN-debug] GET /config --> main.generateHandleConfig.func1 (3 handlers) [GIN-debug] POST /run --> github.com/criyle/go-judge/cmd/executorserver/rest_executor.(handle).handleRun-fm (3 handlers) [GIN-debug] GET /file --> github.com/criyle/go-judge/cmd/executorserver/rest_executor.(fileHandle).fileGet-fm (3 handlers) [GIN-debug] POST /file --> github.com/criyle/go-judge/cmd/executorserver/rest_executor.(fileHandle).filePost-fm (3 handlers) [GIN-debug] GET /file/:fid --> github.com/criyle/go-judge/cmd/executorserver/rest_executor.(fileHandle).fileIDGet-fm (3 handlers) [GIN-debug] DELETE /file/:fid --> github.com/criyle/go-judge/cmd/executorserver/rest_executor.(fileHandle).fileIDDelete-fm (3 handlers) [GIN-debug] GET /ws --> github.com/criyle/go-judge/cmd/executorserver/ws_executor.(wsHandle).handleWS-fm (3 handlers) 2023-12-14T08:59:05.486Z ERROR executorserver/main.go:186 Http server listen failed: listen tcp 127.0.0.1:5050: bind: address already in use main.initHTTPServer.func1.1 /home/runner/work/go-judge/go-judge/cmd/executorserver/main.go:186 main.main.func1 /home/runner/work/go-judge/go-judge/cmd/executorserver/main.go:92 2023-12-14T08:59:05.486Z INFO executorserver/main.go:109 Shutting Down... 2023-12-14T08:59:05.486Z INFO executorserver/main.go:155 Worker shutdown 2023-12-14T08:59:05.486Z INFO executorserver/main.go:196 Http server shutdown 2023-12-14T08:59:05.486Z INFO executorserver/main.go:168 FileStore cleaned up 2023-12-14T08:59:05.486Z INFO executorserver/main.go:123 Shutdown Finished container_exit: serve: recvCmd RecvMsg: read unixpacket @->@0000f: EOF”

JML-CELL commented 10 months ago

请问该沙盒底层是使用cgroup实现的吗?我查阅了cgroup资料,发现它并没有对Java中的Serversocket做出什么限制,非常奇怪

criyle commented 10 months ago

之前描述的场景符合现实条件吗?

沙箱是容器技术实现的,包含 linux namespace 和 cgroup 。

JML-CELL commented 10 months ago

是的,场景跟你前面说的近似,相当于在沙箱里同时存在服务端和客户端

---原始邮件--- 发件人: "Yang @.> 发送时间: 2023年12月14日(周四) 晚上7:56 收件人: @.>; 抄送: @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

之前描述的场景符合现实条件吗?

沙箱是容器技术实现的,包含 linux namespace 和 cgroup 。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

我不明白,是同一个 jar 里面有两个部分,服务端和客户端吗?

JML-CELL commented 10 months ago

是的,有一个JAR包存在服务端和客户端两部分,同时里面的服务端也会与其他jar包联系传输数据

---原始邮件--- 发件人: "Yang @.> 发送时间: 2023年12月15日(周五) 下午2:47 收件人: @.>; 抄送: @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

我不明白,是同一个 jar 里面有两个部分,服务端和客户端吗?

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

所以不是很明白为什么会连不上,不在沙箱本地运行能过吗

JML-CELL commented 10 months ago

我在宿主机都可以运行,只有放到沙箱的时候执行到SendData命令的时候就报错,也很困扰

---原始邮件--- 发件人: "Yang @.> 发送时间: 2023年12月15日(周五) 下午3:14 收件人: @.>; 抄送: @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

所以不是很明白为什么会连不上,不在沙箱本地运行能过吗

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

如果能提供一个最小可复现 POC ,那么可以进一步 debug。不然现在一切都只有猜测。

JML-CELL commented 10 months ago

假如您有时间的话,可以到https://pan.quark.cn/s/84a7f03b2222下载镜像(这里已经包含需要的环境和写好的json指令),非常感谢! ------------------ 原始邮件 ------------------ 发件人: "criyle/go-judge" @.>; 发送时间: 2023年12月15日(星期五) 下午4:49 @.>; 抄送: "JIa @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

如果能提供一个最小可复现 POC ,那么可以进一步 debug。不然现在一切都只有猜测。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

没有账号,无法下载。可以选择直接提供 java 源文件内容在 issue 当中。同时注意到请求中 cmd 字段有空字符串 "" ,可能是非必需的。

JML-CELL commented 10 months ago

PITest源码在hcoles/pitest: State of the art mutation testing system for the JVM (github.com)这个网址,或者也可以执行一段小型的模拟,在沙箱执行一小段serversocket模拟, import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;

public class SimpleServer {

    public static void main(String[] args) {         int portNumber = 12345; // 选择一个空闲的端口

        try (ServerSocket serverSocket = new ServerSocket(portNumber)) {             System.out.println("Server is listening on port " + portNumber);

            while (true) {                 Socket clientSocket = serverSocket.accept();                 System.out.println("Accepted connection from " + clientSocket.getInetAddress());

                // 创建一个新的线程来处理客户端连接                 new Thread(() -> handleClient(clientSocket)).start();             }

        } catch (IOException e) {             e.printStackTrace();         }     }

    private static void handleClient(Socket clientSocket) {         try (             PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);             BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))         ) {             String inputLine;             while ((inputLine = in.readLine()) != null) {                 System.out.println("Received from client: " + inputLine);

                // 发送响应给客户端                 out.println("Server: Received your message - " + inputLine);             }         } catch (IOException e) {             e.printStackTrace();         } finally {             try {                 clientSocket.close();             } catch (IOException e) {                 e.printStackTrace();             }         }     } }

------------------ 原始邮件 ------------------ 发件人: "criyle/go-judge" @.>; 发送时间: 2023年12月15日(星期五) 晚上7:24 @.>; 抄送: "JIa @.**@.>; 主题: Re: [criyle/go-judge] go-judge使用场景 (Issue #56)

没有账号,无法下载。可以选择直接提供 java 源文件内容在 issue 当中。同时注意到请求中 cmd 字段有空字符串 "" ,可能是非必需的。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you commented.Message ID: @.***>

criyle commented 10 months ago

可以尝试在 goj.ac 上提交,展示一下错误以及提出应当的输出结果