module LMonad.TCB (
module Export
, LMonad (..)
, LMonadT
, runLMonad
, lLift
, getCurrentLabel
, getClearance
, lubCurrentLabel
, canSetLabel
, setLabel
, taintLabel
, setClearance
, raiseClearanceTCB
, lowerLabelTCB
, Labeled
, label
, unlabel
, canUnlabel
, labelOf
, toLabeledTCB
, ToLabel(..)
, swapBase
) where
import Control.Applicative
import Control.Monad
import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Control
import Control.Monad.Trans.State
import Data.Monoid
import Prelude
import LMonad.Label as Export
class Monad m => LMonad m where
lFail :: m a
lAllowLift :: m Bool
data Label l => LState l = LState {
lStateLabel :: !l
, lStateClearance :: !l
}
class ToLabel t l where
toConfidentialityLabel :: t -> l
toIntegrityLabel :: t -> l
data (Label l, Monad m, LMonad m) => LMonadT l m a = LMonadT {
lMonadTState :: (StateT (LState l) m a)
}
instance (Label l, LMonad m) => Monad (LMonadT l m) where
(LMonadT ma) >>= f =
LMonadT $ ma >>= (lMonadTState . f)
return = LMonadT . return
fail _ = LMonadT $ lift lFail
instance (Label l, LMonad m, Functor m) => Functor (LMonadT l m) where
fmap f (LMonadT ma) = LMonadT $ fmap f ma
instance (Label l, LMonad m, Functor m) => Applicative (LMonadT l m) where
pure = return
(<*>) = ap
instance (Label l, LMonad m, MonadIO m) => MonadIO (LMonadT l m) where
liftIO ma = lLift $ liftIO ma
instance (LMonad m, Label l, Functor m, MonadBase IO m) => MonadBase IO (LMonadT l m) where
liftBase = lLift . liftBase
instance (Label l, LMonad m, MonadThrow m) => MonadThrow (LMonadT l m) where
throwM = lLift . throwM
newtype StMT l m a = StMT {unStMT :: StM (StateT (LState l) m) a}
instance (LMonad m, Label l, MonadBaseControl IO m) => MonadBaseControl IO (LMonadT l m) where
type StM (LMonadT l m) a = StMT l m a
liftBaseWith f = LMonadT $ liftBaseWith $ \run -> f $ liftM StMT . run . lMonadTState
restoreM = LMonadT . restoreM . unStMT
instance (LMonad m, Label l, Monoid (m a)) => Monoid (LMonadT l m a) where
mempty = lLift mempty
mappend a b = a >> b
runLMonad :: (Label l, LMonad m) => LMonadT l m a -> m a
runLMonad (LMonadT lm) =
let s = LState bottom bottom in
evalStateT lm s
lLift :: (Label l, LMonad m) => m a -> LMonadT l m a
lLift ma = LMonadT $ do
allow <- lift lAllowLift
if allow then
lift ma
else
lift lFail
getCurrentLabel :: (Label l, LMonad m) => LMonadT l m l
getCurrentLabel = LMonadT $ do
(LState label _) <- get
return label
lubCurrentLabel :: (Label l, LMonad m) => l -> LMonadT l m l
lubCurrentLabel l = do
getCurrentLabel >>= (return . (lub l))
getClearance :: (Label l, LMonad m) => LMonadT l m l
getClearance = LMonadT $ do
(LState _ clearance) <- get
return clearance
canAlloc :: (Label l, LMonad m) => l -> StateT (LState l) m Bool
canAlloc l = do
(LState label clearance) <- get
return $ canFlowTo label l && canFlowTo l clearance
guardAlloc :: (Label l, LMonad m) => l -> StateT (LState l) m ()
guardAlloc l = do
guard <- canAlloc l
unless guard $
lift lFail
canSetLabel :: (Label l, LMonad m) => l -> LMonadT l m Bool
canSetLabel = LMonadT . canAlloc
setLabel :: (Label l, LMonad m) => l -> LMonadT l m ()
setLabel l = do
LMonadT $ guardAlloc l
setLabelTCB l
setLabelTCB :: (Label l, LMonad m) => l -> LMonadT l m ()
setLabelTCB l = LMonadT $ do
(LState _ clearance) <- get
put $ LState l clearance
taintLabel :: (Label l, LMonad m) => l -> LMonadT l m ()
taintLabel l = do
lM' <- taintHelper l
case lM' of
Nothing ->
LMonadT $ lift lFail
Just l' -> do
setLabelTCB l'
setClearance :: (Label l, LMonad m) => l -> LMonadT l m ()
setClearance c = LMonadT $ do
guardAlloc c
(LState label _) <- get
put $ LState label c
raiseClearanceTCB :: (Label l, LMonad m) => l -> LMonadT l m ()
raiseClearanceTCB c = LMonadT $ do
(LState label clearance) <- get
put $ LState label $ lub clearance c
lowerLabelTCB :: (Label l, LMonad m) => l -> LMonadT l m ()
lowerLabelTCB l = LMonadT $ do
(LState label clearance) <- get
put $ LState (glb label l) clearance
data Label l => Labeled l a = Labeled {
labeledLabel :: l
, labeledValue :: a
}
label :: (Label l, LMonad m) => l -> a -> LMonadT l m (Labeled l a)
label l a = LMonadT $ do
guardAlloc l
return $ Labeled l a
taintHelper :: (Label l, LMonad m) => l -> LMonadT l m (Maybe l)
taintHelper l = do
(LState label clearance) <- LMonadT get
let l' = label `lub` l
if l' `canFlowTo` clearance then
return $ Just l'
else
return Nothing
unlabel :: (Label l, LMonad m) => Labeled l a -> LMonadT l m a
unlabel l = do
taintLabel $ labelOf l
return $ labeledValue l
canUnlabel :: (Label l, LMonad m) => Labeled l a -> LMonadT l m Bool
canUnlabel l = do
fmap (maybe False $ const True) $ taintHelper $ labelOf l
labelOf :: Label l => Labeled l a -> l
labelOf = labeledLabel
toLabeledTCB :: (Label l, LMonad m) => l -> LMonadT l m a -> LMonadT l m (Labeled l a)
toLabeledTCB l ma = do
oldLabel <- getCurrentLabel
oldClearance <- getClearance
raiseClearanceTCB l
a <- ma
la <- label l a
lowerLabelTCB oldLabel
setClearance oldClearance
return la
swapBase :: (Label l, LMonad m, LMonad n) => (m (a,LState l) -> n (b,LState l)) -> LMonadT l m a -> LMonadT l n b
swapBase f (LMonadT m) = LMonadT $ do
prev <- get
( res, new) <- lift $ f $ (runStateT m) prev
put new
return res