diff options
Diffstat (limited to 'docs/users_guide/safe_haskell.xml')
-rw-r--r-- | docs/users_guide/safe_haskell.xml | 964 |
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 <- pathOK file - if ok then readFile file else return "" - - rioWriteFile :: FilePath -> String -> RIO () - rioWriteFile file contents = UnsafeRIO $ do - ok <- 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> — 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> — 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> — 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> — 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> — 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> — Foreign - import declarations that import a function with a non-IO type are - disallowed. - </listitem> - - <listitem><emphasis>RULES</emphasis> — 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> — 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> — 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> — 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> — 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> — 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> — 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> — Exposes package P if it was - hidden and considers it a trusted package regardless of the package - database.</listitem> - <listitem><emphasis>-distrust P</emphasis> — 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> — 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> — 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> — 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> — Yes</listitem> - <listitem><emphasis>Haskell Language</emphasis> — Restricted to - Safe Language</listitem> - <listitem><emphasis>Imported Modules</emphasis> — 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> — Yes.</listitem> - <listitem><emphasis>Module Trusted - (<option>-fpackage-trust</option> enabled)</emphasis> — Yes but - only if the package the module resides in is also - trusted.</listitem> - <listitem><emphasis>Haskell Language</emphasis> — Unrestricted, - except only <link linkend="safe-overlapping-instances">safe - overlapping instances</link> allowed. - </listitem> - <listitem><emphasis>Imported Modules</emphasis> — 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> — No</listitem> - <listitem><emphasis>Haskell Language</emphasis> — - Unrestricted</listitem> - <listitem><emphasis>Imported Modules</emphasis> — 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: *** - --> |