PyParis 2017 / Camisole : A secure online sandbox to grade student - Antoine Pietri

Pôle Systematic Paris-Region
Pôle Systematic Paris-RegionPôle Systematic Paris-Region
Camisole
A secure online sandbox to grade students
Context: Prologin
● French national programming contest
for students under 20
● Online qualification with algorithmic
exercises
● Thousands of applications every year
● C, C++, C#, Python, Haskell, OCaml,
Java, PHP, …
https://prologin.org
Problem: secure untrusted code evaluation
(We are lazy and we want to grade our students without looking at their code.)
Aimed at: teachers, programming contests, learning websites,
Design goals:
● Simple enough to be used by everyone (teachers, developers, tinkerers…)
● Fast and precise (overhead matters in programming contests)
● Secure enough to be used in online websites (or malicious students)
● Abstract the languages in a modular way
HTTP/JSON interface
$ curl camisole/run -d '{"lang": "python", "source": "print(42)"}'
{
"success": true,
"tests": [
{
"exitcode": 0,
"meta": { ... },
"name": "test000",
"stderr": "",
"stdout": "42n"
}
]
}
Limits and quotas
{
"lang": "ocaml",
"source": "print_string "Hello, world!n"",
"compile": {
"wall-time": 10
},
"execute": {
"time": 2,
"wall-time": 5,
"processes": 1,
"mem": 100000
}
}
● User time
● Wall time
● Memory
● Stack size
● Number of processes/threads
● Size of files created
● Filesystem blocks
● Filesystem inodes
● … possibly more?
Test suite
Statement: “Write a program that outputs twice its input.”
{
"lang": "python",
"source": "print(int(input()) * 2)",
"tests": [{"name": "test_h2g2", "stdin": "42"},
{"name": "test_?", "stdin": "404"},
{"name": "test_leet", "stdin": "1337"},
{"name": "test_666", "stdin": "27972"}]
}
{
"success": true,
"tests": [
{
"exitcode": 0,
"meta": { ... },
"name": "test_h2g2",
"stderr": "",
"stdout": "84n"
},
{
"exitcode": 0,
"meta": { ... },
"name": "test_notfound",
"stderr": "",
"stdout": "808n"
},
{
"exitcode": 0,
"meta": { ... },
"name": "test_leet",
"stderr": "",
"stdout": "2674n"
},
{
"exitcode": 0,
"meta": { ... },
"name": "test_666",
"stderr": "",
"stdout": "55944n"
}
]
}
Metadata
{
"success": true,
"tests": [
{
"exitcode": 0,
"meta": {
"cg-mem": 2408,
"csw-forced": 9,
"csw-voluntary": 2,
"exitcode": 0,
"exitsig": null,
"killed": false,
"max-rss": 6628,
"message": null,
"status": "OK",
"time": 0.009,
"time-wall": 0.028
},
"name": "test000",
"stderr": "",
"stdout": "42n"
}
]
}
● Time
● Wall time
● Memory of the cgroup
● Context switches
● Exit code
● Signal received
● Killed or exited successfully
● Max resident set size
● … possibly more?
Front-end integration: programming contest
Front-end integration: online course
*
(* not actually using camisole, but could… :-))
Architecture
User application
Camisole
Isolation backend
HTTP/JSON API
Virtual machine
Sandbox
Untrusted program
Solutions considered that don’t really work:
● ptrace
○ Overhead to monitor the system calls
○ Multiprocessing doesn’t work
○ Not multiplatform
○ Lot of things to handle
○ Runtimes can do weird things
● Docker
○ Overhead because overkill
○ Not precise enough
Isolation backend
Isolation backend
Backends :
● “Big brother” (chroot + setrlimit + memory watchdog + outside firewall)
○ Previous in-house solution
○ Isolation is very sloppy
● Isolate (https://github.com/ioi/isolate)
○ Resources limitation using cgroups
○ Isolation with namespaces
○ Lightweight FS isolation (chroot + mount --bind)
● Nsjail? (http://nsjail.com/)
○ Could be implemented as an alternate backend
○ You know how every time you do something, Google comes and does it 10x better?
Language module system
Python 3.6 __init_subclass__ in action!
from camisole.models import Lang, Program
class Python(Lang, name='Python'):
source_ext = '.py'
interpreter = Program('python3')
reference_source = r'print(42)'
Load arbitrary language modules with:
$ export CAMISOLEPATH=~/mylangs
(Simple, except for Java.)
import re
import subprocess
from pathlib import Path
from camisole.models import Lang, Program
RE_WRONG_FILENAME_ERROR = re.compile(r...,')
PSVMAIN_SIGNATURE = 'public static void main('
PSVMAIN_DESCRIPTOR = 'descriptor: ([Ljava/lang/String;)V'
class Java(Lang):
source_ext = '.java'
compiled_ext = '.class'
compiler = Program('javac', env={'LANG': 'C'},
version_opt='-version')
interpreter = Program('java', version_opt='-version')
# /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/jvm.cfg links to
# /etc/java-8-openjdk/amd64/jvm.cfg
allowed_dirs = ['/etc/java-8-openjdk']
# ensure we can parse the javac(1) stderr
extra_binaries = {'disassembler': Program('javap',
version_opt='-version')}
reference_source = r'''
class SomeClass {
static int fortytwo() {
return 42;
}
static class Subclass {
// nested psvmain! wow!
public static void main(String args[]) {
System.out.println(SomeClass.fortytwo());
}
}
}
'''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# use an illegal class name so that javac(1) will spit out the actual
# class named used in the source
self.class_name = '1337'
# we give priority to the public class, if any, so keep a flag if we
# found such a public class
self.found_public = False
try:
self.heapsize = self.opts['execute'].pop('mem')
except KeyError:
self.heapsize = None
def compile_opt_out(self, output):
# javac has no output directive, file name is class name
return []
async def compile(self):
# try to compile with default class name (Main)
retcode, info, binary = await super().compile()
if retcode != 0:
# error: public class name is not '1337' -- obviously, it's
illegal,
# so find what it actually is
match = RE_WRONG_FILENAME_ERROR.search(info['stderr'])
if match:
self.found_public = True
self.class_name = match.group(1)
# retry with new name
retcode, info, binary = await super().compile()
return (retcode, info, binary)
def source_filename(self):
return self.class_name + self.source_ext
def execute_filename(self):
# return eg. Main.class
return self.class_name + self.compiled_ext
def execute_command(self, output):
cmd = [self.interpreter.cmd]
# Use the memory limit as a maximum heap size
if self.heapsize is not None:
cmd.append(f'-Xmx{self.heapsize}k')
# foo/Bar.class is run with $ java -cp foo Bar
cmd += ['-cp',
str(Path(self.filter_box_prefix(output)).parent),
self.class_name]
return cmd
def find_class_having_main(self, classes):
for file in classes:
# run javap(1) with type signatures
try:
stdout = subprocess.check_output(
[self.extra_binaries['disassembler'].cmd, '-s',
str(file)],
stderr=subprocess.DEVNULL,
env=self.compiler.env)
except subprocess.SubprocessError:
continue
# iterate on lines to find p s v main() signature and
then
# its descriptor on the line below; we don't rely on
the type
# from the signature, because it could be String[], String...
or
# some other syntax I'm not even aware of
lines = iter(stdout.decode().split('n'))
for line in lines:
if line.lstrip().startswith(PSVMAIN_SIGNATURE):
if next(lines).lstrip() ==
PSVMAIN_DESCRIPTOR:
return file.stem
def read_compiled(self, path, isolator):
# in case of multiple or nested classes, multiple .class
files are
# generated by javac
classes = list(isolator.path.glob('*.class'))
files = [(file.name, file.open('rb').read()) for file in
classes]
if not self.found_public:
# the main() may be anywhere, so run javap(1) on all
.class
new_class_name = self.find_class_having_main(classes)
if new_class_name:
self.class_name = new_class_name
return files
def write_binary(self, path, binary):
# see read_compiled(), we need to write back all .class
files
# but give only the main class name (execute_filename())
to java(1)
for file, data in binary:
with (path / file).open('wb') as c:
c.write(data)
return path / self.execute_filename()
Low-level API
When simple single-file evaluation doesn’t suit your needs:
opts = {'time': 5, 'mem': 5000}
isolator = Isolator(opts, allowed_dirs=['/home'])
async with isolator:
await isolator.run(command, env=env, data=input())
return (isolator.stdout, isolator.stderr)
Deployment
We autobuild an OVA (VirtualBox export) using packer.io:
https://camisole.prologin.org/ova/camisole-latest.ova
Importing it in VirtualBox and running the VM just works™ and gives you an HTTP
server with all the built-in languages (Ada, C, Brainfuck, C#, C++, F#, Haskell, Java,
Javascript, Lua, OCaml, Pascal, Perl, PHP, Python, Ruby, Rust, Scheme, VisualBasic).
Great for non-tech savvy people!
Conclusion
● Elegant API for a hard problem: good abstraction!
● Linux isolation is awesome
● Python 3.5 and 3.6 features are awesome (f-strings, __init_subclass__, async…)
Will our simplicity-centered design will make the project gain traction? :-)
Full documentation: https://camisole.prologin.org
Contribute! https://github.com/prologin/camisole
Contact: #prologin @ irc.freenode.net
antoine.pietri@prologin.org alexandre.macabies@prologin.org
1 of 17

Recommended

Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ... by
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...
Øredev 2011 - JVM JIT for Dummies (What the JVM Does With Your Bytecode When ...Charles Nutter
8.5K views107 slides
Building High Performance Android Applications in Java and C++ by
Building High Performance Android Applications in Java and C++Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++Kenneth Geisshirt
2.1K views27 slides
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D... by
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...
O CPAN tem as ferramentas que você precisa para fazer TDD em Perl, o Coding D...Rodolfo Carvalho
468 views35 slides
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV) by
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)
2013.02.02 지앤선 테크니컬 세미나 - Xcode를 활용한 디버깅 팁(OSXDEV)JiandSon
1.5K views66 slides
ooc - OSDC 2010 - Amos Wenger by
ooc - OSDC 2010 - Amos Wengerooc - OSDC 2010 - Amos Wenger
ooc - OSDC 2010 - Amos WengerAmos Wenger
579 views34 slides
Google Dart by
Google DartGoogle Dart
Google DartEberhard Wolff
5.2K views40 slides

More Related Content

What's hot

Building a java tracer by
Building a java tracerBuilding a java tracer
Building a java tracerrahulrevo
645 views9 slides
Fast as C: How to Write Really Terrible Java by
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible JavaCharles Nutter
10.6K views132 slides
Mastering Java Bytecode With ASM - 33rd degree, 2012 by
Mastering Java Bytecode With ASM - 33rd degree, 2012Mastering Java Bytecode With ASM - 33rd degree, 2012
Mastering Java Bytecode With ASM - 33rd degree, 2012Anton Arhipov
8K views70 slides
AST Transformations at JFokus by
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
945 views101 slides
Inside the JVM - Follow the white rabbit! by
Inside the JVM - Follow the white rabbit!Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!Sylvain Wallez
1.5K views59 slides
Runtime by
RuntimeRuntime
RuntimeJorge Ortiz
1.4K views55 slides

What's hot(20)

Building a java tracer by rahulrevo
Building a java tracerBuilding a java tracer
Building a java tracer
rahulrevo645 views
Fast as C: How to Write Really Terrible Java by Charles Nutter
Fast as C: How to Write Really Terrible JavaFast as C: How to Write Really Terrible Java
Fast as C: How to Write Really Terrible Java
Charles Nutter10.6K views
Mastering Java Bytecode With ASM - 33rd degree, 2012 by Anton Arhipov
Mastering Java Bytecode With ASM - 33rd degree, 2012Mastering Java Bytecode With ASM - 33rd degree, 2012
Mastering Java Bytecode With ASM - 33rd degree, 2012
Anton Arhipov8K views
AST Transformations at JFokus by HamletDRC
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
HamletDRC945 views
Inside the JVM - Follow the white rabbit! by Sylvain Wallez
Inside the JVM - Follow the white rabbit!Inside the JVM - Follow the white rabbit!
Inside the JVM - Follow the white rabbit!
Sylvain Wallez1.5K views
JRuby and Invokedynamic - Japan JUG 2015 by Charles Nutter
JRuby and Invokedynamic - Japan JUG 2015JRuby and Invokedynamic - Japan JUG 2015
JRuby and Invokedynamic - Japan JUG 2015
Charles Nutter1.6K views
Dart London hackathon by chrisbuckett
Dart  London hackathonDart  London hackathon
Dart London hackathon
chrisbuckett790 views
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge by Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Guillaume Laforge3.8K views
Java Bytecode For Discriminating Developers - GeeCON 2011 by Anton Arhipov
Java Bytecode For Discriminating Developers - GeeCON 2011Java Bytecode For Discriminating Developers - GeeCON 2011
Java Bytecode For Discriminating Developers - GeeCON 2011
Anton Arhipov2.5K views
Introduction to Dart by Ramesh Nair
Introduction to DartIntroduction to Dart
Introduction to Dart
Ramesh Nair2.5K views
Inside the JVM - Follow the white rabbit! / Breizh JUG by Sylvain Wallez
Inside the JVM - Follow the white rabbit! / Breizh JUGInside the JVM - Follow the white rabbit! / Breizh JUG
Inside the JVM - Follow the white rabbit! / Breizh JUG
Sylvain Wallez912 views
Native code in Android applications by Dmitry Matyukhin
Native code in Android applicationsNative code in Android applications
Native code in Android applications
Dmitry Matyukhin4.2K views
Everything you wanted to know about Stack Traces and Heap Dumps by Andrei Pangin
Everything you wanted to know about Stack Traces and Heap DumpsEverything you wanted to know about Stack Traces and Heap Dumps
Everything you wanted to know about Stack Traces and Heap Dumps
Andrei Pangin2.6K views
Java Basics by Sunil OS
Java BasicsJava Basics
Java Basics
Sunil OS1.5M views
Bytecode manipulation with Javassist and ASM by ashleypuls
Bytecode manipulation with Javassist and ASMBytecode manipulation with Javassist and ASM
Bytecode manipulation with Javassist and ASM
ashleypuls7K views
Rust tutorial from Boston Meetup 2015-07-22 by nikomatsakis
Rust tutorial from Boston Meetup 2015-07-22Rust tutorial from Boston Meetup 2015-07-22
Rust tutorial from Boston Meetup 2015-07-22
nikomatsakis1.1K views
Lift off with Groovy 2 at JavaOne 2013 by Guillaume Laforge
Lift off with Groovy 2 at JavaOne 2013Lift off with Groovy 2 at JavaOne 2013
Lift off with Groovy 2 at JavaOne 2013
Guillaume Laforge3.8K views

Similar to PyParis 2017 / Camisole : A secure online sandbox to grade student - Antoine Pietri

2007 09 10 Fzi Training Groovy Grails V Ws by
2007 09 10 Fzi Training Groovy Grails V Ws2007 09 10 Fzi Training Groovy Grails V Ws
2007 09 10 Fzi Training Groovy Grails V Wsloffenauer
1.3K views58 slides
Python utan-stodhjul-motorsag by
Python utan-stodhjul-motorsagPython utan-stodhjul-motorsag
Python utan-stodhjul-motorsagniklal
527 views50 slides
Deep Learning for Computer Vision: Software Frameworks (UPC 2016) by
Deep Learning for Computer Vision: Software Frameworks (UPC 2016)Deep Learning for Computer Vision: Software Frameworks (UPC 2016)
Deep Learning for Computer Vision: Software Frameworks (UPC 2016)Universitat Politècnica de Catalunya
1.7K views19 slides
Presentation of Python, Django, DockerStack by
Presentation of Python, Django, DockerStackPresentation of Python, Django, DockerStack
Presentation of Python, Django, DockerStackDavid Sanchez
827 views24 slides
Atlassian Groovy Plugins by
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy PluginsPaul King
2.3K views27 slides
Adv kvr -satya by
Adv  kvr -satyaAdv  kvr -satya
Adv kvr -satyaJyothsna Sree
50 views142 slides

Similar to PyParis 2017 / Camisole : A secure online sandbox to grade student - Antoine Pietri(20)

2007 09 10 Fzi Training Groovy Grails V Ws by loffenauer
2007 09 10 Fzi Training Groovy Grails V Ws2007 09 10 Fzi Training Groovy Grails V Ws
2007 09 10 Fzi Training Groovy Grails V Ws
loffenauer1.3K views
Python utan-stodhjul-motorsag by niklal
Python utan-stodhjul-motorsagPython utan-stodhjul-motorsag
Python utan-stodhjul-motorsag
niklal527 views
Presentation of Python, Django, DockerStack by David Sanchez
Presentation of Python, Django, DockerStackPresentation of Python, Django, DockerStack
Presentation of Python, Django, DockerStack
David Sanchez827 views
Atlassian Groovy Plugins by Paul King
Atlassian Groovy PluginsAtlassian Groovy Plugins
Atlassian Groovy Plugins
Paul King2.3K views
Advance java kvr -satya by Satya Johnny
Advance java  kvr -satyaAdvance java  kvr -satya
Advance java kvr -satya
Satya Johnny435 views
Introduction to clojure by Abbas Raza
Introduction to clojureIntroduction to clojure
Introduction to clojure
Abbas Raza1.4K views
Node.js Patterns for Discerning Developers by cacois
Node.js Patterns for Discerning DevelopersNode.js Patterns for Discerning Developers
Node.js Patterns for Discerning Developers
cacois34.8K views
How Secure Are Docker Containers? by Ben Hall
How Secure Are Docker Containers?How Secure Are Docker Containers?
How Secure Are Docker Containers?
Ben Hall376 views
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018 by Codemotion
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Codemotion81 views
Cocoa for Web Developers by georgebrock
Cocoa for Web DevelopersCocoa for Web Developers
Cocoa for Web Developers
georgebrock1K views
Kotlin, smarter development for the jvm by Arnaud Giuliani
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
Arnaud Giuliani898 views
Java basic part 2 : Datatypes Keywords Features Components Security Exceptions by Soumen Santra
Java basic part 2 : Datatypes Keywords Features Components Security Exceptions Java basic part 2 : Datatypes Keywords Features Components Security Exceptions
Java basic part 2 : Datatypes Keywords Features Components Security Exceptions
Soumen Santra87 views

More from Pôle Systematic Paris-Region

OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na... by
OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...
OSIS19_IoT :Transparent remote connectivity to short-range IoT devices, by Na...Pôle Systematic Paris-Region
686 views39 slides
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ... by
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...
OSIS19_Cloud : SAFC: Scheduling and Allocation Framework for Containers in a ...Pôle Systematic Paris-Region
293 views24 slides
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ... by
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...
OSIS19_Cloud : Qu’apporte l’observabilité à la gestion de configuration? par ...Pôle Systematic Paris-Region
349 views38 slides
OSIS19_Cloud : Performance and power management in virtualized data centers, ... by
OSIS19_Cloud : Performance and power management in virtualized data centers, ...OSIS19_Cloud : Performance and power management in virtualized data centers, ...
OSIS19_Cloud : Performance and power management in virtualized data centers, ...Pôle Systematic Paris-Region
288 views27 slides
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ... by
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...
OSIS19_Cloud : Des objets dans le cloud, et qui y restent -- L'expérience du ...Pôle Systematic Paris-Region
271 views30 slides
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt... by
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...
OSIS19_Cloud : Attribution automatique de ressources pour micro-services, Alt...Pôle Systematic Paris-Region
229 views9 slides

More from Pôle Systematic Paris-Region(20)

Recently uploaded

Ransomware is Knocking your Door_Final.pdf by
Ransomware is Knocking your Door_Final.pdfRansomware is Knocking your Door_Final.pdf
Ransomware is Knocking your Door_Final.pdfSecurity Bootcamp
96 views46 slides
Qualifying SaaS, IaaS.pptx by
Qualifying SaaS, IaaS.pptxQualifying SaaS, IaaS.pptx
Qualifying SaaS, IaaS.pptxSachin Bhandari
1K views8 slides
"Surviving highload with Node.js", Andrii Shumada by
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada Fwdays
56 views29 slides
Business Analyst Series 2023 - Week 4 Session 7 by
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7DianaGray10
139 views31 slides
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...Bernd Ruecker
54 views69 slides
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue by
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlueElevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlueShapeBlue
222 views7 slides

Recently uploaded(20)

"Surviving highload with Node.js", Andrii Shumada by Fwdays
"Surviving highload with Node.js", Andrii Shumada "Surviving highload with Node.js", Andrii Shumada
"Surviving highload with Node.js", Andrii Shumada
Fwdays56 views
Business Analyst Series 2023 - Week 4 Session 7 by DianaGray10
Business Analyst Series 2023 -  Week 4 Session 7Business Analyst Series 2023 -  Week 4 Session 7
Business Analyst Series 2023 - Week 4 Session 7
DianaGray10139 views
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas... by Bernd Ruecker
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
iSAQB Software Architecture Gathering 2023: How Process Orchestration Increas...
Bernd Ruecker54 views
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue by ShapeBlue
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlueElevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue
Elevating Privacy and Security in CloudStack - Boris Stoyanov - ShapeBlue
ShapeBlue222 views
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue by ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
2FA and OAuth2 in CloudStack - Andrija Panić - ShapeBlue
ShapeBlue147 views
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue by ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlueCloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
CloudStack Managed User Data and Demo - Harikrishna Patnala - ShapeBlue
ShapeBlue135 views
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R... by ShapeBlue
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...
Setting Up Your First CloudStack Environment with Beginners Challenges - MD R...
ShapeBlue173 views
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool by ShapeBlue
Extending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPoolExtending KVM Host HA for Non-NFS Storage -  Alex Ivanov - StorPool
Extending KVM Host HA for Non-NFS Storage - Alex Ivanov - StorPool
ShapeBlue123 views
State of the Union - Rohit Yadav - Apache CloudStack by ShapeBlue
State of the Union - Rohit Yadav - Apache CloudStackState of the Union - Rohit Yadav - Apache CloudStack
State of the Union - Rohit Yadav - Apache CloudStack
ShapeBlue297 views
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N... by James Anderson
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
GDG Cloud Southlake 28 Brad Taylor and Shawn Augenstein Old Problems in the N...
James Anderson160 views
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ... by ShapeBlue
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...
Backroll, News and Demo - Pierre Charton, Matthias Dhellin, Ousmane Diarra - ...
ShapeBlue186 views
Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P... by ShapeBlue
Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P...Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P...
Developments to CloudStack’s SDN ecosystem: Integration with VMWare NSX 4 - P...
ShapeBlue194 views
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And... by ShapeBlue
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...
Enabling DPU Hardware Accelerators in XCP-ng Cloud Platform Environment - And...
ShapeBlue106 views
Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O... by ShapeBlue
Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O...Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O...
Declarative Kubernetes Cluster Deployment with Cloudstack and Cluster API - O...
ShapeBlue132 views
NTGapps NTG LowCode Platform by Mustafa Kuğu
NTGapps NTG LowCode Platform NTGapps NTG LowCode Platform
NTGapps NTG LowCode Platform
Mustafa Kuğu423 views

PyParis 2017 / Camisole : A secure online sandbox to grade student - Antoine Pietri

  • 1. Camisole A secure online sandbox to grade students
  • 2. Context: Prologin ● French national programming contest for students under 20 ● Online qualification with algorithmic exercises ● Thousands of applications every year ● C, C++, C#, Python, Haskell, OCaml, Java, PHP, … https://prologin.org
  • 3. Problem: secure untrusted code evaluation (We are lazy and we want to grade our students without looking at their code.) Aimed at: teachers, programming contests, learning websites, Design goals: ● Simple enough to be used by everyone (teachers, developers, tinkerers…) ● Fast and precise (overhead matters in programming contests) ● Secure enough to be used in online websites (or malicious students) ● Abstract the languages in a modular way
  • 4. HTTP/JSON interface $ curl camisole/run -d '{"lang": "python", "source": "print(42)"}' { "success": true, "tests": [ { "exitcode": 0, "meta": { ... }, "name": "test000", "stderr": "", "stdout": "42n" } ] }
  • 5. Limits and quotas { "lang": "ocaml", "source": "print_string "Hello, world!n"", "compile": { "wall-time": 10 }, "execute": { "time": 2, "wall-time": 5, "processes": 1, "mem": 100000 } } ● User time ● Wall time ● Memory ● Stack size ● Number of processes/threads ● Size of files created ● Filesystem blocks ● Filesystem inodes ● … possibly more?
  • 6. Test suite Statement: “Write a program that outputs twice its input.” { "lang": "python", "source": "print(int(input()) * 2)", "tests": [{"name": "test_h2g2", "stdin": "42"}, {"name": "test_?", "stdin": "404"}, {"name": "test_leet", "stdin": "1337"}, {"name": "test_666", "stdin": "27972"}] } { "success": true, "tests": [ { "exitcode": 0, "meta": { ... }, "name": "test_h2g2", "stderr": "", "stdout": "84n" }, { "exitcode": 0, "meta": { ... }, "name": "test_notfound", "stderr": "", "stdout": "808n" }, { "exitcode": 0, "meta": { ... }, "name": "test_leet", "stderr": "", "stdout": "2674n" }, { "exitcode": 0, "meta": { ... }, "name": "test_666", "stderr": "", "stdout": "55944n" } ] }
  • 7. Metadata { "success": true, "tests": [ { "exitcode": 0, "meta": { "cg-mem": 2408, "csw-forced": 9, "csw-voluntary": 2, "exitcode": 0, "exitsig": null, "killed": false, "max-rss": 6628, "message": null, "status": "OK", "time": 0.009, "time-wall": 0.028 }, "name": "test000", "stderr": "", "stdout": "42n" } ] } ● Time ● Wall time ● Memory of the cgroup ● Context switches ● Exit code ● Signal received ● Killed or exited successfully ● Max resident set size ● … possibly more?
  • 9. Front-end integration: online course * (* not actually using camisole, but could… :-))
  • 10. Architecture User application Camisole Isolation backend HTTP/JSON API Virtual machine Sandbox Untrusted program
  • 11. Solutions considered that don’t really work: ● ptrace ○ Overhead to monitor the system calls ○ Multiprocessing doesn’t work ○ Not multiplatform ○ Lot of things to handle ○ Runtimes can do weird things ● Docker ○ Overhead because overkill ○ Not precise enough Isolation backend
  • 12. Isolation backend Backends : ● “Big brother” (chroot + setrlimit + memory watchdog + outside firewall) ○ Previous in-house solution ○ Isolation is very sloppy ● Isolate (https://github.com/ioi/isolate) ○ Resources limitation using cgroups ○ Isolation with namespaces ○ Lightweight FS isolation (chroot + mount --bind) ● Nsjail? (http://nsjail.com/) ○ Could be implemented as an alternate backend ○ You know how every time you do something, Google comes and does it 10x better?
  • 13. Language module system Python 3.6 __init_subclass__ in action! from camisole.models import Lang, Program class Python(Lang, name='Python'): source_ext = '.py' interpreter = Program('python3') reference_source = r'print(42)' Load arbitrary language modules with: $ export CAMISOLEPATH=~/mylangs
  • 14. (Simple, except for Java.) import re import subprocess from pathlib import Path from camisole.models import Lang, Program RE_WRONG_FILENAME_ERROR = re.compile(r...,') PSVMAIN_SIGNATURE = 'public static void main(' PSVMAIN_DESCRIPTOR = 'descriptor: ([Ljava/lang/String;)V' class Java(Lang): source_ext = '.java' compiled_ext = '.class' compiler = Program('javac', env={'LANG': 'C'}, version_opt='-version') interpreter = Program('java', version_opt='-version') # /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/jvm.cfg links to # /etc/java-8-openjdk/amd64/jvm.cfg allowed_dirs = ['/etc/java-8-openjdk'] # ensure we can parse the javac(1) stderr extra_binaries = {'disassembler': Program('javap', version_opt='-version')} reference_source = r''' class SomeClass { static int fortytwo() { return 42; } static class Subclass { // nested psvmain! wow! public static void main(String args[]) { System.out.println(SomeClass.fortytwo()); } } } ''' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # use an illegal class name so that javac(1) will spit out the actual # class named used in the source self.class_name = '1337' # we give priority to the public class, if any, so keep a flag if we # found such a public class self.found_public = False try: self.heapsize = self.opts['execute'].pop('mem') except KeyError: self.heapsize = None def compile_opt_out(self, output): # javac has no output directive, file name is class name return [] async def compile(self): # try to compile with default class name (Main) retcode, info, binary = await super().compile() if retcode != 0: # error: public class name is not '1337' -- obviously, it's illegal, # so find what it actually is match = RE_WRONG_FILENAME_ERROR.search(info['stderr']) if match: self.found_public = True self.class_name = match.group(1) # retry with new name retcode, info, binary = await super().compile() return (retcode, info, binary) def source_filename(self): return self.class_name + self.source_ext def execute_filename(self): # return eg. Main.class return self.class_name + self.compiled_ext def execute_command(self, output): cmd = [self.interpreter.cmd] # Use the memory limit as a maximum heap size if self.heapsize is not None: cmd.append(f'-Xmx{self.heapsize}k') # foo/Bar.class is run with $ java -cp foo Bar cmd += ['-cp', str(Path(self.filter_box_prefix(output)).parent), self.class_name] return cmd def find_class_having_main(self, classes): for file in classes: # run javap(1) with type signatures try: stdout = subprocess.check_output( [self.extra_binaries['disassembler'].cmd, '-s', str(file)], stderr=subprocess.DEVNULL, env=self.compiler.env) except subprocess.SubprocessError: continue # iterate on lines to find p s v main() signature and then # its descriptor on the line below; we don't rely on the type # from the signature, because it could be String[], String... or # some other syntax I'm not even aware of lines = iter(stdout.decode().split('n')) for line in lines: if line.lstrip().startswith(PSVMAIN_SIGNATURE): if next(lines).lstrip() == PSVMAIN_DESCRIPTOR: return file.stem def read_compiled(self, path, isolator): # in case of multiple or nested classes, multiple .class files are # generated by javac classes = list(isolator.path.glob('*.class')) files = [(file.name, file.open('rb').read()) for file in classes] if not self.found_public: # the main() may be anywhere, so run javap(1) on all .class new_class_name = self.find_class_having_main(classes) if new_class_name: self.class_name = new_class_name return files def write_binary(self, path, binary): # see read_compiled(), we need to write back all .class files # but give only the main class name (execute_filename()) to java(1) for file, data in binary: with (path / file).open('wb') as c: c.write(data) return path / self.execute_filename()
  • 15. Low-level API When simple single-file evaluation doesn’t suit your needs: opts = {'time': 5, 'mem': 5000} isolator = Isolator(opts, allowed_dirs=['/home']) async with isolator: await isolator.run(command, env=env, data=input()) return (isolator.stdout, isolator.stderr)
  • 16. Deployment We autobuild an OVA (VirtualBox export) using packer.io: https://camisole.prologin.org/ova/camisole-latest.ova Importing it in VirtualBox and running the VM just works™ and gives you an HTTP server with all the built-in languages (Ada, C, Brainfuck, C#, C++, F#, Haskell, Java, Javascript, Lua, OCaml, Pascal, Perl, PHP, Python, Ruby, Rust, Scheme, VisualBasic). Great for non-tech savvy people!
  • 17. Conclusion ● Elegant API for a hard problem: good abstraction! ● Linux isolation is awesome ● Python 3.5 and 3.6 features are awesome (f-strings, __init_subclass__, async…) Will our simplicity-centered design will make the project gain traction? :-) Full documentation: https://camisole.prologin.org Contribute! https://github.com/prologin/camisole Contact: #prologin @ irc.freenode.net antoine.pietri@prologin.org alexandre.macabies@prologin.org