Skip to content

mktmpdir broken: insecure temporary file race condition #4

@joshtriplett

Description

@joshtriplett

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions