1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
//
// 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() })
})
}