Not able to read/write in directories where the config.toml has configured that directory as a writable root

Resolved 💬 3 comments Opened Jan 14, 2026 by baccigalupi Closed Jan 15, 2026

What version of Codex is running?

codex-cli 0.81.0

What subscription do you have?

Some cisco mega enterprise thingy

Which model were you using?

gpt-5.1-codex-max

What platform is your computer?

Linux 5.15.0-1068-aws (Ubuntu 20.04 kernel)

What terminal emulator and version are you using (if applicable)?

iterm2

What issue are you seeing?

Setting my config.coms with a writable root doesn't make that root writable or readable.

[sandbox]
writable_roots = ["/my/path"]

Running ls /my/path in codex fails with a Landlock failure.

I had codex debug it and write some C scripts to verify it's hypothesis. It believes that the commands happen out of order when setting up the sandbox. Details in additional information.

What steps can reproduce the bug?

Uploaded thread: 019bbebb-c0b6-7111-8994-6ed51163edd9

What is the expected behavior?

When I configure a writable root in my config.toml it is readable and writable.

Additional information

Here is a document I had codex write after debugging the issue:

------

Codex sandbox Landlock failure on AWS kernel

Summary

  • Sandboxed commands fail before execution with: "error running landlock: Io(Os { code: 1, kind: PermissionDenied, message: \"Operation not permitted\" })".
  • Host kernel supports Landlock and unprivileged Landlock works when no_new_privs is set first.
  • This points to a sandbox wrapper ordering issue (calling landlock_restrict_self before setting no_new_privs).

Environment

  • Host: Linux <redacted-hostname> 5.15.0-1068-aws (Ubuntu 20.04 kernel)
  • LSMs: lockdown, capability, landlock, yama, apparmor
  • Kernel config: CONFIG_SECURITY_LANDLOCK=y, CONFIG_LSM includes landlock
  • Codex config: /home/<redacted-user>/.codex/config.toml includes [sandbox] writable_roots = ["/home/<redacted-user>/co/manage"]

Repro
1) Run any sandboxed command, e.g.:

  • rg --files -g '*.toml' /home/kane/.codex

2) Result: the command fails before execution with Landlock EPERM.

Observed

  • Error on sandboxed command:
  • thread 'main' panicked at linux-sandbox/src/linux_run_main.rs:30:9:
  • error running landlock: Io(Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" })

Expected

  • Sandbox should initialize and command should run (and then be restricted by writable_roots).

Landlock probe results

  • I ran a minimal C program that calls the Landlock syscalls directly.
  • Output:
  • landlock ABI version: 1
  • landlock_create_ruleset(attr) ok, fd=3
  • landlock_restrict_self (before no_new_privs) failed: errno=1 (Operation not permitted)
  • prctl(PR_SET_NO_NEW_PRIVS) ok
  • landlock_restrict_self (after no_new_privs) ok

Landlock probe source (C)

#define _GNU_SOURCE
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>

#ifndef __NR_landlock_create_ruleset
#define __NR_landlock_create_ruleset 444
#endif
#ifndef __NR_landlock_restrict_self
#define __NR_landlock_restrict_self 446
#endif

#ifndef LANDLOCK_CREATE_RULESET_VERSION
#define LANDLOCK_CREATE_RULESET_VERSION (1U << 0)
#endif
#ifndef LANDLOCK_ACCESS_FS_EXECUTE
#define LANDLOCK_ACCESS_FS_EXECUTE (1ULL << 0)
#endif

struct landlock_ruleset_attr {
    uint64_t handled_access_fs;
};

static int ll_create(const struct landlock_ruleset_attr *attr, size_t size, uint32_t flags) {
    return (int)syscall(__NR_landlock_create_ruleset, attr, size, flags);
}

static int ll_restrict(int fd, uint32_t flags) {
    return (int)syscall(__NR_landlock_restrict_self, fd, flags);
}

int main(void) {
    errno = 0;
    int abi = ll_create(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
    if (abi < 0) {
        printf("landlock_create_ruleset(VERSION) failed: errno=%d (%s)\n", errno, strerror(errno));
    } else {
        printf("landlock ABI version: %d\n", abi);
    }

    struct landlock_ruleset_attr attr = {0};
    attr.handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE;

    errno = 0;
    int fd = ll_create(&attr, sizeof(attr), 0);
    if (fd < 0) {
        printf("landlock_create_ruleset(attr) failed: errno=%d (%s)\n", errno, strerror(errno));
        return 0;
    }
    printf("landlock_create_ruleset(attr) ok, fd=%d\n", fd);

    errno = 0;
    int ret = ll_restrict(fd, 0);
    if (ret < 0) {
        printf("landlock_restrict_self (before no_new_privs) failed: errno=%d (%s)\n", errno, strerror(errno));
    } else {
        printf("landlock_restrict_self (before no_new_privs) ok\n");
    }

    errno = 0;
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
        printf("prctl(PR_SET_NO_NEW_PRIVS) failed: errno=%d (%s)\n", errno, strerror(errno));
    } else {
        printf("prctl(PR_SET_NO_NEW_PRIVS) ok\n");
    }

    errno = 0;
    int fd2 = ll_create(&attr, sizeof(attr), 0);
    if (fd2 < 0) {
        printf("landlock_create_ruleset(attr) after no_new_privs failed: errno=%d (%s)\n", errno, strerror(errno));
        return 0;
    }

    errno = 0;
    ret = ll_restrict(fd2, 0);
    if (ret < 0) {
        printf("landlock_restrict_self (after no_new_privs) failed: errno=%d (%s)\n", errno, strerror(errno));
    } else {
        printf("landlock_restrict_self (after no_new_privs) ok\n");
    }

    return 0;
}

Analysis

  • On this host, Landlock is available and works, but requires no_new_privs=1 for unprivileged landlock_restrict_self.
  • The sandbox wrapper appears to call Landlock before setting no_new_privs, causing EPERM and aborting before any command executes.

Impact

  • All sandboxed commands fail immediately, even when operating in configured writable roots.
  • Escalated (non-sandboxed) runs work and can access /home/<redacted-user>/co/manage.

Suggested fix

  • Ensure the sandbox wrapper sets PR_SET_NO_NEW_PRIVS before invoking landlock_restrict_self.
  • Optionally add a clearer error message when Landlock fails due to missing no_new_privs.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗