Untrusted code

Safe Haskell

Safe vs. Trustworthy

What if untrusted code needs to do IO?

Example: hypothetical RIO monad

{-# LANGUAGE Trustworthy #-}
module RIO (RIO(), runRIO, RIO.readFile) where

-- Notice that symbol UnsafeRIO is not exported from this module!
newtype RIO a = UnsafeRIO (IO a)
runRIO :: RIO a -> IO a
runRIO (UnsafeRIO io) = io

instance Monad RIO where ...

-- Returns True iff access is allowed to file name
pathOK :: FilePath -> IO Bool
pathOK file = -- policy, e.g., only allow files in /tmp

readFile :: FilePath -> RIO String
readFile file = UnsafeRIO $ do
  ok <- pathOK file
  if ok then Prelude.readFile file else return ""

Exercise: implement RIO Monad instance

newtype RIO a = UnsafeRIO (IO a)
runRIO :: RIO a -> IO a
runRIO (UnsafeRIO io) = io
GHCi, version 7.8.2: http://www.haskell.org/ghc/  :? for help
...
*RIO> writeFile "/tmp/hello" "Hello, world\n"
*RIO> runRIO $ RIO.readFile "/tmp/hello"
"Hello, world\n"
*RIO> runRIO $ RIO.readFile "/etc/passwd"
""
*RIO> 
newtype RIO a = UnsafeRIO { runRIO :: IO a }

Solutions

newtype RIO a = UnsafeRIO (IO a)
instance Monad RIO where
  return = UnsafeRIO . return
  m >>= k = UnsafeRIO $ runRIO m >>= runRIO . k
  fail = UnsafeRIO . fail

Example policies for RIO

Why RIO isn’t enough

What is DIFC?

What is DIFC?

What is DIFC?

Labels are transitive