@@ -12,29 +12,46 @@ use nix::{
12
12
unistd:: Pid ,
13
13
} ;
14
14
use std:: collections:: HashMap ;
15
+ use std:: path:: PathBuf ;
15
16
use tiny_nix_ipc:: Socket ;
17
+ use rand:: Rng ;
16
18
17
19
struct ChildInfo {
18
20
in_syscall : bool ,
19
21
}
20
22
21
- fn decode_syscall_args ( regs : libc:: user_regs_struct ) -> RawSyscall {
23
+ fn decode_syscall_args ( regs : & libc:: user_regs_struct ) -> RawSyscall {
22
24
let mut out = RawSyscall {
23
25
syscall_id : 0 ,
24
26
args : [ 0 ; 6 ] ,
25
27
ret : 0 ,
28
+ is_spoiled : false
26
29
} ;
27
30
out. ret = regs. rax ;
28
- out. syscall_id = regs. orig_rax ;
31
+ out. syscall_id = regs. orig_rax & 0xffffffu64 ;
29
32
out. args [ 0 ] = regs. rdi ;
30
33
out. args [ 1 ] = regs. rsi ;
31
34
out. args [ 2 ] = regs. rdx ;
32
35
out. args [ 3 ] = regs. r10 ;
33
36
out. args [ 4 ] = regs. r8 ;
34
37
out. args [ 5 ] = regs. r9 ;
38
+ out. is_spoiled = ( regs. orig_rax & 0x1000000u64 ) != 0 ;
35
39
out
36
40
}
37
41
42
+ fn spoil ( pid : Pid , regs : libc:: user_regs_struct ) -> Result < ( ) , nix:: Error > {
43
+ let mut regs = regs;
44
+ regs. rax = regs. orig_rax | 0x1000000u64 ;
45
+ regs. orig_rax = regs. rax ;
46
+ nix:: sys:: ptrace:: setregs ( pid, regs)
47
+ }
48
+
49
+ fn return_eio ( pid : Pid , regs : libc:: user_regs_struct ) -> Result < ( ) , nix:: Error > {
50
+ let mut regs = regs;
51
+ regs. rax = -( nix:: errno:: Errno :: EIO as i32 as i64 ) as u64 ;
52
+ nix:: sys:: ptrace:: setregs ( pid, regs)
53
+ }
54
+
38
55
fn process_syscall (
39
56
raw : & RawSyscall ,
40
57
proc : Pid ,
@@ -154,13 +171,30 @@ pub(crate) unsafe fn parent(
154
171
children. insert ( pid, new_info) ;
155
172
let regs = nix:: sys:: ptrace:: getregs ( Pid :: from_raw ( pid as i32 ) )
156
173
. context ( "ptrace getregs failed" ) ?;
157
- let params = decode_syscall_args ( regs) ;
174
+ let params = decode_syscall_args ( & regs) ;
158
175
let def = magic. lookup_syscall_by_id ( SyscallId ( params. syscall_id as u32 ) ) ;
159
176
let child_pid = Pid :: from_raw ( pid as i32 ) ;
160
177
let mut decoded_params = match def {
161
178
Some ( def) => process_syscall ( & params, child_pid, magic, def) ,
162
179
None => None ,
163
180
} ;
181
+ if decoded_params. is_some ( ) && ( params. syscall_id == 2 /*open*/ || params. syscall_id == 257 /*openat*/ ) { //TODO: x86_64 only
182
+ let decoded_params = decoded_params. as_ref ( ) . unwrap ( ) ;
183
+ let arg_id = if params. syscall_id == 2 { 0 } else { 1 } ;
184
+ let path: PathBuf = match & decoded_params. args [ arg_id] {
185
+ crate :: magic:: ty:: Value :: String ( s) => s,
186
+ _ => panic ! ( "open/openat with non-string argument" )
187
+ } . into ( ) ;
188
+ if started_syscall {
189
+ if settings. fail_path . is_some ( ) && path. starts_with ( settings. fail_path . as_ref ( ) . unwrap ( ) ) && rand:: thread_rng ( ) . gen_range ( 0 , 100 ) == 0 {
190
+ spoil ( Pid :: from_raw ( pid as i32 ) , regs) . context ( "spoil failed" ) ?;
191
+ }
192
+ } else {
193
+ if params. is_spoiled {
194
+ return_eio ( Pid :: from_raw ( pid as i32 ) , regs) . context ( "return -EIO failed" ) ?;
195
+ }
196
+ }
197
+ }
164
198
decoded_params. as_mut ( ) . map ( |p| {
165
199
// attach backtrace if requested
166
200
if settings. capture_backtrace {
0 commit comments