summaryrefslogtreecommitdiff
path: root/docs/users_guide/safe_haskell.xml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/users_guide/safe_haskell.xml')
-rw-r--r--docs/users_guide/safe_haskell.xml964
1 files changed, 0 insertions, 964 deletions
diff --git a/docs/users_guide/safe_haskell.xml b/docs/users_guide/safe_haskell.xml
deleted file mode 100644
index 02182d3b8e..0000000000
--- a/docs/users_guide/safe_haskell.xml
+++ /dev/null
@@ -1,964 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<sect1 id="safe-haskell">
- <title>Safe Haskell</title>
- <indexterm><primary>safe haskell</primary></indexterm>
-
- <para>
- Safe Haskell is an extension to the Haskell language that is implemented in
- GHC as of version 7.2. It allows for unsafe code to be securely included in a
- trusted code base by restricting the features of GHC Haskell the code is
- allowed to use. Put simply, it makes the types of programs trustable.
- </para>
-
- <para>
- While a primary use case of Safe Haskell is running untrusted code, Safe
- Haskell doesn't provide this directly. Instead, Safe Haskell provides strict
- type safety. Without Safe Haskell, GHC allows many exceptions to the type
- system which can subvert any abstractions. By providing strict type safety,
- Safe Haskell enables developers to build their own library level sandbox
- mechanisms to run untrusted code.
- </para>
-
- <para>
- While Safe Haskell is an extension, it actually runs in the background for
- every compilation with GHC. It does this to track the type violations of
- modules to infer their safety, even when they aren't explicitly using Safe
- Haskell. Please refer to section <xref linkend="safe-inference"/> for more
- details of this.
- </para>
-
- <para>
- The design of Safe Haskell covers the following aspects:
-
- <itemizedlist>
- <listitem>A <link linkend="safe-language">safe language</link> dialect of
- Haskell that provides stricter guarantees about the code. It allows types
- and module boundaries to be trusted.
- </listitem>
- <listitem>A <emphasis>safe import</emphasis> extension that specifies that
- the module being imported must be trusted.
- </listitem>
- <listitem>A definition of <emphasis>trust</emphasis> (or safety) and how it
- operates, along with ways of defining and changing the trust of modules
- and packages.
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- Safe Haskell, however, <emphasis>does not offer</emphasis> compilation
- safety. During compilation time it is possible for arbitrary processes to be
- launched, using for example the <link linkend="pre-processor">custom
- pre-processor</link> flag. This can be manipulated to either compromise a
- users system at compilation time, or to modify the source code just before
- compilation to try to alter Safe Haskell flags. This is discussed further in
- section <xref linkend="safe-compilation"/>.
- </para>
-
- <sect2 id="safe-use-cases">
- <title>Uses of Safe Haskell</title>
- <indexterm><primary>safe haskell uses</primary></indexterm>
-
- <para>
- Safe Haskell has been designed with two use cases in mind:
-
- <itemizedlist>
- <listitem>Enforcing strict type safety at compile time</listitem>
- <listitem>Compiling and executing untrusted code</listitem>
- </itemizedlist>
- </para>
-
- <sect3>
- <title>Strict type-safety (good style)</title>
-
- Haskell offers a powerful type system and separation of pure and
- effectual functions through the <literal>IO</literal> monad. However,
- there are several loop holes in the type system, the most obvious being
- the <literal>unsafePerformIO :: IO a -> a</literal> function. The safe
- language dialect of Safe Haskell disallows the use of such functions.
- This can be useful restriction as it makes Haskell code easier to analyse
- and reason about. It also codifies the existing culture in the Haskell
- community of trying to avoid unsafe functions unless absolutely
- necessary. As such, using the safe language (through the
- <option>-XSafe</option> flag) can be thought of as a way of enforcing
- good style, similar to the function of <option>-Wall</option>.
- </sect3>
-
- <sect3>
- <title>Building secure systems (restricted IO Monads)</title>
- <indexterm><primary>secure haskell</primary></indexterm>
-
- <para>
- Systems such as information flow control security, capability based
- security systems and DSLs for working with encrypted data.. etc can be
- built in the Haskell language as a library. However they require
- guarantees about the properties of Haskell that aren't true in general
- due to the presence of functions like <literal>unsafePerformIO
- </literal>. Safe Haskell gives users enough guarantees about the type
- system to allow them to build such secure systems.
- </para>
-
- <para>
- As an example, lets define an interface for a plugin system where the
- plugin authors are untrusted, possibly malicious third-parties. We do
- this by restricting the plugin interface to pure functions or to a
- restricted <literal>IO</literal> monad that we have defined. The
- restricted <literal>IO</literal> monad will only allow a safe subset of
- <literal>IO</literal> actions to be executed. We define the plugin
- interface so that it requires the plugin module,
- <literal>Danger</literal>, to export a single computation,
- <literal>Danger.runMe</literal>, of type <literal>RIO ()</literal>, where
- <literal>RIO</literal> is a monad defined as follows:
- </para>
-
- <programlisting>
- -- While we use `Safe', the `Trustworthy' pragma would also be
- -- fine. We simply want to ensure that:
- -- 1) The module exports an interface that untrusted code can't
- -- abuse.
- -- 2) Untrusted code can import this module.
- --
- {-# LANGUAGE Safe #-}
-
- module RIO (RIO(), runRIO, rioReadFile, rioWriteFile) where
-
- -- Notice that symbol UnsafeRIO is not exported from this module!
- newtype RIO a = UnsafeRIO { runRIO :: IO a }
-
- instance Monad RIO where
- return = UnsafeRIO . return
- (UnsafeRIO m) >>= k = UnsafeRIO $ m >>= runRIO . k
-
- -- Returns True iff access is allowed to file name
- pathOK :: FilePath -> IO Bool
- pathOK file = {- Implement some policy based on file name -}
-
- rioReadFile :: FilePath -> RIO String
- rioReadFile file = UnsafeRIO $ do
- ok &lt;- pathOK file
- if ok then readFile file else return ""
-
- rioWriteFile :: FilePath -> String -> RIO ()
- rioWriteFile file contents = UnsafeRIO $ do
- ok &lt;- pathOK file
- if ok then writeFile file contents else return ()
- </programlisting>
-
- We then compile the <literal>Danger</literal> plugin using the new Safe
- Haskell <option>-XSafe</option> flag:
-
- <programlisting>
- {-# LANGUAGE Safe #-}
- module Danger ( runMe ) where
-
- runMe :: RIO ()
- runMe = ...
- </programlisting>
-
- <para>
- Before going into the Safe Haskell details, lets point out some of the
- reasons this security mechanism would fail without Safe Haskell:
- </para>
-
- <itemizedlist>
- <listitem>The design attempts to restrict the operations that
- <literal>Danger</literal> can perform by using types, specifically
- the <literal>RIO</literal> type wrapper around <literal>IO</literal>.
- The author of <literal>Danger</literal> can subvert this though by
- simply writing arbitrary <literal>IO</literal> actions and using
- <literal>unsafePerformIO :: IO a -> a</literal> to execute them as
- pure functions.
- </listitem>
- <listitem>The design also relies on <literal>Danger</literal> not being
- able to access the <literal>UnsafeRIO</literal> constructor.
- Unfortunately Template Haskell can be used to subvert module
- boundaries and so could be used to gain access to this constructor.
- </listitem>
- <listitem>There is no way to place restrictions on the modules that
- <literal>Danger</literal> can import. This gives the author of
- <literal>Danger</literal> a very large attack surface, essentially
- any package currently installed on the system. Should any of these
- packages have a vulnerability, then the <literal>Danger</literal>
- module can exploit it.
- </listitem>
- </itemizedlist>
-
- <para>
- Safe Haskell prevents all these attacks. This is done by compiling the
- RIO module with the <option>-XSafe</option> or
- <option>-XTrustworthy</option> flag and compiling
- <literal>Danger</literal> with the <option>-XSafe</option> flag. We
- explain each below.
- </para>
-
- <para>
- The use of <option>-XSafe</option> to compile
- <literal>Danger</literal> restricts the features of Haskell that can be used
- to a <link linkend="safe-language">safe subset</link>. This
- includes disallowing <literal>unsafePerformIO</literal>,
- Template Haskell, pure FFI functions, RULES and restricting the
- operation of Overlapping Instances. The <option>-XSafe</option>
- flag also restricts the modules can be imported by
- <literal>Danger</literal> to only those that are considered trusted.
- Trusted modules are those compiled with <option>-XSafe</option>, where
- GHC provides a mechanical guarantee that the code is safe. Or those
- modules compiled with <option>-XTrustworthy</option>, where the module
- author claims that the module is Safe.
- </para>
-
- <para>
- This is why the RIO module is compiled with <option>-XSafe</option> or
- <option>-XTrustworthy</option>>, to allow the <literal>Danger</literal>
- module to import it. The <option>-XTrustworthy</option> flag doesn't
- place any restrictions on the module like <option>-XSafe</option> does
- (expect to restrict overlapping instances to
- <link linkend="safe-overlapping-instances">safe overlapping
- instances</link>). Instead the module author claims that while code
- may use unsafe features internally, it only exposes an API that can used
- in a safe manner.
- </para>
-
- <para>
- However, the unrestricted use of <option>-XTrustworthy</option> is a
- problem as an arbitrary module can use it to mark themselves as
- trusted, yet <option>-XTrustworthy</option> doesn't offer any
- guarantees about the module, unlike <option>-XSafe</option>.
-
- To control the use of trustworthy modules it is recommended to use the
- <option>-fpackage-trust</option> flag. This flag adds an extra
- requirement to the trust check for trustworthy modules.
-
- It requires that for a trustworthy modules to be considered trusted, and
- allowed to be used in <option>-XSafe</option> compiled code, the client C
- compiling the code must tell GHC that they trust the package the
- trustworthy module resides in.
-
- This is essentially a way of for C to say, while this package contains
- trustworthy modules that can be used by untrusted modules compiled with
- <option>-XSafe</option>, I trust the author(s) of this package and trust
- the modules only expose a safe API. The trust of a package can be
- changed at any time, so if a vulnerability found in a package, C can
- declare that package untrusted so that any future compilation against
- that package would fail. For a more detailed overview of this mechanism
- see <xref linkend="safe-trust"/>.
- </para>
-
- <para>
- In the example, <literal>Danger</literal> can import module
- <literal>RIO</literal> because <literal>RIO</literal> is compiled with
- <option>-XSafe</option>. Thus, <literal>Danger</literal> can make use of
- the <literal>rioReadFile</literal> and <literal>rioWriteFile</literal>
- functions to access permitted file names. The main application then
- imports both <literal>RIO</literal> and <literal>Danger</literal>. To run
- the plugin, it calls <literal>RIO.runRIO Danger.runMe</literal> within
- the <literal>IO</literal> monad. The application is safe in the knowledge
- that the only <literal>IO</literal> to ensue will be to files whose paths
- were approved by the <literal>pathOK</literal> test.
- </para>
- </sect3>
- </sect2>
-
- <sect2 id="safe-language">
- <title>Safe Language</title>
- <indexterm><primary>safe language</primary></indexterm>
-
- The Safe Haskell <emphasis>safe language</emphasis> (enabled by
- <option>-XSafe</option>) guarantees the following properties:
-
- <itemizedlist>
- <listitem><emphasis>Referential transparency</emphasis> &mdash; The types
- can be trusted. Any pure function, is guaranteed to be pure. Evaluating
- them is deterministic and won't cause any side effects. Functions in
- the <literal>IO</literal> monad are still allowed and behave as usual.
- So, for example, the <literal>unsafePerformIO :: IO a -> a</literal>
- function is disallowed in the safe language to enforce this property.
- </listitem>
-
- <listitem><emphasis>Module boundary control</emphasis> &mdash; Only
- symbols that are publicly available through other module export lists
- can be accessed in the safe language. Values using data constructors
- not exported by the defining module, cannot be examined or created. As
- such, if a module M establishes some invariants through careful use of
- its export list, then code written in the safe language that imports M
- is guaranteed to respect those invariants.
- </listitem>
-
- <listitem><emphasis>Semantic consistency</emphasis> &mdash; For any
- module that imports a module written in the safe language, expressions
- that compile both with and without the safe import have the same
- meaning in both cases. That is, importing a module written in the safe
- language cannot change the meaning of existing code that isn't
- dependent on that module. So, for example, there are some restrictions
- placed on the use of <emphasis><link linkend="instance-overlap">
- Overlapping Instances</link></emphasis>, as these can violate this
- property.
- </listitem>
-
- <listitem><emphasis>Strict subset</emphasis> &mdash; The safe language is
- strictly a subset of Haskell as implemented by GHC. Any expression that
- compiles in the safe language has the same meaning as it does when
- compiled in normal Haskell.
- </listitem>
- </itemizedlist>
-
- <para>
- These four properties guarantee that in the safe language you can trust the
- types, can trust that module export lists are respected, and can trust that
- code that successfully compiles has the same meaning as it normally would.
- </para>
-
- <para>
- To achieve these properties, in the safe language dialect we disable
- completely the following features:
- <itemizedlist>
- <listitem><emphasis>TemplateHaskell</emphasis> &mdash; Can be used to
- gain access to constructors and abstract data types that weren't
- exported by a module, subverting module boundaries.
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- Furthermore, we restrict the following features:
- <itemizedlist>
- <listitem><emphasis>ForeignFunctionInterface</emphasis> &mdash; Foreign
- import declarations that import a function with a non-IO type are
- disallowed.
- </listitem>
-
- <listitem><emphasis>RULES</emphasis> &mdash; RULES defined in a module M
- compiled with <option>-XSafe</option> are dropped. RULES defined in
- trustworthy modules that M imports are still valid and will fire as
- usual.
- </listitem>
-
- <listitem><emphasis>OverlappingInstances</emphasis> &mdash; There is no
- restriction on the creation of overlapping instances, but we do
- restrict their use at a particular call site. This is a detailed
- restriction, please refer to
- <link linkend="safe-overlapping-instances">Safe Overlapping Instances
- </link> for details.
- </listitem>
-
- <listitem><emphasis>GeneralisedNewtypeDeriving</emphasis> &mdash; GND is
- not allowed in the safe language. This is due to the ability of it to
- violate module boundaries when module authors forget to put nominal
- role annotations on their types as appropriate. For this reason, the
- <literal>Data.Coerce</literal> module is also considered unsafe. We are
- hoping to find a better solution here in the future.
- </listitem>
-
- <listitem><emphasis>Data.Typeable</emphasis> &mdash; Hand crafted
- instances of the Typeable type class are not allowed in Safe Haskell as
- this can easily be abused to unsafely coerce between types. Derived
- instances (through the <link linkend="deriving-typeable"><option>
- -XDeriveDataTypeable</option></link> extension) are still allowed.
- </listitem>
- </itemizedlist>
- </para>
-
- <sect3 id="safe-overlapping-instances">
- <title>Safe Overlapping Instances</title>
-
- <para>
- Due to the semantic consistency guarantee of Safe Haskell, we must
- restrict the function of overlapping instances. We don't restrict their
- ability to be defined, as this is a global property and not something we
- can determine by looking at a single module. Instead, when a module calls
- a function belonging to a type-class, we check that the instance
- resolution done is considered 'safe'. This check is enforced for modules
- compiled with both <option>-XSafe</option> and
- <option>-XTrustworthy</option>.
- </para>
-
- <para>
- More specifically, consider the following modules:
-
- <programlisting>
- {-# LANGUAGE Safe #-}
- module Class (TC(..)) where
- class TC a where { op :: a -> String }
-
- {-# LANGUAGE Safe #-}
- module Dangerous (TC(..)) where
- import Class
-
- instance
- {-# OVERLAPS #-}
- TC [Int] where { op _ = "[Int]" }
-
- {-# LANGUAGE Safe #-}
- module TCB_Runner where
- import Class
- import Dangerous
-
- instance
- TC [a] where { op _ = "[a]" }
-
- f :: String
- f = op ([1,2,3,4] :: [Int])
- </programlisting>
-
- Both module Class and module Dangerous will compile under
- <option>-XSafe</option> without issue. However, in module TCB_Runner, we
- must check if the call to <literal>op</literal> in function
- <literal>f</literal> is safe.
- </para>
-
- <para>
- What does it mean to be Safe? That importing a module compiled with
- <option>-XSafe</option> shouldn't change the meaning of code that
- compiles fine without importing the module. This is the Safe Haskell
- property known as <emphasis>semantic consistency</emphasis>.
- </para>
-
- <para>
- In our situation, module TCB_Runner compiles fine without importing
- module Dangerous. So when deciding which instance to use for the call to
- <literal>op</literal>, if we determine the instance <literal>TC
- [Int]</literal> from module Dangerous is the most specific, this is
- unsafe. This prevents code written by third-parties we don't trust (which
- is compiled using <option>-XSafe</option> in Safe Haskell) from changing
- the behaviour of our existing code.
- </para>
-
- <para>
- Specifically, we apply the following rule to determine if a type-class
- method call is <emphasis>unsafe</emphasis> when overlapping instances are
- involved:
-
- <itemizedlist>
- <listitem>Most specific instance, <literal>Ix</literal>, defined in an
- `-XSafe` compiled module.
- </listitem>
-
- <listitem><literal>Ix</literal> is an orphan instance or a
- multi-parameter-type-class.
- </listitem>
-
- <listitem>At least one overlapped instance, <literal>Iy</literal>, is both:
- <itemizedlist>
- <listitem>From a different module than <literal>Ix</literal></listitem>
- <listitem><literal>Iy</literal> is not marked
- <option>OVERLAPPABLE</option></listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
-
- This is a slightly involved heuristic, but captures the situation of an
- imported module N changing the behaviour of existing code. For example, if
- the second condition isn't violated, then the module author M must depend
- either on a type-class or type defined in N.
- </para>
-
- <para>
- When an particular type-class method call is considered unsafe due to
- overlapping instances, and the module being compiled is using
- <option>-XSafe</option> or <option>-XTrustworthy</option>, then
- compilation will fail. For <option>-XUnsafe</option>, no restriction is
- applied, and for modules using safe inference, they will be inferred
- unsafe.
- </para>
- </sect3>
-
- </sect2>
-
- <sect2 id="safe-imports">
- <title>Safe Imports</title>
- <indexterm><primary>safe imports</primary></indexterm>
-
- Safe Haskell enables a small extension to the usual import syntax of
- Haskell, adding a <emphasis>safe</emphasis> keyword:
-
- <programlisting>
- impdecl -> import [safe] [qualified] modid [as modid] [impspec]
- </programlisting>
-
- When used, the module being imported with the safe keyword must be a
- trusted module, otherwise a compilation error will occur. The safe import
- extension is enabled by either of the <option>-XSafe</option>,
- <option>-XTrustworthy</option>, or <option>-XUnsafe</option> flags. When
- the <option>-XSafe</option> flag is used, the safe keyword is allowed but
- meaningless, as every import is treated as a safe import.
- </sect2>
-
- <sect2 id="safe-trust">
- <title>Trust and Safe Haskell Modes</title>
- <indexterm><primary>safe haskell trust</primary></indexterm>
- <indexterm><primary>trust</primary></indexterm>
-
- Safe Haskell introduces the following three language flags:
-
- <itemizedlist>
- <listitem><emphasis>-XSafe</emphasis> &mdash; Enables the safe language
- dialect, asking GHC to guarantee trust. The safe language dialect
- requires that all imports be trusted or a compilation error will occur.
- Safe Haskell will also infer this safety type for modules automatically
- when possible. Please refer to section <xref linkend="safe-inference"/>
- for more details of this.
- </listitem>
-
- <listitem><emphasis>-XTrustworthy</emphasis> &mdash; Means that while
- this module may invoke unsafe functions internally, the module's author
- claims that it exports an API that can't be used in an unsafe way. This
- doesn't enable the safe language. It does however restrict the
- resolution of overlapping instances to only allow
- <link linkend="safe-overlapping-instances">safe overlapping
- instances</link>. The trust guarantee is provided by the module
- author, not GHC. An import statement with the safe keyword results in a
- compilation error if the imported module is not trusted. An import
- statement without the keyword behaves as usual and can import any
- module whether trusted or not.
- </listitem>
-
- <listitem><emphasis>-XUnsafe</emphasis> &mdash; Marks the module being
- compiled as unsafe so that modules compiled using
- <option>-XSafe</option> can't import it. You may want to explicitly
- mark a module unsafe when it exports internal constructors that can be
- used to violate invariants.
- </listitem>
- </itemizedlist>
-
- <para>
- While these are flags, they also correspond to Safe Haskell module types
- that a module can have. You can think of using these as declaring an
- explicit contract (or type) that a module must have. If it is invalid, then
- compilation will fail. GHC will also infer the correct type for Safe
- Haskell, please refer to section <xref linkend="safe-inference"/> for more
- details.
- </para>
-
- <para>
- The procedure to check if a module is trusted or not depends on if the
- <option>-fpackage-trust</option> flag is present. The check is similar in
- both cases with the <option>-fpackage-trust</option> flag enabling an extra
- requirement for trustworthy modules to be regarded as trusted.
- </para>
-
- <sect3>
- <title>Trust check (<option>-fpackage-trust</option> disabled)</title>
- <indexterm><primary>trust check</primary></indexterm>
-
- <para>
- A <emphasis>module M in a package P is trusted by a client C</emphasis>
- if and only if:
-
- <itemizedlist>
- <listitem>Both of these hold:
- <itemizedlist>
- <listitem>The module was compiled with <option>-XSafe</option>
- </listitem>
- <listitem>All of M's direct imports are trusted by C</listitem>
- </itemizedlist>
- </listitem>
- <listitem><emphasis>OR</emphasis> all of these hold:
- <itemizedlist>
- <listitem>The module was compiled with
- <option>-XTrustworthy</option></listitem>
- <listitem>All of M's direct <emphasis>safe imports</emphasis>are trusted by
- C</listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- The above definition of trust has an issue. Any module can be compiled
- with <option>-XTrustworthy</option> and it will be trusted. To control
- this, there is an additional definition of package trust (enabled with the
- <option>-fpackage-trust</option> flag). The point of package trust is to
- require that the client C explicitly say which packages are allowed to
- contain trustworthy modules. Trustworthy packages are only trusted if
- they reside in a package trusted by C.
- </para>
- </sect3>
-
- <sect3>
- <title>Trust check (<option>-fpackage-trust</option> enabled)</title>
- <indexterm><primary>trust check</primary></indexterm>
- <indexterm><primary>-fpackage-trust</primary></indexterm>
-
- <para>
- When the <option>-fpackage-trust</option> flag is enabled, whether or not
- a module is trusted depends on if certain packages are trusted. Package
- trust is determined by the client C invoking GHC (i.e. you).
- </para>
-
- <para>
- Specifically, a package <emphasis>P is trusted</emphasis> when one of
- these hold:
- <itemizedlist>
- <listitem>C's package database records that P is trusted (and no
- command-line arguments override this)</listitem>
- <listitem>C's command-line flags say to trust P regardless of what is
- recorded in the package database.</listitem>
- </itemizedlist>
- </para>
-
- <para>
- In either case, C is the only authority on package trust. It is up to the
- client to decide which <link linkend="safe-package-trust">packages they
- trust</link>.
- </para>
-
- <para>
- When the <option>-fpackage-trust</option> flag is used a <emphasis>module M from
- package P is trusted by a client C</emphasis> if and only if:
-
- <itemizedlist>
- <listitem>Both of these hold:
- <itemizedlist>
- <listitem> The module was compiled with <option>-XSafe</option>
- </listitem>
- <listitem> All of M's direct imports are trusted by C</listitem>
- </itemizedlist>
- </listitem>
- <listitem><emphasis>OR</emphasis> all of these hold:
- <itemizedlist>
- <listitem>The module was compiled with
- <option>-XTrustworthy</option></listitem>
- <listitem>All of M's direct safe imports are trusted by C</listitem>
- <listitem>Package P is trusted by C</listitem>
- </itemizedlist>
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- For the first trust definition the trust guarantee is provided by GHC
- through the restrictions imposed by the safe language. For the second
- definition of trust, the guarantee is provided initially by the
- module author. The client C then establishes that they trust the
- module author by indicating they trust the package the module resides
- in. This trust chain is required as GHC provides no guarantee for
- <literal>-XTrustworthy</literal> compiled modules.
- </para>
-
- <para>
- The reason there are two modes of checking trust is that the extra
- requirement enabled by <option>-fpackage-trust</option> causes the design
- of Safe Haskell to be invasive. Packages using Safe Haskell when the flag
- is enabled may or may not compile depending on the state of trusted
- packages on a users machine. This is both fragile, and causes compilation
- failures for everyone, even if they aren't trying to use any of the
- guarantees provided by Safe Haskell. Disabling
- <option>-fpackage-trust</option> by default and turning it into a flag
- makes Safe Haskell an opt-in extension rather than an always on feature.
- </para>
- </sect3>
-
- <sect3 id="safe-trust-example">
- <title>Example</title>
-
- <programlisting>
- Package Wuggle:
- {-# LANGUAGE Safe #-}
- module Buggle where
- import Prelude
- f x = ...blah...
-
- Package P:
- {-# LANGUAGE Trustworthy #-}
- module M where
- import System.IO.Unsafe
- import safe Buggle
- </programlisting>
-
- <para>
- Suppose a client C decides to trust package P and package base. Then does
- C trust module M? Well M is marked <option>-XTrustworthy</option>, so we
- don't restrict the language. However, we still must check M's imports:
- <itemizedlist>
- <listitem>First, M imports System.IO.Unsafe. This is an unsafe module,
- however M was compiled with <option>-XTrustworthy</option>, so P's
- author takes responsibility for that import. C trusts P's author, so
- this import is fine.
- </listitem>
-
- <listitem>
- Second, M safe imports Buggle. For this import P's author takes no
- responsibility for the safety, instead asking GHC to check whether
- Buggle is trusted by C. Is it?
- </listitem>
-
- <listitem>
- Buggle, is compiled with <option>-XSafe</option>, so the code is
- machine-checked to be OK, but again under the assumption that all of
- Buggle's imports are trusted by C. We must recursively check all
- imports!
- </listitem>
-
- <listitem>
- Buggle only imports Prelude, which is compiled with
- <option>-XTrustworthy</option>. Prelude resides in the base package,
- which C trusts, and (we'll assume) all of Prelude's imports are
- trusted. So C trusts Prelude, and so C also trusts Buggle. (While
- Prelude is typically imported implicitly, it still obeys the same
- rules outlined here).
- </listitem>
- </itemizedlist>
- </para>
-
- <para>
- Notice that C didn't need to trust package Wuggle; the machine checking
- is enough. C only needs to trust packages that contain
- <option>-XTrustworthy</option> modules.
- </para>
- </sect3>
-
- <sect3 id="trustworthy-guarantees">
- <title>Trustworthy Requirements</title>
- <indexterm><primary>trustworthy</primary></indexterm>
-
- Module authors using the <option>-XTrustworthy</option> language
- extension for a module M should ensure that M's public API (the symbols
- exposed by its export list) can't be used in an unsafe manner. This mean
- that symbols exported should respect type safety and referential
- transparency.
- </sect3>
-
- <sect3 id="safe-package-trust">
- <title>Package Trust</title>
- <indexterm><primary>package trust</primary></indexterm>
-
- Safe Haskell gives packages a new Boolean property, that of trust.
- Several new options are available at the GHC command-line to specify the
- trust property of packages:
-
- <itemizedlist>
- <listitem><emphasis>-trust P</emphasis> &mdash; Exposes package P if it was
- hidden and considers it a trusted package regardless of the package
- database.</listitem>
- <listitem><emphasis>-distrust P</emphasis> &mdash; Exposes package P if it
- was hidden and considers it an untrusted package regardless of the
- package database.</listitem>
- <listitem><emphasis>-distrust-all-packages</emphasis> &mdash; Considers all
- packages distrusted unless they are explicitly set to be trusted by
- subsequent command-line options.</listitem>
- </itemizedlist>
-
- To set a package's trust property in the package database please refer to
- <xref linkend="packages"/>.
- </sect3>
-
- </sect2>
-
- <sect2 id="safe-inference">
- <title>Safe Haskell Inference</title>
- <indexterm><primary>safe inference</primary></indexterm>
-
- <para>
- In the case where a module is compiled without one of
- <option>-XSafe</option>, <option>-XTrustworthy</option> or
- <option>-XUnsafe</option> being used, GHC will try to figure out itself if
- the module can be considered safe. This safety inference will never mark a
- module as trustworthy, only as either unsafe or as safe. GHC uses a simple
- method to determine this for a module M: If M would compile without error
- under the <option>-XSafe</option> flag, then M is marked as safe.
- Otherwise, it is marked as unsafe.
- </para>
-
- <para>
- When should you use Safe Haskell inference and when should you use an
- explicit <option>-XSafe</option> flag? The later case should be used when
- you have a hard requirement that the module be safe. This is most useful
- for the <xref linkend="safe-use-cases">security use case</xref> of Safe
- Haskell: running untrusted code. Safe inference is meant to be used by
- ordinary Haskell programmers. Users who probably don't care about Safe
- Haskell.
- </para>
-
- <para>
- Haskell library authors have a choice. Most should just use Safe inference.
- Assuming you avoid any unsafe features of the language then your modules
- will be marked safe. Inferred vs. Explicit has the following trade-offs:
- </para>
-
- <itemizedlist>
- <listitem><emphasis>Inferred</emphasis> &mdash; This works well and adds no
- dependencies on the Safe Haskell type of any modules in other packages.
- It does mean that the Safe Haskell type of your own modules could
- change without warning if a dependency changes. One way to deal with
- this is through the use of <xref linkend="safe-flag-summary">Safe
- Haskell warning flags</xref> that will warn if GHC infers a Safe
- Haskell type different from expected.</listitem>
- <listitem><emphasis>Explicit</emphasis> &mdash; This gives your library a
- stable Safe Haskell type that others can depend on. However, it will
- increase the chance of compilation failure when your package
- dependencies change.</listitem>
- </itemizedlist>
- </sect2>
-
- <sect2 id="safe-flag-summary">
- <title>Safe Haskell Flag Summary</title>
- <indexterm><primary>safe haskell flags</primary></indexterm>
-
- In summary, Safe Haskell consists of the following three language flags:
-
- <variablelist>
- <varlistentry>
- <term>-XSafe</term>
- <indexterm><primary>-XSafe</primary></indexterm>
- <listitem>Restricts the module to the safe language. All of the
- module's direct imports must be trusted, but the module itself need
- not reside in a trusted package, because the compiler vouches for its
- trustworthiness. The "safe" keyword is allowed but meaningless in
- import statements, as regardless, every import is required to be
- safe.
- <itemizedlist>
- <listitem><emphasis>Module Trusted</emphasis> &mdash; Yes</listitem>
- <listitem><emphasis>Haskell Language</emphasis> &mdash; Restricted to
- Safe Language</listitem>
- <listitem><emphasis>Imported Modules</emphasis> &mdash; All forced to be
- safe imports, all must be trusted.</listitem>
- </itemizedlist>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>-XTrustworthy</term>
- <indexterm><primary>-XTrustworthy</primary></indexterm>
- <listitem>This establishes that the module is trusted, but the
- guarantee is provided by the module's author. A client of this module
- then specifies that they trust the module author by specifying they
- trust the package containing the module.
- <option>-XTrustworthy</option> doesn't restrict the module to the
- safe language. It does however restrict the resolution of overlapping
- instances to only allow <link linkend="safe-overlapping-instances">
- safe overlapping instances</link>. It also allows the use of the safe
- import keyword.
-
- <itemizedlist>
- <listitem><emphasis>Module Trusted</emphasis> &mdash; Yes.</listitem>
- <listitem><emphasis>Module Trusted
- (<option>-fpackage-trust</option> enabled)</emphasis> &mdash; Yes but
- only if the package the module resides in is also
- trusted.</listitem>
- <listitem><emphasis>Haskell Language</emphasis> &mdash; Unrestricted,
- except only <link linkend="safe-overlapping-instances">safe
- overlapping instances</link> allowed.
- </listitem>
- <listitem><emphasis>Imported Modules</emphasis> &mdash; Under control of
- module author which ones must be trusted.</listitem>
- </itemizedlist>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>-XUnsafe</term>
- <indexterm><primary>-XUnsafe</primary></indexterm>
- <listitem>Mark a module as unsafe so that it can't be imported by code
- compiled with <option>-XSafe</option>. Also enable the Safe Import
- extension so that a module can require a dependency to be trusted.
- <itemizedlist>
- <listitem><emphasis>Module Trusted</emphasis> &mdash; No</listitem>
- <listitem><emphasis>Haskell Language</emphasis> &mdash;
- Unrestricted</listitem>
- <listitem><emphasis>Imported Modules</emphasis> &mdash; Under control of
- module author which ones must be trusted.</listitem>
- </itemizedlist>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- And one general flag:
-
- <variablelist>
- <varlistentry>
- <term>-fpackage-trust</term>
- <indexterm><primary>-fpackage-trust</primary></indexterm>
- <listitem>When enabled, turn on an extra check for a trustworthy module
- M, requiring the package that M resides in be considered trusted, for
- M to be considered trusted.
- </listitem>
- </varlistentry>
- </variablelist>
-
- And three warning flags:
-
- <variablelist>
- <varlistentry>
- <term>-fwarn-unsafe</term>
- <indexterm><primary>-fwarn-unsafe</primary></indexterm>
- <listitem>Issue a warning if the module being compiled is regarded to
- be unsafe. Should be used to check the safety type of modules when
- using safe inference.
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>-fwarn-safe</term>
- <indexterm><primary>-fwarn-safe</primary></indexterm>
- <listitem>Issue a warning if the module being compiled is regarded to
- be safe. Should be used to check the safety type of modules when
- using safe inference.
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>-fwarn-trustworthy-safe</term>
- <indexterm><primary>-fwarn-trustworthy-safe</primary></indexterm>
- <listitem>Issue a warning if the module being compiled is marked as
- <option>-XTrustworthy</option> but it could instead be marked as
- <option>-XSafe</option>, a more informative bound. Can be used to
- detect once a Safe Haskell bound can be improved as dependencies are
- updated.</listitem>
- </varlistentry>
- </variablelist>
- </sect2>
-
- <sect2 id="safe-compilation">
- <title>Safe Compilation</title>
- <indexterm><primary>safe compilation</primary></indexterm>
-
- <para>
- GHC includes a variety of flags that allow arbitrary processes to be run at
- compilation time. One such example is the
- <link linkend="pre-processor">custom pre-processor</link> flag. Another is
- the ability of Template Haskell to execute Haskell code at compilation
- time, including IO actions. Safe Haskell <emphasis>does not address this
- danger</emphasis> (although, Template Haskell is a disallowed feature).
- </para>
-
- <para>
- Due to this, it is suggested that when compiling untrusted source code that
- has had no manual inspection done, the following precautions be taken:
- <itemizedlist>
- <listitem>Compile in a sandbox, such as a chroot or similar container
- technology. Or simply as a user with very reduced system
- access.</listitem>
- <listitem>Compile untrusted code with the <option>-XSafe</option> flag
- being specified on the command line. This will ensure that modifications
- to the source being compiled can't disable the use of the Safe Language
- as the command line flag takes precedence over a source level
- pragma.</listitem>
- <listitem>Ensure that all untrusted code is imported as a
- <link linkend="safe-imports">safe import</link><emphasis> and</emphasis>
- that the <link linkend="safe-package-trust"><option>-fpackage-trust</option></link>
- flag is used with packages from untrusted sources being marked as
- untrusted.</listitem>
- </itemizedlist>
- </para>
-
- <para>
- There is a more detailed discussion of the issues involved in compilation
- safety and some potential solutions on the <ulink
- url="http://ghc.haskell.org/trac/ghc/wiki/SafeHaskell/SafeCompilation">GHC
- Wiki</ulink>.
- </para>
-
- <para>
- Additionally, the use of <link linkend="annotation-pragmas">annotations</link>
- is forbidden, as that would allow bypassing Safe Haskell restrictions.
- See <ulink url="https://ghc.haskell.org/trac/ghc/ticket/10826">ticket #10826</ulink>.
- </para>
-
- </sect2>
-
-</sect1>
-
-<!-- Emacs stuff:
- ;;; Local Variables: ***
- ;;; sgml-parent-document: ("users_guide.xml" "book" "chapter" "sect1") ***
- ;;; ispell-local-dictionary: "british" ***
- ;;; End: ***
- -->