landlock: Haskell bindings for the Linux Landlock API

[ bsd3, library, system ] [ Propose Tags ]

This library exposes Haskell bindings for the Linux kernel Landlock API.

The Linux kernel Landlock API provides unprivileged access control. The goal of Landlock is to enable to restrict ambient rights (e.g. global filesystem access) for a set of processes. Because Landlock is a stackable LSM, it makes possible to create safe security sandboxes as new security layers in addition to the existing system-wide access-controls. This kind of sandbox is expected to help mitigate the security impact of bugs or unexpected/malicious behaviors in user space applications. Landlock empowers any process, including unprivileged ones, to securely restrict themselves.

For more information, see the Landlock homepage and its kernel documentation.


[Skip to Readme]

Modules

[Index] [Quick Jump]

Flags

Manual Flags

NameDescriptionDefault
landlocked

Build the landlocked utility.

Enabled
werror

Turn compiler warnings into errors.

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.0, 0.2.0.0, 0.2.0.1, 0.2.1.0, 0.2.1.1 (info)
Change log CHANGELOG.md
Dependencies base (>=4.14.2.0 && <4.18), exceptions (>=0.10.4 && <0.11), landlock, optparse-applicative (>=0.16.1.0 && <0.18), psx (>=0.1 && <0.2), unix (>=2.7.2.2 && <2.9) [details]
License BSD-3-Clause
Copyright (c) 2022 Nicolas Trangez
Author Nicolas Trangez
Maintainer ikke@nicolast.be
Category System
Home page https://github.com/NicolasT/landlock-hs
Bug tracker https://github.com/NicolasT/landlock-hs/issues
Source repo head: git clone https://github.com/NicolasT/landlock-hs.git -b main(landlock)
Uploaded by NicolasTrangez at 2023-02-28T22:49:22Z
Distributions
Executables landlocked
Downloads 200 total (13 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for landlock-0.2.1.1

[back to package description]

landlock-hs: Haskell bindings for the Linux Landlock API

This library exposes Haskell bindings for the Linux kernel Landlock API.

The Linux kernel Landlock API provides unprivileged access control. The goal of Landlock is to enable to restrict ambient rights (e.g. global filesystem access) for a set of processes. Because Landlock is a stackable LSM, it makes possible to create safe security sandboxes as new security layers in addition to the existing system-wide access-controls. This kind of sandbox is expected to help mitigate the security impact of bugs or unexpected/malicious behaviors in user space applications. Landlock empowers any process, including unprivileged ones, to securely restrict themselves.

For more information, see the Landlock homepage and its kernel documentation.

Example

Here's a simple example, allowing read-only access to the user's SSH public key, full access to tmp and the ability to read and execute everything in /usr:

import System.Landlock (
      AccessFsFlag(..)
    , OpenPathFlags(..)
    , RulesetAttr(..)
    , abiVersion
    , accessFsFlags
    , accessFsFlagIsReadOnly
    , defaultOpenPathFlags
    , isSupported
    , landlock
    , pathBeneath
    , withOpenPath
    )

import ReadmeUtils

-- These tests run with a "fake" pre-populated rootfs
-- All files and directories in it are created using the current user,
-- readable, writable and (in case of scripts) executable, so without
-- Landlock, there would be no permission errors.

main :: IO ()
main = withFakeRoot $ \root -> do
    -- Check whether Landlock is supported
    hasLandlock <- isSupported

    unless hasLandlock $
        fail "Landlock not supported"

    version <- abiVersion
    -- Find all FS access flags for the running kernel's ABI version
    allFlags <- lookupAccessFsFlags version
    let roFlags = filter accessFsFlagIsReadOnly allFlags

    let homeDir = root </> "home" </> "user"
        publicKey = homeDir </> ".ssh" </> "id_ed25519.pub"
        privateKey = homeDir </> ".ssh" </> "id_ed25519"
        tmpDir = root </> "tmp"

    -- Construct the sandbox, locking down everything by default
    landlock (RulesetAttr allFlags) [] [] $ \addRule -> do
        -- /tmp is fully accessible
        withOpenPath tmpDir defaultOpenPathFlags{ directory = True } $ \tmp ->
            addRule (pathBeneath tmp allFlags) []

        -- SSH public key is readable
        withOpenPath publicKey defaultOpenPathFlags $ \key ->
            addRule (pathBeneath key [AccessFsReadFile]) []

        -- (Real) /usr is fully accessible, but read-only (includes executable permissions)
        withOpenPath "/usr" defaultOpenPathFlags{ directory = True } $ \usr -> do
            addRule (pathBeneath usr roFlags) []

    -- Can create and write to files in tmp
    writeFile (tmpDir </> "program.log") "Success!"

    -- Can read SSH key
    _pubKey <- readFile publicKey

    -- Can execute things in /usr
    "Linux\n" <- readProcess ("/usr" </> "bin" </> "uname") ["-s"] ""

    -- Can't read SSH private key
    assertPermissionDenied $
        readFile privateKey

    -- Can't write to SSH public key
    assertPermissionDenied $
        withFile publicKey WriteMode $ \fd ->
            hPutStrLn fd "Oops, key gone!"

    -- Can't remove SSH public key
    assertPermissionDenied $
        removeFile publicKey

    -- Can't create files in homedir
    assertPermissionDenied $
        writeFile (homeDir </> "whoops.txt") "This file should not exist!"

    -- Can't read files from (real) /etc
    assertPermissionDenied $
        readFile ("/etc" </> "hosts")

  where
    lookupAccessFsFlags version = case lookup version accessFsFlags of
        -- In a production implementation, we'd lookup the "best matching" flag
        -- set, not require an exact match.
        Nothing -> fail "Unsupported ABI version"
        Just flags -> return flags

    assertPermissionDenied act = handleJust permissionDenied return $ do
        _ <- act
        fail "Expected permission error"
    permissionDenied e = if isPermissionError e then Just () else Nothing