-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Cardano.Crypto.Libsodium with basic secure memory stubs
The allocSecureForeignPtr is as secure as `libsodium` makes it. To allocate the single `GHC.Fingerprint` (used for 128bit MD5 hash), on my machine it reserves four memory pages. With provided `memory-example`, it is possible to investigate what (and if) happens. Execute with cabal run test-memory-example -- Then, using information in /proc we can see how pages come and go. The pages around the payload page (`rw-p` one) are protection trap pages by libsodium, explained in https://libsodium.gitbook.io/doc/memory_management#guarded-heap-allocations ```diff --- before.txt 2020-06-01 00:46:35.947953980 +0300 +++ after.txt 2020-06-01 00:46:42.003877057 +0300 @@ -46,10 +46,6 @@ 7f3538e01000-7f3538e02000 rw-p 0019d000 103:05 399924 /lib/x86_64-linux-gnu/libm-2.27.so 7f3538e02000-7f3538e29000 r-xp 00000000 103:05 397952 /lib/x86_64-linux-gnu/ld-2.27.so 7f3538fff000-7f3539005000 rw-p 00000000 00:00 0 -7f3539025000-7f3539026000 r--p 00000000 00:00 0 -7f3539026000-7f3539027000 ---p 00000000 00:00 0 -7f3539027000-7f3539028000 rw-p 00000000 00:00 0 -7f3539028000-7f3539029000 ---p 00000000 00:00 0 7f3539029000-7f353902a000 r--p 00027000 103:05 397952 /lib/x86_64-linux-gnu/ld-2.27.so 7f353902a000-7f353902b000 rw-p 00028000 103:05 397952 /lib/x86_64-linux-gnu/ld-2.27.so 7f353902b000-7f353902c000 rw-p 00000000 00:00 0 ``` I think that for development this is very good option. The less memory hungry variant can be easily added later. Yet, in it we'd still like to use `libsodium`'s `mlock` and `munlock` primitives, so having this in place sooner is beneficial.
- Loading branch information
Showing
3 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
{-# LANGUAGE RankNTypes #-} | ||
module Main (main) where | ||
|
||
import Foreign.ForeignPtr (ForeignPtr, finalizeForeignPtr, withForeignPtr) | ||
import Foreign.Storable (Storable (peek, poke)) | ||
import Control.Monad (void, when) | ||
import GHC.Fingerprint (Fingerprint (..)) | ||
import System.Environment (getArgs) | ||
import System.Posix.Process (getProcessID) | ||
|
||
import Cardano.Crypto.Libsodium (allocSecureForeignPtr, sodiumInit) | ||
|
||
main :: IO () | ||
main = do | ||
pid <- getProcessID | ||
|
||
putStrLn $ "If you run this test with 'pause' argument" | ||
putStrLn $ "you may look at /proc/" ++ show pid ++ "/maps" | ||
putStrLn $ " /proc/" ++ show pid ++ "/smaps" | ||
|
||
sodiumInit | ||
|
||
args <- getArgs | ||
|
||
sodiumInit | ||
example args allocSecureForeignPtr | ||
|
||
example | ||
:: [String] | ||
-> (IO (ForeignPtr Fingerprint)) | ||
-> IO () | ||
example args alloc = do | ||
-- create foreign ptr to mlocked memory | ||
fptr <- alloc | ||
withForeignPtr fptr $ \ptr -> poke ptr (Fingerprint 0xdead 0xc0de) | ||
|
||
when ("pause" `elem` args) $ do | ||
putStrLn "Allocated..." | ||
void getLine | ||
|
||
-- we shouldn't do this, but rather do computation inside | ||
-- withForeignPtr on provided Ptr a | ||
fingerprint <- withForeignPtr fptr peek | ||
|
||
-- we have the fingeprint | ||
print fingerprint | ||
|
||
-- force finalizers | ||
finalizeForeignPtr fptr | ||
|
||
when ("pause" `elem` args) $ do | ||
putStrLn "Finalized..." | ||
void getLine | ||
|
||
when ("use-after-free" `elem` args) $ do | ||
-- in this demo we can try to print it again. | ||
-- this should deterministically cause segmentation fault | ||
fingerprint' <- withForeignPtr fptr peek | ||
print fingerprint' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
{-# LANGUAGE CApiFFI #-} | ||
{-# LANGUAGE ScopedTypeVariables #-} | ||
module Cardano.Crypto.Libsodium | ||
( -- * High level interface | ||
sodiumInit | ||
|
||
, allocSecureForeignPtr | ||
|
||
-- * Low-level interface | ||
-- ** Initialization | ||
, c_sodium_init | ||
|
||
-- ** Zeroing memory | ||
, c_sodium_memzero | ||
|
||
-- ** Guarded heap allocations | ||
, c_sodium_malloc | ||
, c_sodium_free_funptr | ||
) where | ||
|
||
import Control.Monad (when, unless) | ||
import Foreign.C.Error (errnoToIOError, getErrno) | ||
import Foreign.C.Types (CSize (..)) | ||
import Foreign.ForeignPtr (ForeignPtr, newForeignPtr) | ||
import Foreign.Ptr (FunPtr, Ptr, nullPtr) | ||
import Foreign.Storable (Storable (alignment, sizeOf)) | ||
import GHC.IO.Exception (ioException) | ||
|
||
------------------------------------------------------------------------------- | ||
-- Initialization | ||
------------------------------------------------------------------------------- | ||
|
||
-- @sodiumInit@ initializes the library and should be called before any other | ||
-- function provided by Sodium. It is safe to call this function more than once | ||
-- and from different threads -- subsequent calls won't have any effects. | ||
-- | ||
-- <https://libsodium.gitbook.io/doc/usage> | ||
sodiumInit :: IO () | ||
sodiumInit = do | ||
res <- c_sodium_init | ||
-- sodium_init() returns 0 on success, -1 on failure, and 1 if the library | ||
-- had already been initialized. | ||
unless (res == 0 || res == 1) $ fail "sodium_init failed" | ||
|
||
------------------------------------------------------------------------------- | ||
-- Acquiring memory | ||
------------------------------------------------------------------------------- | ||
|
||
-- | Allocate secure memory using 'c_sodium_malloc'. | ||
-- | ||
-- <https://libsodium.gitbook.io/doc/memory_management> | ||
-- | ||
allocSecureForeignPtr :: Storable a => IO (ForeignPtr a) | ||
allocSecureForeignPtr = impl undefined where | ||
impl :: forall b. Storable b => b -> IO (ForeignPtr b) | ||
impl b = do | ||
ptr <- c_sodium_malloc size | ||
when (ptr == nullPtr) $ do | ||
errno <- getErrno | ||
ioException $ errnoToIOError "allocSecureForeingPtr: c_sodium_malloc" errno Nothing Nothing | ||
|
||
newForeignPtr c_sodium_free_funptr ptr | ||
|
||
where | ||
size :: CSize | ||
size = fromIntegral size'' | ||
|
||
size' :: Int | ||
size' = sizeOf b | ||
|
||
align :: Int | ||
align = alignment b | ||
|
||
size'' :: Int | ||
size'' | ||
| m == 0 = size' | ||
| otherwise = (q + 1) * align | ||
where | ||
(q,m) = size' `divMod` align | ||
|
||
------------------------------------------------------------------------------- | ||
-- Low-level c-bindings | ||
------------------------------------------------------------------------------- | ||
|
||
-- | @void sodium_init():@ | ||
-- | ||
-- <https://libsodium.gitbook.io/doc/usage> | ||
foreign import capi "sodium.h sodium_init" c_sodium_init :: IO Int | ||
|
||
-- | @void sodium_memzero(void * const pnt, const size_t len);@ | ||
-- | ||
-- <https://libsodium.gitbook.io/doc/memory_management#zeroing-memory> | ||
foreign import capi "sodium.h sodium_memzero" c_sodium_memzero :: Ptr a -> CSize -> IO () | ||
|
||
-- | @void *sodium_malloc(size_t size);@ | ||
-- | ||
-- <https://libsodium.gitbook.io/doc/memory_management> | ||
foreign import capi "sodium.h sodium_malloc" c_sodium_malloc :: CSize -> IO (Ptr a) | ||
|
||
-- | @void sodium_free(void *ptr);@ | ||
-- | ||
-- <https://libsodium.gitbook.io/doc/memory_management> | ||
foreign import capi "sodium.h &sodium_free" c_sodium_free_funptr :: FunPtr (Ptr a -> IO ()) |