| Safe Haskell | Trustworthy |
|---|
LIO.Privs
Description
Privileges are objects the possesion of which allows code to bypass
some label protections. An in instance of class PrivDesc describes
a pre-order among labels in which certain unequal labels become
equivalent. When wrapped in a Priv type (whose constructor is
private) a PrivDesc allows code to treat those labels as equivalent.
Put another way, privileges represent the ability to bypass the
protection of certain labels. Specifically, privilege allows you to
behave as if L_1 ` even when that is not the case.
The process of making data labeled canFlowTo` L_2L_1 affect data labeled L_2
when not (L_1 ` is called downgrading.
canFlowTo` L_2)
The basic method of the PrivDesc class is canFlowToP, which
performs a more permissive can-flow-to check by exercising particular
privileges (in literature this relation is a pre-order, commonly
written as ⊑ₚ). Almost all LIO operations have variants
ending ...P that take a privilege argument to act in a more
permissive way.
By convention, all PrivDesc instances are also be instances of
Monoid, allowing privileges to be combined with mappend. The
creation of PrivDesc values is specific to the particular label type
in use; the method used is mintTCB, but the arguments depend on the
particular label type.
- class Label l => PrivDesc l p where
- canFlowToPrivDesc :: p -> l -> l -> Bool
- partDowngradePrivDesc :: p -> l -> l -> l
- canFlowToP :: PrivDesc l p => Priv p -> l -> l -> Bool
- partDowngradeP :: PrivDesc l p => Priv p -> l -> l -> l
- data Priv a
- privDesc :: Priv a -> a
- data NoPrivs
- noPrivs :: Priv NoPrivs
- data Gate d a
- gate :: (d -> a) -> Gate d a
- callGate :: Gate p a -> Priv p -> a
Privilege descriptions
class Label l => PrivDesc l p whereSource
This class defines privileges and the more-permissive relation
(canFlowToP) on labels using privileges. Additionally, it defines
partDowngradeP which is used to downgrage a label up to a limit,
given a set of privilege.
Methods
canFlowToPrivDesc :: p -> l -> l -> BoolSource
The "can-flow-to given privileges" pre-order used to compare
two labels in the presence of privileges. If holds, then privileges canFlowToP p L_1
L_2p are sufficient to downgrade data
from L_1 to L_2. Note that implies
canFlowTo L_1 L_2 for all canFlowToP p L_1 L_2p, but for some labels and
privileges, canFlowToP will hold even where canFlowTo does
not.
Arguments
| :: p | Privileges |
| -> l | Label from which data must flow |
| -> l | Goal label |
| -> l | Result |
Roughly speaking, L_r = partDowngradeP p L L_g computes how
close one can come to downgrading data labeled L to the goal
label L_g, given privileges p. When p == , the
resulting label NoPrivsL_r == L `. If lub` L_gp contains all
possible privileges, then L_r == L_g.
More specifically, L_r is the greatest lower bound of the
set of all labels L_l satisfying:
-
L_g ⊑ L_l, and -
L ⊑ₚ L_l.
Operationally, partDowngradeP captures the minimum change required
to the current label when viewing data labeled L_l. A common
pattern is to use the result of getLabel as L_g (i.e., the
goal is to use privileges p to avoid changing the label at all),
and then compute L_r based on the label of data the code is
about to observe.
Instances
| Label l => PrivDesc l NoPrivs | With lack of privileges, |
| PrivDesc DCLabel Component |
canFlowToP :: PrivDesc l p => Priv p -> l -> l -> BoolSource
TODO(dm): document
partDowngradeP :: PrivDesc l p => Priv p -> l -> l -> lSource
TODO(dm): document
Privileges
Generic privilege type used to denote the lack of privileges.
Gates
LIO provides a basic implementation of gates, useful in providing controlled RPC-like services where the client and service provider are in mutual distrust.
A service provider uses gate to create a gate data type
given a computation of type Gate d ad -> a. Here, d is a privilege
description (type variable for an instance of PrivDesc). Gates are
invoked with callGate, and as such the service provider has the
guarantee that the client (the caller) owns the privileges
corresponding to the privilege description d. In effect, this
allows a client to "prove" to the service provider that they own
certain privileges without entrusting the service with its privileges.
The gate computation can analyze this privilege description before
performing the "actual" computation. The client and server solely
need to trust the implementation of callGate.
A Gate is a lambda abstraction from a privilege description to an
arbitrary type a. Applying the gate is accomplished with callGate
which takes a privilege argument that is converted to a description
before invoking the gate computation.
Arguments
| :: (d -> a) | Gate computation |
| -> Gate d a |
Create a gate given a computation from a privilege description.
Note that because of currying type a may itself be a function
type and thus gates can take arguments in addition to the privilege
descriptoin.
Given a gate and privilege, execute the gate computation. It is
important to note that callGate invokes the gate computation with
the privilege description and NOT the privilege itself.
Note that, in general, code should not provide privileges to
functions other than callGate when wishing to call a gate. This
function is provided by LIO since it can be easily inspected by
both the gate creator and caller to be doing the "right" thing:
provide the privilege description corresponding to the supplied
privilege as "proof" without explicitly passing in the privilege.
Gate example
This example uses LIO.DCLabel to demonstrate the use of gates. The
service provider provides addGate which adds two integers if the
gate is called by a piece of code that owns the "Alice" or "Bob"
principals. Otherwise, it simply returns Nothing.
import LIO
import LIO.DCLabel
import LIO.Privs.TCB (mintTCB)
-- | Add two numbers if the computation is invoked by Alice or Bob.
addGate :: DCGate (Int -> Int -> Maybe Int)
addGate = gate $ \pd a b ->
if pd `elem` (dcPrivDesc `map` ["Alice", "Bob"])
then Just $ a + b
else Nothing
alice, bob, clark :: DCPriv
alice = PrivTCB . dcPrivDesc $ "Alice"
bob = PrivTCB . dcPrivDesc $ "Bob"
clark = PrivTCB . dcPrivDesc $ "Clark"
main = putStrLn . show $
[ callGate addGate alice 1 2 -- Just 3
, callGate addGate bob 3 4 -- Just 7
, callGate addGate clark 5 6 -- Nothing
]