Landlock-Sharp

Error handling

The binding surfaces three kinds of error:

  1. Win32Exception thrown by Landlock-Sharp itself when a syscall returns a negative result. The NativeErrorCode is the libc errno.
  2. UnauthorizedAccessException thrown by .NET I/O APIs after the sandbox is enforced — the kernel returned EACCES and the standard library wrapped it.
  3. PlatformNotSupportedException (your code, not the library) when you decide the kernel is too old for what you need.

This page walks through the common cases. For the authoritative errno lists see the per-syscall man pages: landlock_create_ruleset(2), landlock_add_rule(2), landlock_restrict_self(2).


Errors from CreateRuleset

try
{
    var sandbox = Landlock.CreateRuleset(Landlock.FileSystem.CORE);
}
catch (Win32Exception ex)
{
    // ex.NativeErrorCode is errno
}
errno Meaning Fix
ENOSYS Kernel doesn't know the Landlock syscalls. Run on kernel ≥ 5.13. Guard call sites with Landlock.IsSupported().
EOPNOTSUPP Kernel knows the syscalls but Landlock is disabled in lsm=. Re-enable Landlock in the kernel boot parameters — see the kernel docs.
EINVAL A handled-access flag was rejected. Usually: requested a flag the kernel doesn't recognise. The binding already auto-filters by ABI, so this typically only happens if you bypass that filtering.
E2BIG The landlock_ruleset_attr struct was the wrong size. Should not happen with the shipped binding — file a bug.

Errors from AddPathBeneathRule

try
{
    sandbox.AddPathBeneathRule("/no/such/dir", Landlock.FileSystem.READ_FILE);
}
catch (Win32Exception ex)
{
    // ex.Message will be: open O_PATH("/no/such/dir") failed
}
errno Where Meaning Fix
ENOENT open(O_PATH) step Path doesn't exist. Create the directory before adding the rule.
EACCES open(O_PATH) step The current process lacks permission to even reference the path. Check ownership / mode of every component in the path.
ENOTDIR open(O_PATH) step Path is a file, not a directory. AddPathBeneathRule only takes directories.
EINVAL landlock_add_rule step An allowed-action flag isn't in the ruleset's handled-access set. Add the flag to CreateRuleset too, or remove it from the rule.
EBADF / EBADFD landlock_add_rule step The ruleset fd is stale or already enforced. Don't reuse an enforced Landlock instance.

The binding additionally throws a managed Exception (not Win32Exception) with the message "Cannot modify an already enforced landlock" if you call AddPathBeneathRule or AddPortRule after Enforce().


Errors from Enforce

try
{
    sandbox.Enforce();
}
catch (Win32Exception ex)
{
    // The kernel rejected the call.
}
errno Coming from Meaning Fix
EPERM prctl(PR_SET_NO_NEW_PRIVS) step The kernel disallows PR_SET_NO_NEW_PRIVS for this process. Rare. Check that you're not running under a kernel security policy that forbids no_new_privs.
EACCES landlock_restrict_self step Caller doesn't have permission to restrict itself. Usually means the kernel was unable to set PR_SET_NO_NEW_PRIVS first. Same as EPERM.
EBADF / EBADFD landlock_restrict_self step The ruleset fd has been closed. Don't reuse an already-enforced Landlock instance.
E2BIG landlock_restrict_self step Too many nested Landlock domains. Reduce how often you layer rulesets.

Errors from .NET I/O after Enforce

This is the case you'll see most often. When Landlock blocks an access, the underlying syscall returns EACCES. The .NET BCL wraps that into an UnauthorizedAccessException:

try
{
    File.ReadAllText("/etc/passwd");
}
catch (UnauthorizedAccessException)
{
    // Landlock (or filesystem permissions) blocked the read.
}

There's no way at .NET level to distinguish "blocked by filesystem permissions" from "blocked by Landlock" — the kernel returns the same errno. If you need to tell them apart, check Landlock.IsSupported() plus whether you have an enforced sandbox.

For network calls, you'll see SocketException with the AccessDenied socket error code when Landlock blocks bind/connect.


public static bool TryApplySandbox(out string reason)
{
    if (!Landlock.IsSupported())
    {
        reason = "Landlock unsupported on this kernel.";
        return false;
    }

    try
    {
        Landlock.CreateRuleset(Landlock.FileSystem.CORE)
            .AddPathBeneathRule("/var/lib/myapp",
                Landlock.FileSystem.READ_FILE,
                Landlock.FileSystem.READ_DIR,
                Landlock.FileSystem.WRITE_FILE)
            .Enforce();

        reason = $"Sandbox active (ABI {Landlock.GetAbiVersion()})";
        return true;
    }
    catch (Win32Exception ex)
    {
        reason = $"Landlock setup failed: errno={ex.NativeErrorCode}, {ex.Message}";
        return false;
    }
}

Decide your own policy: refuse to start if the sandbox couldn't be applied (most secure) or log a warning and continue (most compatible). The library does not impose either choice.

© 2026 Landlock-Sharp. All rights reserved.