syd 3.52.0

rock-solid application kernel
Documentation
//
// Syd: rock-solid application kernel
// src/kernel/mkdir.rs: mkdir(2) and mkdirat(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, sys::stat::Mode};

use crate::{
    cookie::{safe_mkdirat, safe_umask},
    kernel::{syscall_path_handler, to_mode},
    lookup::FsFlags,
    proc::proc_umask,
    req::{PathArgs, SysArg, UNotifyEventRequest},
};

pub(crate) fn sys_mkdir(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We want NO_FOLLOW_LAST because creating an entry
    // through a dangling symbolic link should return EEXIST!
    let req = request.scmpreq;

    // Strip undefined/invalid mode bits.
    let mode = to_mode(req.data.args[1]);

    let argv = &[SysArg {
        path: Some(0),
        fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST | FsFlags::DOTLAST_EEXIST,
        ..Default::default()
    }];
    syscall_path_handler(request, "mkdir", argv, |path_args, request, sandbox| {
        drop(sandbox); // release the read-lock.
        syscall_mkdir_handler(request, path_args, mode)
    })
}

pub(crate) fn sys_mkdirat(request: UNotifyEventRequest) -> ScmpNotifResp {
    // We want NO_FOLLOW_LAST because creating an entry
    // through a dangling symbolic link should return EEXIST!
    let req = request.scmpreq;

    // Strip undefined/invalid mode bits.
    let mode = to_mode(req.data.args[2]);

    let argv = &[SysArg {
        dirfd: Some(0),
        path: Some(1),
        fsflags: FsFlags::MISS_LAST | FsFlags::NO_FOLLOW_LAST | FsFlags::DOTLAST_EEXIST,
        ..Default::default()
    }];
    syscall_path_handler(request, "mkdirat", argv, |path_args, request, sandbox| {
        drop(sandbox); // release the read-lock.
        syscall_mkdir_handler(request, path_args, mode)
    })
}

/// A helper function to handle mkdir* syscalls.
fn syscall_mkdir_handler(
    request: &UNotifyEventRequest,
    args: PathArgs,
    mode: Mode,
) -> Result<ScmpNotifResp, Errno> {
    // SysArg has one element.
    #[expect(clippy::disallowed_methods)]
    let path = &args.0.as_ref().unwrap().path;

    let req = request.scmpreq;
    let mask = proc_umask(req.pid())?;

    // Honour process' umask:
    // Umask is per-thread here.
    // POSIX ACLs may override this.
    safe_umask(mask);

    // Record blocking call so it can get invalidated.
    request.cache.add_sys_block(req, false)?;

    let result = safe_mkdirat(path.dir(), path.base(), mode);

    // Remove invalidation record.
    request.cache.del_sys_block(req.id)?;

    result.map(|_| request.return_syscall(0))
}