-
Notifications
You must be signed in to change notification settings - Fork 40
Description
System.Path.mktmpdir does not make temporary directories securely. It calls either mkstemp or openTempFile to create a temporary file, removes that file, and creates a directory with the same name. That introduces a race condition: between the removal of the file and the creation of the directory, another program could create a symlink with the same name.
Jamey Sharp and I ended up writing a similar function that works securely, in pure portable Haskell with no FFI:
-- Note that this uses the current umask
mkdtemp :: FilePath -> IO FilePath
mkdtemp prefix = do
suffix <- sequence $ replicate 8 $ randomRIO ('a', 'z')
let path = prefix ++ '.' : suffix
result <- tryJust (guard . isAlreadyExistsError) $ createDirectory path
case result of
Left _ -> mkdtemp prefix
Right _ -> return path
If you don't mind using the createDirectory from System.Posix.Directory instead, you can trivially create the directory with mode 0o700 instead. Other potentialy useful enhancements: allowing the user to specify a template (with the .XXXXXXXX included) rather than just a prefix, and using [A-Za-z0-9] rather than just [a-z](hence why I use 8 characters rather than 6: 8 [a-z] has more entropy than 6 [A-Za-z0-9]). Not sure I see any value in the template, though, except for compatibility with the mkdtemp C function which only wants the template so it can overwrite the X characters and avoid allocating memory itself. That doesn't apply to the Haskell version, though, so the template seems like a waste.