syd 3.52.0

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

// SAFETY: This module has been liberated from unsafe code!
#![forbid(unsafe_code)]

#[cfg(feature = "log")]
use libseccomp::ScmpNotifResp;
#[cfg(feature = "log")]
use nix::errno::Errno;

#[cfg(feature = "log")]
use crate::{
    req::UNotifyEventRequest,
    syslog::{SYSLOG_ACTION_READ, SYSLOG_ACTION_READ_ALL, SYSLOG_ACTION_READ_CLEAR},
};

#[cfg(feature = "log")]
pub(crate) fn sys_syslog(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // syslog(2) is only allowed if the sandbox lock is off,
        // unless trace/allow_safe_syslog:1 is set at startup.
        let req = request.scmpreq;
        let sandbox = request.get_sandbox();
        if !sandbox.options.allow_safe_syslog() && sandbox.locked_for(req.pid()) {
            return Err(Errno::EPERM);
        }
        drop(sandbox); // release the read-lock.

        // Return EPERM if the global Syslog has not be initialized.
        let syslog = if let Some(syslog) = crate::syslog::global_syslog() {
            syslog
        } else {
            return Err(Errno::EPERM);
        };

        // Linux truncates upper bits of action.
        #[expect(clippy::cast_possible_truncation)]
        let action = req.data.args[0] as libc::c_int;

        // Check if action is a read action.
        let is_read_action = matches!(
            action,
            SYSLOG_ACTION_READ | SYSLOG_ACTION_READ_ALL | SYSLOG_ACTION_READ_CLEAR,
        );

        // Linux rejects NULL buffer only for read actions.
        if is_read_action && req.data.args[1] == 0 {
            return Err(Errno::EINVAL);
        }

        // Linux rejects negative length only for read actions.
        #[expect(clippy::cast_possible_truncation)]
        let len = match usize::try_from(req.data.args[2] as libc::c_int) {
            Ok(len) => len,
            Err(_) if is_read_action => return Err(Errno::EINVAL),
            Err(_) => 0,
        };

        let (count, buf) = syslog.syslog(action, len)?;
        if let Some(buf) = buf {
            request.write_mem_all(&buf, req.data.args[1])?;
        }

        #[expect(clippy::cast_possible_wrap)]
        Ok(request.return_syscall(count as i64))
    })
}