syd 3.52.0

rock-solid application kernel
Documentation
//
// Syd: rock-solid application kernel
// src/kernel/chdir.rs: chdir(2) and fchdir(2) handlers
//
// Copyright (c) 2023, 2024, 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use libseccomp::ScmpNotifResp;
use nix::errno::Errno;

use crate::{
    kernel::syscall_path_handler,
    req::{SysArg, UNotifyEventRequest},
};

pub(crate) fn sys_chdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We do not pass `fsflags` which defaults to MUST_PATH.
    let argv = &[SysArg {
        path: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(request, "chdir", argv, |path_args, request, sandbox| {
        drop(sandbox); // release the read-lock.

        // SysArg has one element.
        #[expect(clippy::disallowed_methods)]
        if let Some(typ) = path_args.0.as_ref().unwrap().path.typ.as_ref() {
            if !typ.is_dir() {
                return Err(Errno::ENOTDIR);
            }
        } else {
            return Err(Errno::ENOENT);
        }

        // SAFETY: This is vulnerable to TOCTTOU.
        // We only use this hook with trace/allow_unsafe_ptrace:1
        // hence the user is aware of the consequences.
        Ok(unsafe { request.continue_syscall() })
    })
}

pub(crate) fn sys_fchdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We do not pass `fsflags` which defaults to MUST_PATH.
    // fchdir works with O_PATH fds.
    let argv = &[SysArg {
        dirfd: Some(0),
        ..Default::default()
    }];

    syscall_path_handler(request, "fchdir", argv, |path_args, request, sandbox| {
        drop(sandbox); // release the read-lock.

        // SysArg has one element.
        #[expect(clippy::disallowed_methods)]
        let path = &path_args.0.as_ref().unwrap().path;

        // Check file type.
        if let Some(typ) = path.typ.as_ref() {
            if !typ.is_dir() {
                // Deny non-directory with ENOTDIR.
                return Err(Errno::ENOTDIR);
            }
        } else {
            // No file type, file disappeared mid-way?
            return Err(Errno::ENOENT);
        }

        // SAFETY: This is vulnerable to TOCTTOU.
        // We only use this hook with trace/allow_unsafe_ptrace:1
        // hence the user is aware of the consequences.
        Ok(unsafe { request.continue_syscall() })
    })
}