1use crate::exec::{self, shim};
5use crate::fs::Fs;
6use crate::fs::translate::translate_path;
7use crate::note;
8use crate::state::Ctx;
9use crate::sys::Result;
10use crate::syscall::nr::*;
11use crate::tracee::regs::Regs;
12
13pub fn handle(ctx: &Ctx, regs: &mut Regs) {
24 let pid = regs.pid();
25 if let Some(pending) = ctx.procs.shim_pending(ctx.tgid(pid)) {
26 let tgid = ctx.tgid(pid);
27 if shim::running(pid as u32) {
28 let is_exec = matches!(
29 regs.abi().to_canonical(regs.sysnum()),
30 Some((EXECVE, _)) | Some((EXECVEAT, _))
31 );
32 if is_exec {
33 ctx.procs.shim_leave(tgid);
34 exec::finish_pending(ctx, tgid, pending);
35 }
36 return;
37 }
38 ctx.procs.shim_leave(tgid);
39 }
40 let view = ctx.view(pid);
41 let fs = &view.fs;
42 if regs.abi().socketcall_nr() == Some(regs.sysnum()) {
43 if let Err(e) = rewrite_socketcall(ctx, fs, regs) {
44 note!(
45 ctx,
46 1,
47 "pid {} socketcall: {}",
48 regs.pid(),
49 crate::sys::strerror(e)
50 );
51 regs.fail(e);
52 }
53 return;
54 }
55 let Some((nr, _)) = regs.abi().to_canonical(regs.sysnum()) else {
57 return;
58 };
59 let r = match nr {
60 EXECVE | EXECVEAT => crate::exec::handle_execve(ctx, regs),
61 CHDIR | CHROOT => rewrite_path_arg(ctx, fs, regs, 0, true),
62 CONNECT | BIND => rewrite_sockaddr(ctx, fs, regs, nr == CONNECT),
63 OPEN => {
66 let deref = regs.abi().open_flags_to_host(regs.arg(1) as i64) & libc::O_NOFOLLOW as i64 == 0;
67 rewrite_path_arg_at(ctx, fs, regs, None, 0, deref)
68 }
69 OPENAT => {
70 let deref = regs.abi().open_flags_to_host(regs.arg(2) as i64) & libc::O_NOFOLLOW as i64 == 0;
71 rewrite_path_arg_at(ctx, fs, regs, Some(0), 1, deref)
72 }
73 INOTIFY_ADD_WATCH => rewrite_path_arg(ctx, fs, regs, 1, true),
74 _ => Ok(()),
75 };
76 if let Err(e) = r {
77 note!(
78 ctx,
79 1,
80 "pid {} {}: {}",
81 regs.pid(),
82 name(nr),
83 crate::sys::strerror(e)
84 );
85 regs.fail(e);
86 }
87}
88
89pub fn push_cstr(ctx: &Ctx, regs: &mut Regs, bytes: &[u8]) -> Result<u64> {
96 let mut buf = bytes.to_vec();
97 buf.push(0);
98 let addr = regs.alloc_stack(buf.len() as u64);
99 ctx.mem.write(regs.pid() as u32, addr, &buf)?;
100 Ok(addr)
101}
102
103pub fn rewrite_path_arg_at(
116 ctx: &Ctx,
117 fs: &Fs,
118 regs: &mut Regs,
119 dirfd_index: Option<usize>,
120 path_index: usize,
121 deref_final: bool,
122) -> Result<()> {
123 let pid = regs.pid() as u32;
124 let dirfd = dirfd_index.map(|i| regs.arg(i) as i32).unwrap_or(libc::AT_FDCWD);
125 let path = ctx.mem.read_cstr(pid, regs.arg(path_index))?;
126 if path.is_empty() {
127 return Ok(()); }
129 let host = translate_path(fs, pid, dirfd, &path, deref_final)?;
130 if host != path {
131 let addr = push_cstr(ctx, regs, &host)?;
132 regs.set_arg(path_index, addr);
133 if let Some(i) = dirfd_index {
134 regs.set_arg(i, libc::AT_FDCWD as u64);
135 }
136 }
137 Ok(())
138}
139
140pub fn rewrite_path_arg(ctx: &Ctx, fs: &Fs, regs: &mut Regs, index: usize, deref_final: bool) -> Result<()> {
151 let pid = regs.pid() as u32;
152 let path = ctx.mem.read_cstr(pid, regs.arg(index))?;
153 if path.is_empty() {
154 return Ok(());
155 }
156 let host = translate_path(fs, pid, libc::AT_FDCWD, &path, deref_final)?;
157 if host != path {
158 let addr = push_cstr(ctx, regs, &host)?;
159 regs.set_arg(index, addr);
160 }
161 Ok(())
162}
163
164fn rewrite_sockaddr(ctx: &Ctx, fs: &Fs, regs: &mut Regs, deref_final: bool) -> Result<()> {
175 if let Some((addr, len)) =
176 translate_sockaddr(ctx, fs, regs, regs.arg(1), regs.arg(2) as usize, deref_final)?
177 {
178 regs.set_arg(1, addr);
179 regs.set_arg(2, len);
180 }
181 Ok(())
182}
183
184fn translate_sockaddr(
197 ctx: &Ctx,
198 fs: &Fs,
199 regs: &mut Regs,
200 addr: u64,
201 len: usize,
202 deref_final: bool,
203) -> Result<Option<(u64, u64)>> {
204 let pid = regs.pid() as u32;
205 if addr == 0 || len <= 2 || len > 110 {
206 return Ok(None);
207 }
208 let mut sa = vec![0u8; len];
209 ctx.mem.read(pid, addr, &mut sa)?;
210 if u16::from_ne_bytes([sa[0], sa[1]]) != libc::AF_UNIX as u16 || sa[2] == 0 {
211 return Ok(None);
212 }
213 let end = sa[2..].iter().position(|&b| b == 0).map(|p| p + 2).unwrap_or(len);
214 let path = &sa[2..end];
215 let host = translate_path(fs, pid, libc::AT_FDCWD, path, deref_final)?;
216 if host == path {
217 return Ok(None);
218 }
219 if host.len() >= 108 {
220 return Err(libc::ENAMETOOLONG);
221 }
222 let mut new = vec![0u8; 2 + host.len() + 1];
223 new[0..2].copy_from_slice(&(libc::AF_UNIX as u16).to_ne_bytes());
224 new[2..2 + host.len()].copy_from_slice(&host);
225 let slot = regs.alloc_stack(new.len() as u64);
226 ctx.mem.write(pid, slot, &new)?;
227 Ok(Some((slot, new.len() as u64)))
228}
229
230fn rewrite_socketcall(ctx: &Ctx, fs: &Fs, regs: &mut Regs) -> Result<()> {
241 let pid = regs.pid() as u32;
242 let call = regs.arg(0);
243 let args_ptr = regs.arg(1);
244 let mut raw = [0u8; 12];
245 ctx.mem.read(pid, args_ptr, &mut raw)?;
246 let word = |i: usize| u32::from_ne_bytes(raw[i * 4..i * 4 + 4].try_into().unwrap()) as u64;
247 let (fd, addr, len) = (word(0), word(1), word(2) as usize);
248 let deref_final = call == 3;
249 if let Some((new_addr, new_len)) = translate_sockaddr(ctx, fs, regs, addr, len, deref_final)? {
250 let mut new_args = [0u8; 12];
251 new_args[0..4].copy_from_slice(&(fd as u32).to_ne_bytes());
252 new_args[4..8].copy_from_slice(&(new_addr as u32).to_ne_bytes());
253 new_args[8..12].copy_from_slice(&(new_len as u32).to_ne_bytes());
254 let slot = regs.alloc_stack(12);
255 ctx.mem.write(pid, slot, &new_args)?;
256 regs.set_arg(1, slot);
257 }
258 Ok(())
259}