Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Inside the Go playground

Inside the Go playground

A presentation on how the Go playground is built and how it runs safely untrusted Go code.
golang

Francesc Campoy Flores

September 12, 2014
Tweet

More Decks by Francesc Campoy Flores

Other Decks in Programming

Transcript

  1. Agenda What is the Go playground What could go wrong

    What did we do to avoid it An animated ASCII train
  2. Executable slides These slides are driven by the p r

    e s e n t Go tool g o g e t c o d e . g o o g l e . c o m / g o . t o o l s / c m d / p r e s e n t p a c k a g e m a i n i m p o r t " f m t " f u n c m a i n ( ) { f m t . P r i n t l n ( " H e l l o , g o p h e r s ! " ) } Run
  3. Exhausting memory on the stack s t a c k

    o v e r f l o w The runtime catches the error and panics. p a c k a g e m a i n f u n c f o o ( a [ 1 0 0 0 ] b y t e ) { f o o ( a ) } f u n c m a i n ( ) { f o o ( [ 1 0 0 0 ] b y t e { } ) } Run
  4. Too much memory on the heap o u t o

    f m e m o r y Again the runtime catches the error and panics. p a c k a g e m a i n t y p e l i s t s t r u c t { b u f [ 1 0 0 0 0 0 ] b y t e n e x t * l i s t } f u n c m a i n ( ) { v a r l * l i s t f o r { l = & l i s t { n e x t : l } } } Run
  5. Too much CPU time p a c k a g

    e m a i n f u n c m a i n ( ) { f o r { } } Run
  6. Stealing resources by sleeping A sleeping program still consumes resources.

    Easy way of having a Denial of Service attack. p a c k a g e m a i n i m p o r t ( " f m t " " t i m e " ) f u n c m a i n ( ) { f m t . P r i n t l n ( " G o o d n i g h t " ) t i m e . S l e e p ( 8 * t i m e . H o u r ) f m t . P r i n t l n ( " G o o d m o r n i n g " ) } Run
  7. File system access User code shouldn't be able to modify

    the backend's file system. Reading sensitive information Installing backdoors General mayhem f u n c m a i n ( ) { e r r : = o s . R e m o v e A l l ( " / f o o " ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } } Run
  8. Network access f u n c m a i n

    ( ) { r e s , e r r : = h t t p . G e t ( " h t t p : / / a p i . o p e n w e a t h e r m a p . o r g / d a t a / 2 . 5 / w e a t h e r ? q = P o r t l a n d " ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } d e f e r r e s . B o d y . C l o s e ( ) v a r w s t r u c t { W e a t h e r [ ] s t r u c t { D e s c s t r i n g ` j s o n : " d e s c r i p t i o n " ` } ` j s o n : " w e a t h e r " ` } i f e r r : = j s o n . N e w D e c o d e r ( r e s . B o d y ) . D e c o d e ( & w ) ; e r r ! = n i l { l o g . F a t a l ( e r r ) } f m t . P r i n t f ( " N o n e e d t o r u s h o u t s i d e , w e h a v e % v . " , w . W e a t h e r [ 0 ] . D e s c ) } Run
  9. Restricting resource usage with ulimit Default limits are not safe

    enough. u l i m i t could solve this. - d m a x i m u m s i z e o f d a t a s e g m e n t o r h e a p ( i n k b y t e s ) - s m a x i m u m s i z e o f s t a c k s e g m e n t ( i n k b y t e s ) - t m a x i m u m C P U t i m e ( i n s e c o n d s ) - v m a x i m u m s i z e o f v i r t u a l m e m o r y ( i n k b y t e s )
  10. Native Client Originally designed to execute native code in Chrome

    safely. NaCl defines restrictions on the binaries being executed. The code runs in a sandbox isolated from the underlying OS. No file access No network access
  11. Isolating process execution with NaCl We use NaCl to: limit

    CPU time limit memory isolate from the filesystem isolate from the network Process can only write to stdout/stderr.
  12. Limiting user time "No sleeping in the playground." Custom runtime

    with a fake t i m e package. f u n c S l e e p ( d t i m e . D u r a t i o n ) { p a n i c ( " N o s l e e p i n g i n t h e p l a y g r o u n d " ) }
  13. Faking the file system The s y s c a

    l l package is the only link between user code and the OS kernel. The playground runtime has a custom s y s c a l l package. File system operations operate on a fake in-memory file system. f u n c m a i n ( ) { c o n s t f i l e n a m e = " / t m p / f i l e . t x t " e r r : = i o u t i l . W r i t e F i l e ( f i l e n a m e , [ ] b y t e ( " H e l l o , f i l e s y s t e m \ n " ) , 0 6 4 4 ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } b , e r r : = i o u t i l . R e a d F i l e ( f i l e n a m e ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } f m t . P r i n t f ( " % s " , b ) } Run
  14. Faking the network All network operations also use the s

    y s c a l l package. The network stack is also faked in-memory. f u n c m a i n ( ) { l , e r r : = n e t . L i s t e n ( " t c p " , " 1 2 7 . 0 . 0 . 1 : 4 0 0 0 " ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } d e f e r l . C l o s e ( ) g o d i a l ( ) c , e r r : = l . A c c e p t ( ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } d e f e r c . C l o s e ( ) i o . C o p y ( o s . S t d o u t , c ) } Run
  15. Faking the network (continued) f u n c d i

    a l ( ) { c , e r r : = n e t . D i a l ( " t c p " , " 1 2 7 . 0 . 0 . 1 : 4 0 0 0 " ) i f e r r ! = n i l { l o g . F a t a l ( e r r ) } d e f e r c . C l o s e ( ) c . W r i t e ( [ ] b y t e ( " H e l l o , n e t w o r k \ n " ) ) } Run
  16. Sleeping in the playground Go is about concurrency. We need

    to demonstrate concurrency in blog posts and talks. And demonstrating concurrency without t i m e is hard.
  17. Normal behavior There's a special goroutine managing timers T .

    A goroutine G calls t i m e . S l e e p : 1. G adds a timer to the timer heap. 2. G puts itself to sleep. 3. T tells the OS to wake it when the next timer expires and puts itself to sleep. 4. When T is woken up it looks at the timer on the top of the heap, and wakes the corresponding goroutine.
  18. Intermission: deadlocks Many flavors of deadlocks. One common property: all

    goroutines are asleep. p a c k a g e m a i n f u n c m a i n ( ) { c : = m a k e ( c h a n i n t ) < - c } Run
  19. New behavior A goroutine G calls t i m e

    . S l e e p : 1. G adds a timer to the timer heap. 2. G puts itself to sleep. 3. The scheduler detects a deadlock, checks the timer heap for pending timers. 4. The internal clock is advanced to the next timer expiration. 5. The corresponding goroutines are woken up.
  20. Sleeping fast Faking time allows precise sleep durations. p a

    c k a g e m a i n i m p o r t ( " f m t " " t i m e " ) f u n c m a i n ( ) { s t a r t : = t i m e . N o w ( ) f m t . P r i n t l n ( s t a r t ) f o r i : = 0 ; i < 1 0 ; i + + { t i m e . S l e e p ( t i m e . N a n o s e c o n d ) f m t . P r i n t l n ( t i m e . S i n c e ( s t a r t ) ) } } Run
  21. So there's no actual sleep? The playground's w r i

    t e syscall inserts a timestamp before each write. The front end translates that into a series of "events" that the browser can play back. Returns directly { " E r r o r s " : " " , " E v e n t s " : [ { " M e s s a g e " : " G o o d n i g h t \ n " , " D e l a y " : 0 } , { " M e s s a g e " : " G o o d m o r n i n g \ n " , " D e l a y " : 2 8 8 0 0 0 0 0 0 0 0 0 0 0 } ] } f u n c m a i n ( ) { f m t . P r i n t l n ( " G o o d n i g h t " ) t i m e . S l e e p ( 8 * t i m e . H o u r ) f m t . P r i n t l n ( " G o o d m o r n i n g " ) } Run
  22. References These slides: talks.golang.org/2014/playground.slide (http://talks.golang.org/2014/playground.slide) More about the Go tour:

    Inside the Go playground: blog.golang.org/playground (http://blog.golang.org/playground) The Go tour: tour.golang.org (http://tour.golang.org) More about Go on NaCl: Running Go under Native Client: code.google.com/p/go-wiki/wiki/NativeClient (https://code.google.com/p/go-wiki/wiki/NativeClient) Go 1.3 Native Client Support: golang.org/s/go13nacl (http://golang.org/s/go13nacl)