1use std::os::fd::AsRawFd;
10
11use libseccomp::ScmpNotifResp;
12use nix::{errno::Errno, fcntl::AtFlags, sys::time::TimeSpec};
13
14use crate::{
15 confine::scmp_arch_bits,
16 kernel::{syscall_path_handler, to_atflags},
17 lookup::FsFlags,
18 req::{PathArgs, SysArg, SysFlags, UNotifyEventRequest},
19};
20
21pub(crate) fn sys_utime(request: UNotifyEventRequest) -> ScmpNotifResp {
22 let argv = &[SysArg {
23 path: Some(0),
24 fsflags: FsFlags::MUST_PATH,
25 ..Default::default()
26 }];
27
28 syscall_path_handler(request, "utime", argv, |path_args, request, sandbox| {
29 drop(sandbox); let req = request.scmpreq;
32 let (atime, mtime) = request.remote_utimbuf(req.data.args[1])?;
33 syscall_utime_handler(request, path_args, &atime, &mtime)
34 })
35}
36
37pub(crate) fn sys_utimes(request: UNotifyEventRequest) -> ScmpNotifResp {
38 let argv = &[SysArg {
39 path: Some(0),
40 fsflags: FsFlags::MUST_PATH,
41 ..Default::default()
42 }];
43
44 syscall_path_handler(request, "utime", argv, |path_args, request, sandbox| {
45 drop(sandbox); let req = request.scmpreq;
48 let (atime, mtime) = request.remote_utimbuf(req.data.args[1])?;
49 syscall_utime_handler(request, path_args, &atime, &mtime)
50 })
51}
52
53pub(crate) fn sys_futimesat(request: UNotifyEventRequest) -> ScmpNotifResp {
54 let req = request.scmpreq;
55
56 let fsflags = FsFlags::MUST_PATH;
57 let path = if req.data.args[1] != 0 { Some(1) } else { None };
58
59 let argv = &[SysArg {
60 dirfd: Some(0),
61 path,
62 fsflags,
63 ..Default::default()
64 }];
65
66 syscall_path_handler(request, "futimesat", argv, |path_args, request, sandbox| {
67 drop(sandbox); let (atime, mtime) = request.remote_timeval(req.data.args[2])?;
70 syscall_utime_handler(request, path_args, &atime, &mtime)
71 })
72}
73
74pub(crate) fn sys_utimensat(request: UNotifyEventRequest) -> ScmpNotifResp {
75 let req = request.scmpreq;
76
77 let atflags = match to_atflags(
79 req.data.args[3],
80 AtFlags::AT_EMPTY_PATH | AtFlags::AT_SYMLINK_NOFOLLOW,
81 ) {
82 Ok(atflags) => atflags,
83 Err(errno) => return request.fail_syscall(errno),
84 };
85
86 let mut flags = SysFlags::empty();
87 let mut fsflags = FsFlags::MUST_PATH;
88 if atflags.contains(AtFlags::AT_EMPTY_PATH) {
89 flags |= SysFlags::EMPTY_PATH;
90 }
91 if atflags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
92 fsflags |= FsFlags::NO_FOLLOW_LAST;
93 }
94
95 let argv = &[SysArg {
96 dirfd: Some(0),
97 path: if req.data.args[1] != 0 { Some(1) } else { None },
98 flags,
99 fsflags,
100 ..Default::default()
101 }];
102
103 syscall_path_handler(request, "utimensat", argv, |path_args, request, sandbox| {
104 drop(sandbox); let addr = req.data.args[2];
107 let is32 = scmp_arch_bits(req.data.arch) == 32;
108
109 let (atime, mtime) = if is32 {
110 request.remote_timespec32_2(addr)
111 } else {
112 request.remote_timespec64_2(addr)
113 }?;
114
115 syscall_utime_handler(request, path_args, &atime, &mtime)
116 })
117}
118
119pub(crate) fn sys_utimensat64(request: UNotifyEventRequest) -> ScmpNotifResp {
120 let req = request.scmpreq;
121
122 let atflags = match to_atflags(
124 req.data.args[3],
125 AtFlags::AT_EMPTY_PATH | AtFlags::AT_SYMLINK_NOFOLLOW,
126 ) {
127 Ok(atflags) => atflags,
128 Err(errno) => return request.fail_syscall(errno),
129 };
130
131 let mut flags = SysFlags::empty();
132 let mut fsflags = FsFlags::MUST_PATH;
133 if atflags.contains(AtFlags::AT_EMPTY_PATH) {
134 flags |= SysFlags::EMPTY_PATH;
135 }
136 if atflags.contains(AtFlags::AT_SYMLINK_NOFOLLOW) {
137 fsflags |= FsFlags::NO_FOLLOW_LAST;
138 }
139
140 let argv = &[SysArg {
141 dirfd: Some(0),
142 path: if req.data.args[1] != 0 { Some(1) } else { None },
143 flags,
144 fsflags,
145 ..Default::default()
146 }];
147 syscall_path_handler(
148 request,
149 "utimensat_time64",
150 argv,
151 |path_args, request, sandbox| {
152 drop(sandbox); let (atime, mtime) = request.remote_timespec64_2(req.data.args[2])?;
155 syscall_utime_handler(request, path_args, &atime, &mtime)
156 },
157 )
158}
159
160fn syscall_utime_handler(
162 request: &UNotifyEventRequest,
163 args: PathArgs,
164 atime: &TimeSpec,
165 mtime: &TimeSpec,
166) -> Result<ScmpNotifResp, Errno> {
167 #[expect(clippy::disallowed_methods)]
169 let path = args.0.as_ref().unwrap();
170
171 let fd = path
172 .dir
173 .as_ref()
174 .map(|fd| fd.as_raw_fd())
175 .ok_or(Errno::EBADF)?;
176 let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
177
178 Errno::result(unsafe {
184 libc::utimensat(
185 fd,
186 c"".as_ptr().cast(),
187 &raw const times[0],
188 libc::AT_EMPTY_PATH,
189 )
190 })
191 .map(|_| request.return_syscall(0))
192}