with Deferrable constraints in Haskell through the tale of a - - PowerPoint PPT Presentation

with deferrable constraints in haskell
SMART_READER_LITE
LIVE PREVIEW

with Deferrable constraints in Haskell through the tale of a - - PowerPoint PPT Presentation

Gradually typed DSLs with Deferrable constraints in Haskell through the tale of a Haskell information flow control library Pablo Buiras, Alejandro Russo, Dimitrios Vytiniotis Information flow control 101 Non- interference:


slide-1
SLIDE 1

Gradually typed DSLs with Deferrable constraints in Haskell

Pablo Buiras, Alejandro Russo, Dimitrios Vytiniotis

… through the tale of a Haskell information flow control library

slide-2
SLIDE 2

Information flow control 101

  • Non-interference: “sensitive” input does not flow to “public” output
  • Formal model:

a lattice of security labels, security labelled data, and observational equivalence w.r.t. a label

  • Can be enforced statically (e.g. types, static analyses) or dynamically

data Label = L | H ℓ ⊑ H = True L ⊑ L = True H ⊑ L = False

slide-3
SLIDE 3

LIO: Dynamic IFC for Haskell [Stefan et al.]

Just a state monad carrying “current label”

  • 1. Observing (unlabelling) sensitive data

increases current label

  • 2. Cannot output data below current label

data LIO a instance Monad LIO

  • - data guarded by label

data Labeled a

slide-4
SLIDE 4

LIO: Dynamic IFC for Haskell [Stefan et al.]

Just a state monad carrying “current label”

  • 1. Observing (unlabelling) sensitive data

increases current label

  • 2. Cannot output data below current label

data LIO a instance Monad LIO

  • - data guarded by label

data Labeled a

lconcat :: Labeled String -> Labeled String -> LIO String lconcat lstr1 lstr2 = do -- Initial current label ℓcur str1 <- unlabel lstr1 -- ℓcur’ = ℓcur ⊔ (labelOf lstr1) str2 <- unlabel lstr2 -- ℓcur’’ = ℓcur’ ⊔ (labelOf lstr2) return (str1 ++ str2) -- Final current label ℓcur’’

slide-5
SLIDE 5

Quite a number of dynamic checks/taints …

Question: Is there a statically checked variant of LIO?

slide-6
SLIDE 6

Quite a number of dynamic checks/taints …

Question: Is there a statically checked variant of LIO?

type class Flows l1 l2 instance Flows L L instance Flows L H instance Flows H H type family Join l1 l2 where ...

  • - singleton term-level labels

data SLabel (l::Label) where L :: SLabel L H :: SLabel H data Labeled (l::Label) a

IDEA 1 Use labels at the type level

slide-7
SLIDE 7

Quite a number of dynamic checks/taints …

Question: Is there a statically checked variant of LIO?

type class Flows l1 l2 instance Flows L L instance Flows L H instance Flows H H type family Join l1 l2 where ...

  • - singleton term-level labels

data SLabel (l::Label) where L :: SLabel L H :: SLabel H data Labeled (l::Label) a

IDEA 1 Use labels at the type level

data SLIO lin lout a return :: a -> SLIO l l a (>>=) :: SLIO l1 l2 a

  • > (a -> SLIO l2 l3 b)
  • > SLIO l1 l3 b

IDEA 2 Use a “Hoare state monad”

slide-8
SLIDE 8

Quite a number of dynamic checks/taints …

Question: Is there a statically checked variant of LIO?

type class Flows l1 l2 instance Flows L L instance Flows L H instance Flows H H type family Join l1 l2 where ...

  • - singleton term-level labels

data SLabel (l::Label) where L :: SLabel L H :: SLabel H data Labeled (l::Label) a

IDEA 1 Use labels at the type level

data SLIO lin lout a return :: a -> SLIO l l a (>>=) :: SLIO l1 l2 a

  • > (a -> SLIO l2 l3 b)
  • > SLIO l1 l3 b

IDEA 2 Use a “Hoare state monad” Label before action Label after action

slide-9
SLIDE 9

From LIO to SLIO, mechanically

unlabel :: Labeled a -> LIO a

  • - (1) never fails;
  • - (2) taints LIO label with argument label

unlabel :: Labeled la a -> SLIO l (Join l la) a

Label before action Label after action

slide-10
SLIDE 10

From LIO to SLIO, mechanically

label :: Flows l la => SLabel la -> SLIO l l (Labeled la a)

Current label can flow to argument label

label :: Label -> a -> LIO (Labeled a)

  • - (1) succeeds only if current label ⊑ argument label;
  • - (2) returns labelled data
slide-11
SLIDE 11

From LIO to SLIO; tackling the “label creep”

toLabeled :: SLIO ℓi ℓo a -> SLIO ℓi ℓi (Labeled ℓo a) toLabeled :: Label -> LIO a -> LIO (Labeled a)

  • - toLabeled ℓ m
  • - 1) Check that ℓcur ⊑ ℓ
  • - 2) Execute action m starting from ℓcur; new label is ℓcur’
  • - 3) Check that ℓcur’ ⊑ ℓ
  • - 4) If so, pack the result with label ℓ, final label is ℓcur

* A simpler version of

slide-12
SLIDE 12

Success!

slide-13
SLIDE 13

Success!

?

slide-14
SLIDE 14

Static types can get complex

  • - Send a string to a remote server who may leak something

report :: Flows l L => String -> SLIO l l () lReport ls1 ls2 = do v1 <- unlabel ls1 v2 <- unlabel ls2 let res = v1 ++ v2 report res return res

slide-15
SLIDE 15

Static types can get complex

  • - Send a string to a remote server who may leak something

report :: Flows l L => String -> SLIO l l () lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

lReport ls1 ls2 = do v1 <- unlabel ls1 v2 <- unlabel ls2 let res = v1 ++ v2 report res return res

slide-16
SLIDE 16

Static types can get complex

  • - Send a string to a remote server who may leak something

report :: Flows l L => String -> SLIO l l () lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

lReport ls1 ls2 = do v1 <- unlabel ls1 v2 <- unlabel ls2 let res = v1 ++ v2 report res return res

A bit verbose but (depending who you are) may be ok

slide-17
SLIDE 17

And its tedious to interact with dynamic data

lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

readRemote :: URI -> SLIO li li (∃l. Labeled l String) readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” toLabeled (lReport lv1 lv2)

slide-18
SLIDE 18

And its tedious to interact with dynamic data

lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

readRemote :: URI -> SLIO li li (∃l. Labeled l String) readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” toLabeled (lReport lv1 lv2)

Labeled l1 String

slide-19
SLIDE 19

And its tedious to interact with dynamic data

lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

readRemote :: URI -> SLIO li li (∃l. Labeled l String) readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” toLabeled (lReport lv1 lv2)

Labeled l1 String Labeled l2 String

slide-20
SLIDE 20

And its tedious to interact with dynamic data

lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

readRemote :: URI -> SLIO li li (∃l. Labeled l String) readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” toLabeled (lReport lv1 lv2)

Labeled l1 String Labeled l2 String

Can you spot the 2 type errors in readReport?

slide-21
SLIDE 21

What’s wrong with this code?

lReport :: Flows (Join (Join ℓi ℓ1) ℓ2) L => Labeled ℓ1 String

  • > Labeled ℓ2 String
  • > SLIO ℓi (Join (Join ℓi ℓ1) ℓ2) String

readRemote :: URI -> SLIO li li (∃l. Labeled l String) readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” toLabeled (lReport lv1 lv2)

Labeled l1 String Labeled l2 String

(1) Existentials escape in return type (2) Existentials escape in constraint

slide-22
SLIDE 22

Existential escape in types: easy solution

readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” val <- toLabeled (lReport lv1 lv2) return (Exists val)

Labeled l1 String Labeled l2 String

(1) Existentials escape in return type (2) Existentials escape in constraint

Flows (Join (Join li l1) l2) L

slide-23
SLIDE 23

So, back to dynamic LIO?

Not quite!

slide-24
SLIDE 24

What if we could just … defer a constraint?

readReport = do (Exists lv1) <- readRemote “host1” (Exists lv2) <- readRemote “host2” val <- defer (toLabeled (lReport lv1 lv2)) return (Exists val)

Labeled l1 String Labeled l2 String

(1) Existentials escape in return type (2) Existentials escape in constraint

Flows (Join (Join li l1) l2) L

slide-25
SLIDE 25

Gradually typed LIO in Haskell

slide-26
SLIDE 26

How to defer a constraint to runtime?

deferC :: (c => a) -> a

Give me any function that requires constraint c to produce result a, and I will give you back a

Seems seriously implausible! 

slide-27
SLIDE 27

Key idea: A type class of Deferrable constraints

class Deferrable (c :: Constraint) where deferC :: Proxy c -> (c => a) -> a

Common Haskell-ism to account for the lack of explicit type applications

slide-28
SLIDE 28

Easy to give Deferrable instances!

class Deferrable (c :: Constraint) where deferC :: Proxy c -> (c => a) -> a

  • - class providing a singleton

class CLabel l where lab :: Proxy l -> SLabel l instance (Clabel l1, Clabel l2) => Deferrable (Flows l1 l2) where deferC p m = case (lab p1, lab p2) of (L,L) -> m (L,H) -> m (H,H) -> m (H,L) -> error "IFC violation!" where p1 = ⊥ :: Proxy l1; p2 = ⊥ :: Proxy l2 instance (Deferrable c1, Deferrable c2) => Deferrable (c1,c2)

slide-29
SLIDE 29

Easy to give Deferrable instances!

class Deferrable (c :: Constraint) where deferC :: Proxy c -> (c => a) -> a

  • - class providing a singleton

class CLabel l where lab :: Proxy l -> SLabel l instance (Clabel l1, Clabel l2) => Deferrable (Flows l1 l2) where deferC p m = case (lab p1, lab p2) of (L,L) -> m (L,H) -> m (H,H) -> m (H,L) -> error "IFC violation!" where p1 = ⊥ :: Proxy l1; p2 = ⊥ :: Proxy l2 instance (Deferrable c1, Deferrable c2) => Deferrable (c1,c2)

GADT pattern matching refines types to cases where we do have instances

slide-30
SLIDE 30

That’s all the essential ingredients

data SLIO (c :: Constraint) (li :: Expr Label) (lo :: Expr Label) labelOf :: Labeled ℓ a -> SLabel (E ℓ) getLabel :: HLIO () ℓi ℓi (SLabel (E ℓi )) unlabel :: Labeled ℓ a -> HLIO () ℓi (LJoin ℓi ℓ) a label :: SLabel ℓ -> a

  • > HLIO (FlowsE ℓi (LVal ℓ)) ℓi ℓi (Labeled (LVal ℓ) a)

toLabeled :: HLIO c ℓi ℓo a -> HLIO c ℓi ℓi (Labeled ℓo a)

defer :: Deferrable c ⇒ HLIO c ℓi ℓo a -> HLIO () ℓi ℓo a simplify :: c ⇒ HLIO c ℓi ℓo a → HLIO () ℓi ℓo a

Read ICFP paper for other technical details

Expressing constraint as datatype index: (a) Better control over simplification (b) Eliminates need for proxy annotations Distinguishing between label expressions and label values

slide-31
SLIDE 31

Demo and thanks!