mueval 0.9.1 → 0.9.1.1
raw patch · 6 files changed
+107/−89 lines, 6 files
Files
- Mueval/Interpreter.hs +3/−3
- Mueval/Parallel.hs +7/−5
- README +0/−71
- README.md +87/−0
- mueval.cabal +9/−9
- tests.sh +1/−1
Mueval/Interpreter.hs view
@@ -2,7 +2,7 @@ -- TODO: suggest the convenience functions be put into Hint proper? module Mueval.Interpreter where -import Control.Monad (guard,mplus,unless,when)+import Control.Monad (forM_,guard,mplus,unless,when) import Control.Monad.Trans (MonadIO) import Control.Monad.Writer (Any(..),runWriterT,tell) import Data.Char (isDigit)@@ -44,12 +44,12 @@ trustedPackages = trustPkgs, modules = m } = do let lexts = (guard exts >> glasgowExtensions) ++ map readExt nexts- -- Explicitly adding ImplicitPrelude because of + -- Explicitly adding ImplicitPrelude because of -- http://darcsden.com/jcpetruzza/hint/issue/1 unless (null lexts) $ set [languageExtensions := (UnknownExtension "ImplicitPrelude" : lexts)] when trust $ do unsafeSetGhcOption "-fpackage-trust"- flip mapM_ (trustPkgs >>= words) $ \pkg ->+ forM_ (trustPkgs >>= words) $ \pkg -> unsafeSetGhcOption ("-trust " ++ pkg) reset -- Make sure nothing is available
Mueval/Parallel.hs view
@@ -1,10 +1,11 @@ module Mueval.Parallel where -import Control.Concurrent (forkIO, killThread, myThreadId, threadDelay, throwTo, ThreadId)-import System.Posix.Signals (sigXCPU, installHandler, Handler(CatchOnce))-import Control.Exception.Extensible as E (ErrorCall(..),SomeException,catch)+import Control.Concurrent (forkIO, killThread, myThreadId, threadDelay, throwTo, ThreadId) import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar, MVar)+import Control.Exception.Extensible as E (ErrorCall(..),SomeException,catch)+import Control.Monad (void) import System.IO (hSetBuffering, stdout, BufferMode(NoBuffering))+import System.Posix.Signals (sigXCPU, installHandler, Handler(CatchOnce)) import Mueval.Interpreter import Mueval.ArgsParse@@ -29,9 +30,10 @@ _ <- f opts mvar takeMVar mvar -- block until ErrorCall, or forkedMain succeeds --- | Using MVars, block on forkedMain' until it finishes.+-- | Using MVars, block on 'forkedMain' until it finishes. forkedMain :: Options -> IO ()-forkedMain opts = block forkedMain' opts >> return ()+forkedMain opts = void (block forkedMain' opts)+ -- | Set a 'watchDog' on this thread, and then continue on with whatever. forkedMain' :: Options -> MVar String -> IO ThreadId
− README
@@ -1,71 +0,0 @@-WHAT:-Mueval grew out of my discontent with Lambdabot: it's really neat to be able to run expressions like this:--07:53 < ivanm> > filter (\ x -> isLetter x || x == '\t') "asdf$#$ dfs"-07:55 < lambdabot> "asdfdfs"--But Lambdabot is crufty and very difficult to install or run. IMO, we need a replacement or rewrite, but one of the things that make this difficult is that Lambdabot uses hs-plugins to get that sort of evaluation functionality, and hs-plugins is half the problem. We want some sort of standalone executable which provides that functionality. Now, 'ghc -e' is obviously unsuited because there is no sandboxing, so what I've done is basically marry the GHC API (as rendered less sharp-edged by Hint) with a bunch of resource limits and sandboxing (as largely stolen from Lambdabot).--EXAMPLES:-The end result is an adorable little program, which you can use like this:-- bash-3.2$ mueval --expression '1*100+1'- Expression type: (Num t) => t- result: "101"-- bash-3.2$ mueval --expression "filter (\`notElem\` ['A'..'Z']) \"abcXsdzWEE\""- Expression type: [Char]- result: "\"abcsdz\""--Note that mueval will avoid all the attacks I've been able to test on it:-- bash-3.2$ mueval --expression 'let x = x in x'- Expression type: t- result: "mueval: Time limit exceeded-- bash-3.2$ mueval --expression "let foo = readFile \"/etc/passwd\" >>= print in foo"- Expression type: IO ()- result: "<IO ()>"-- bash-3.2$ mueval --module System.IO.Unsafe --expression "let foo = unsafePerformIO readFile \"/etc/passwd\" in foo"- mueval: Unknown or untrusted module supplied! Aborting.--LOADING FROM FILE:-Like Lambdabot, Mueval is capable of loading a file and its definitions. This is useful to get a kind of persistence. Suppose you have a file "L.hs", with a function 'bar = (+1)' in it; then 'mueval --loadfile=L.hs --expression="bar 1"' will evaluate to, as one would expect, '2'.--It's worth noting that definitions and module imports in the loaded *ARE NOT* fully checked like the expression is. The resource limits and timeouts still apply, but little else. So if you are dynamically adding functions and module imports, you *MUST* secure them yourself or accept the loss of security. Currently, all known 'evil' expressions cause Mueval to exit with an error (a non-zero exit code), so my advice is to do something like 'mueval --expression foo && echo "\n" >> L.hs && echo foo >> L.hs'. (That is, only accept new expressions which evaluate successfully.)--SUMMARY:-Anyway, it's my hope that this will be useful as an example or useful in itself for people endeavoring to fix the Lambdabot situation or just in safely running code period.--GETTING:-You can download Mueval at the usual place: <http://hackage.haskell.org/cgi-bin/hackage-scripts/package/mueval>. Mueval has a public darcs repository, at <http://code.haskell.org/mubot/> (in the mueval/ subdirectory). Contributions are of course welcomed.--INSTALLING:-Mueval depends on a few of the standard libraries, which you should have installed already, and also on the 'Hint' library <http://hackage.haskell.org/cgi-bin/hackage-scripts/package/hint>; Hint is particularly essential as it is the very capable wrapper around the GHC API which Mueval uses. (Without Hint, this would've been much more painful to write). All of this is cabalized, so ideally installation will be as simple as:-- sh$ cabal install mueval--However, you can still manually download and unpack the Mueval tarball, and do the usual Cabal dance:-- sh$ runhaskell Setup configure- sh$ runhaskell Setup build- sh$ runhaskell Setup install--BUGS:-Mueval uses a number of techniques for security; particularly problematic seem to be the resource limits, as they have to be specified manually & statically in the source code and so will probably be broken somewhere somewhen. For this reason, they are not enabled by default. Experiment with --rlimits for hours of fun!--Mueval also simply cannot do qualified imports. This is due to limitations in the GHC API; see <http://hackage.haskell.org/trac/ghc/ticket/1895>. (Remember that CC'ing yourself is an implicit vote for the problem to be fixed!)--With darcs Hint and Mueval, compiling Mueval (or any Hint-using executable) with profiling support seems to lead to runtime crashes.--Finally, under 6.10.1, you must run Mueval with "+RTS -N2 -RTS" as otherwise the watchdog threads will not get run and DoS attacks are possible. (Compare 'mueval -e "let x = x + 1 in x"' against 'mueval -e "let x = x + 1 in x" +RTS -N2 -RTS'.)--CONTRIBUTING:-So, you've discovered a bug or other infelicity? If you can successfully build & install Mueval, but running it on expressions leads to errors, please send me an email at <gwern0@gmail.com>. Include in the email all the output you see if you run the informal test suite:-- sh$ sh tests.sh--If this script *does not* terminate with a success message, then there's probably something wrong. One of the properties Mueval strives to have is that on every bad expression, it errors out with an exit code of 1, and on every good expression, an exit code of 0.--If you have a patch handy, 'darcs send' is the best way to contribute. As above, tests.sh should be happy, as should 'cabal check'; even better is if your email is GPG-signed, but that's not as important as test.sh passing.
+ README.md view
@@ -0,0 +1,87 @@+# What++Mueval grew out of my discontent with Lambdabot: it's really neat to be able to run expressions in `#haskell` like this:++ 07:53 < ivanm> > filter (\ x -> isLetter x || x == '\t') "asdf$#$ dfs"+ 07:55 < lambdabot> "asdfdfs"++But Lambdabot is crufty and very difficult to install or run. IMO, we need a replacement or rewrite, but one of the things that make this difficult is that Lambdabot uses `hs-plugins` to get that sort of evaluation functionality, and `hs-plugins` is half the problem. We want some sort of standalone executable which provides that functionality. Now, `ghc -e` is obviously unsuited because there is no sandboxing, so what I've done is basically marry the GHC API (as rendered less sharp-edged by Hint) with a bunch of resource limits and sandboxing (as largely stolen from Lambdabot).++# Examples++The end result is an adorable little program, which you can use like this:++ $ mueval --expression '1*100+1'+ Expression type: (Num t) => t+ result: "101"++ $ mueval --expression "filter (\`notElem\` ['A'..'Z']) \"abcXsdzWEE\""+ Expression type: [Char]+ result: "\"abcsdz\""++Note that mueval will avoid all the attacks I've been able to test on it:++ $ mueval --expression 'let x = x in x'+ Expression type: t+ result: "mueval: Time limit exceeded"++ $ mueval --expression "let foo = readFile \"/etc/passwd\" >>= print in foo"+ Expression type: IO ()+ result: "<IO ()>"++ $ mueval --module System.IO.Unsafe --expression "let foo = unsafePerformIO readFile \"/etc/passwd\" in foo"+ mueval: Unknown or untrusted module supplied! Aborting.++## Loading definitions from files++Like Lambdabot, Mueval is capable of loading a file and its definitions. This is useful to get a kind of persistence. Suppose you have a file `L.hs`, with a function `bar = (+1)` in it; then `mueval --loadfile=L.hs --expression="bar 1"` will evaluate to, as one would expect, `2`.++It's worth noting that definitions and module imports in the loaded *are not* fully checked like the expression is. The resource limits and timeouts still apply, but little else. So if you are dynamically adding functions and module imports, you *must* secure them yourself or accept the loss of security. Currently, all known 'evil' expressions cause Mueval to exit with an error (a non-zero exit code), so my advice is to do something like `mueval --expression foo && echo "\n" >> L.hs && echo foo >> L.hs`. (That is, only accept new expressions which evaluate successfully.)++# Summary++Anyway, it's my hope that this will be useful as an example or useful in itself for people endeavoring to fix the Lambdabot situation or just in safely running code period.++# Getting++You can download Mueval at Hackage: <http://hackage.haskell.org/package/mueval>. Mueval has a public Git repository, at <https://github.com/gwern/mueval>. Contributions & updates are of course welcomed.++# Installing++Mueval depends on a few of the standard libraries, which you should have installed already, and also on the 'Hint' library <http://hackage.haskell.org/package/hint>; Hint is particularly essential as it is the very capable wrapper around the GHC API which Mueval uses. (Without Hint, this would've been much more painful to write). All of this is cabalized, so ideally installation will be as simple as:++ $ cabal install mueval++However, you can still manually download and unpack the Mueval tarball, and do the usual Cabal dance:++ $ runhaskell Setup configure+ $ runhaskell Setup build+ $ runhaskell Setup install++# See also++- Chris Done's [`mueval-interactive`](https://github.com/chrisdone/mueval-interactive) fork: a persistent `mueval` (startup is slow) for use in his [Try Haskell.org](http://tryhaskell.org/)++# Bugs++Mueval uses a number of techniques for security; particularly problematic seem to be the resource limits, as they have to be specified manually & statically in the source code and so will probably be broken somewhere somewhen. For this reason, they are not enabled by default. Experiment with --rlimits for hours of fun!++Mueval also cannot do qualified imports. This is due to limitations in the GHC API; see <https://ghc.haskell.org/trac/ghc/ticket/1895> & <https://ghc.haskell.org/trac/ghc/ticket/2362>.++As of 2010 or so, compiling Mueval (or any Hint-using executable) with profiling support seems to lead to runtime crashes.++Finally, under GHC 6.10.1 (and higher?), you must run Mueval with `+RTS -N2 -RTS` as otherwise the watchdog threads will not get run and DoS attacks are possible. (Compare `mueval -e "let x = x + 1 in x"` against `mueval -e "let x = x + 1 in x" +RTS -N2 -RTS`.)++# Contributions++So, you've discovered a bug or other infelicity? If you can successfully build & install Mueval, but running it on expressions leads to errors, please send me an email at <gwern@gwern.net>. Include in the email all the output you see if you run the informal test suite:++ $ sh tests.sh++If this script *does not* terminate with a success message, then there's probably something wrong. One of the properties Mueval strives to have is that on every bad expression, it errors out with an exit code of 1, and on every good expression, an exit code of 0.++Also good is making sure `cabal check` and `hlint` are happy; but that's not as important as `tests.sh` passing.++# License++BSD-3.
mueval.cabal view
@@ -1,10 +1,10 @@ name: mueval-version: 0.9.1+version: 0.9.1.1 license: BSD3 license-file: LICENSE author: Gwern-maintainer: Gwern <gwern0@gmail.com>+maintainer: Gwern <gwern@gwern.net> category: Development, Language synopsis: Safely evaluate pure Haskell expressions@@ -19,13 +19,13 @@ evaluation functionality. For examples and explanations, please see the README file. . Mueval is POSIX-only.-homepage: http://code.haskell.org/mubot/+homepage: https://github.com/gwern/mueval build-type: Simple cabal-version: >= 1.6 tested-with: GHC==6.10.1 -data-files: README, HCAR.tex+data-files: README.md, HCAR.tex extra-source-files: build.sh, tests.sh library@@ -33,18 +33,18 @@ Mueval.ArgsParse, Mueval.Resources build-depends: base>=4 && < 5, containers, directory, mtl>2, filepath, unix, process, hint>=0.3.1, show>=0.3, utf8-string, Cabal, extensible-exceptions, simple-reflect- ghc-options: -Wall -static -O2+ ghc-options: -Wall -static executable mueval-core main-is: main.hs build-depends: base- ghc-options: -Wall -static -threaded -O2+ ghc-options: -Wall -static -threaded executable mueval main-is: watchdog.hs build-depends: base- ghc-options: -Wall -static -threaded -O2+ ghc-options: -Wall -static -threaded source-repository head- type: darcs- location: http://code.haskell.org/mubot/+ type: git+ location: git://github.com/gwern/mueval.git
tests.sh view
@@ -38,7 +38,7 @@ ## Test 1024-char limit m 'repeat 1' ## Test Unicode. If this fails, characters got mangled somewhere.-# m 'let (ñ) = (+) in ñ 5 5'+m 'let (ñ) = (+) in ñ 5 5' ## Test default imports & have some function fun m 'fix (1:)' m 'fix show'