Compare commits
2 Commits
a6c56ecb22
...
5ed5925a38
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ed5925a38 | ||
|
|
bd2ed7716c |
14
compose.yaml
14
compose.yaml
@@ -26,6 +26,7 @@
|
||||
|
||||
worker:
|
||||
image: liquidcode-tester-worker:latest
|
||||
privileged: true
|
||||
container_name: liquidcode-tester-worker
|
||||
build:
|
||||
context: .
|
||||
@@ -36,16 +37,9 @@
|
||||
- ASPNETCORE_ENVIRONMENT=Development
|
||||
networks:
|
||||
- liquidcode-network
|
||||
# Security hardening for Worker
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
- apparmor=docker-default
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SYS_ADMIN # Required for Isolate namespaces
|
||||
- SETUID # Required for Isolate to change user context
|
||||
- SETGID # Required for Isolate to change group context
|
||||
# Mount cgroup for Isolate sandbox
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:rw
|
||||
# Temporary filesystem for compilation and testing
|
||||
tmpfs:
|
||||
- /tmp:exec,size=4G
|
||||
|
||||
@@ -35,7 +35,7 @@ public class WorkerClientService : IWorkerClientService
|
||||
form.Add(new StringContent(submit.MissionId.ToString()), "MissionId");
|
||||
form.Add(new StringContent(submit.Language), "Language");
|
||||
form.Add(new StringContent(submit.LanguageVersion), "LanguageVersion");
|
||||
form.Add(new StringContent(submit.SourceCode), "SourceCode");
|
||||
form.Add(new StringContent(submit.SourceCode, System.Text.Encoding.UTF8, "text/plain"), "SourceCode");
|
||||
form.Add(new StringContent(submit.CallbackUrl), "CallbackUrl");
|
||||
|
||||
// Add package file
|
||||
|
||||
@@ -82,10 +82,8 @@ RUN apt-get update && \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create unprivileged user for running the worker service
|
||||
RUN useradd -m -u 1001 -s /bin/bash workeruser && \
|
||||
mkdir -p /var/local/lib/isolate && \
|
||||
chmod 755 /var/local/lib/isolate && \
|
||||
chown -R workeruser:workeruser /var/local/lib/isolate
|
||||
RUN mkdir -p /var/local/lib/isolate && \
|
||||
chmod 755 /var/local/lib/isolate
|
||||
|
||||
# Configure isolate directories and control-group root
|
||||
RUN printf "box_root = /var/local/lib/isolate\nlock_root = /run/isolate/locks\ncg_root = /sys/fs/cgroup\nfirst_uid = 60000\nfirst_gid = 60000\nnum_boxes = 1000\n" > /usr/local/etc/isolate.conf && \
|
||||
@@ -96,13 +94,11 @@ RUN printf "box_root = /var/local/lib/isolate\nlock_root = /run/isolate/locks\nc
|
||||
COPY --from=publish /app/publish .
|
||||
|
||||
# Create temp directory for compilation and testing with proper permissions
|
||||
RUN mkdir -p /tmp/testing && \
|
||||
chown -R workeruser:workeruser /tmp/testing && \
|
||||
chown -R workeruser:workeruser /app
|
||||
RUN mkdir -p /tmp/testing
|
||||
|
||||
ENV ASPNETCORE_URLS=http://+:8080
|
||||
|
||||
# Switch to unprivileged user
|
||||
USER workeruser
|
||||
#USER workeruser
|
||||
|
||||
ENTRYPOINT ["dotnet", "LiquidCode.Tester.Worker.dll"]
|
||||
|
||||
@@ -103,7 +103,10 @@ public class CSharpCompilationServiceIsolate : ICompilationService
|
||||
DirectoryBindings = new List<DirectoryBinding>
|
||||
{
|
||||
new DirectoryBinding { HostPath = "/usr/lib", SandboxPath = "/usr/lib", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true }
|
||||
new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/usr/bin", SandboxPath = "/usr/bin", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/usr/share", SandboxPath = "/usr/share", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/etc/mono", SandboxPath = "/etc/mono", ReadOnly = true }
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Diagnostics;
|
||||
using LiquidCode.Tester.Worker.Services.Isolate;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LiquidCode.Tester.Worker.Services;
|
||||
|
||||
@@ -63,6 +64,7 @@ public class CSharpExecutionServiceIsolate : IExecutionService
|
||||
|
||||
// Prepare input/output files inside the sandbox
|
||||
var outputFilePath = Path.Combine(boxDir, "output.txt");
|
||||
var stderrFilePath = Path.Combine(boxDir, "stderr.txt");
|
||||
string? sandboxInputPath = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(inputFilePath) && File.Exists(inputFilePath))
|
||||
@@ -71,20 +73,30 @@ public class CSharpExecutionServiceIsolate : IExecutionService
|
||||
File.Copy(inputFilePath, sandboxInputPath, overwrite: true);
|
||||
}
|
||||
|
||||
// Run in Isolate
|
||||
// Run in Isolate using mono runtime
|
||||
var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions
|
||||
{
|
||||
BoxId = boxId,
|
||||
Executable = $"/box/{executableName}",
|
||||
Executable = "/usr/bin/mono",
|
||||
Arguments = new[] { $"/box/{executableName}" },
|
||||
TimeLimitSeconds = timeLimitMs / 1000.0,
|
||||
WallTimeLimitSeconds = (timeLimitMs / 1000.0) * 2,
|
||||
MemoryLimitKb = memoryLimitMb * 1024,
|
||||
StackLimitKb = 256 * 1024,
|
||||
ProcessLimit = 1, // Single process for C#
|
||||
ProcessLimit = 64, // Mono may create multiple threads/processes
|
||||
EnableNetwork = false,
|
||||
StdinFile = sandboxInputPath,
|
||||
StdoutFile = outputFilePath,
|
||||
WorkingDirectory = "/box"
|
||||
StderrFile = stderrFilePath,
|
||||
WorkingDirectory = "/box",
|
||||
DirectoryBindings = new List<DirectoryBinding>
|
||||
{
|
||||
new DirectoryBinding { HostPath = "/usr/lib", SandboxPath = "/usr/lib", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/usr/share", SandboxPath = "/usr/share", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/etc/mono", SandboxPath = "/etc/mono", ReadOnly = true },
|
||||
new DirectoryBinding { HostPath = "/usr/bin", SandboxPath = "/usr/bin", ReadOnly = true }
|
||||
}
|
||||
});
|
||||
|
||||
stopwatch.Stop();
|
||||
@@ -95,10 +107,19 @@ public class CSharpExecutionServiceIsolate : IExecutionService
|
||||
result.Output = await File.ReadAllTextAsync(outputFilePath);
|
||||
}
|
||||
|
||||
// Read stderr
|
||||
var stderrContent = string.Empty;
|
||||
if (File.Exists(stderrFilePath))
|
||||
{
|
||||
stderrContent = await File.ReadAllTextAsync(stderrFilePath);
|
||||
}
|
||||
|
||||
// Map Isolate result to ExecutionResult
|
||||
result.ExecutionTimeMs = (long)(isolateResult.CpuTimeSeconds * 1000);
|
||||
result.MemoryUsedMb = isolateResult.MemoryUsedKb / 1024;
|
||||
result.ErrorOutput = isolateResult.ErrorOutput;
|
||||
result.ErrorOutput = string.IsNullOrEmpty(stderrContent)
|
||||
? isolateResult.ErrorOutput
|
||||
: $"{stderrContent}\n{isolateResult.ErrorOutput}".Trim();
|
||||
result.ExitCode = isolateResult.ExitCode;
|
||||
|
||||
if (isolateResult.TimeLimitExceeded)
|
||||
|
||||
Reference in New Issue
Block a user