@@ -6,68 +6,117 @@ use libc::{self, c_void, c_long, siginfo_t};
6
6
use :: unistd:: Pid ;
7
7
use sys:: signal:: Signal ;
8
8
9
- pub mod ptrace {
10
- use libc:: c_int;
11
-
12
- cfg_if ! {
13
- if #[ cfg( any( all( target_os = "linux" , arch = "s390x" ) ,
14
- all( target_os = "linux" , target_env = "gnu" ) ) ) ] {
15
- pub type PtraceRequest = :: libc:: c_uint;
16
- } else {
17
- pub type PtraceRequest = c_int;
18
- }
9
+
10
+ cfg_if ! {
11
+ if #[ cfg( any( all( target_os = "linux" , arch = "s390x" ) ,
12
+ all( target_os = "linux" , target_env = "gnu" ) ) ) ] {
13
+ #[ doc( hidden) ]
14
+ pub type RequestType = :: libc:: c_uint;
15
+ } else {
16
+ #[ doc( hidden) ]
17
+ pub type RequestType = :: libc:: c_int;
18
+ }
19
+ }
20
+
21
+ libc_enum ! {
22
+ #[ cfg_attr( not( any( target_env = "musl" , target_os = "android" ) ) , repr( u32 ) ) ]
23
+ #[ cfg_attr( any( target_env = "musl" , target_os = "android" ) , repr( i32 ) ) ]
24
+ /// Ptrace Request enum defining the action to be taken.
25
+ pub enum Request {
26
+ PTRACE_TRACEME ,
27
+ PTRACE_PEEKTEXT ,
28
+ PTRACE_PEEKDATA ,
29
+ PTRACE_PEEKUSER ,
30
+ PTRACE_POKETEXT ,
31
+ PTRACE_POKEDATA ,
32
+ PTRACE_POKEUSER ,
33
+ PTRACE_CONT ,
34
+ PTRACE_KILL ,
35
+ PTRACE_SINGLESTEP ,
36
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" , target_arch = "s390x" ) , not( target_os = "android" ) ) ) ]
37
+ PTRACE_GETREGS ,
38
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" , target_arch = "s390x" ) , not( target_os = "android" ) ) ) ]
39
+ PTRACE_SETREGS ,
40
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" , target_arch = "s390x" ) , not( target_os = "android" ) ) ) ]
41
+ PTRACE_GETFPREGS ,
42
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" , target_arch = "s390x" ) , not( target_os = "android" ) ) ) ]
43
+ PTRACE_SETFPREGS ,
44
+ PTRACE_ATTACH ,
45
+ PTRACE_DETACH ,
46
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" ) , not( target_os = "android" ) ) ) ]
47
+ PTRACE_GETFPXREGS ,
48
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" ) , not( target_os = "android" ) ) ) ]
49
+ PTRACE_SETFPXREGS ,
50
+ PTRACE_SYSCALL ,
51
+ PTRACE_SETOPTIONS ,
52
+ PTRACE_GETEVENTMSG ,
53
+ PTRACE_GETSIGINFO ,
54
+ PTRACE_SETSIGINFO ,
55
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" , target_arch = "s390x" ) , not( target_os = "android" ) ) ) ]
56
+ PTRACE_GETREGSET ,
57
+ #[ cfg( all( any( target_env = "musl" , target_arch ="x86_64" , target_arch = "s390x" ) , not( target_os = "android" ) ) ) ]
58
+ PTRACE_SETREGSET ,
59
+ #[ cfg( not( any( target_os = "android" , target_arch = "mips" , target_arch = "mips64" ) ) ) ]
60
+ PTRACE_SEIZE ,
61
+ #[ cfg( not( any( target_os = "android" , target_arch = "mips" , target_arch = "mips64" ) ) ) ]
62
+ PTRACE_INTERRUPT ,
63
+ #[ cfg( not( any( target_os = "android" , target_arch = "mips" , target_arch = "mips64" ) ) ) ]
64
+ PTRACE_LISTEN ,
65
+ #[ cfg( not( any( target_os = "android" , target_arch = "mips" , target_arch = "mips64" ) ) ) ]
66
+ PTRACE_PEEKSIGINFO ,
67
+ }
68
+ }
69
+
70
+ libc_enum ! {
71
+ #[ repr( i32 ) ]
72
+ /// Using the ptrace options the tracer can configure the tracee to stop
73
+ /// at certain events. This enum is used to define those events as defined
74
+ /// in `man ptrace`.
75
+ pub enum Event {
76
+ /// Event that stops before a return from fork or clone.
77
+ PTRACE_EVENT_FORK ,
78
+ /// Event that stops before a return from vfork or clone.
79
+ PTRACE_EVENT_VFORK ,
80
+ /// Event that stops before a return from clone.
81
+ PTRACE_EVENT_CLONE ,
82
+ /// Event that stops before a return from execve.
83
+ PTRACE_EVENT_EXEC ,
84
+ /// Event for a return from vfork.
85
+ PTRACE_EVENT_VFORK_DONE ,
86
+ /// Event for a stop before an exit. Unlike the waitpid Exit status program.
87
+ /// registers can still be examined
88
+ PTRACE_EVENT_EXIT ,
89
+ /// STop triggered by a seccomp rule on a tracee.
90
+ PTRACE_EVENT_SECCOMP ,
91
+ // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26
19
92
}
93
+ }
20
94
21
- pub const PTRACE_TRACEME : PtraceRequest = 0 ;
22
- pub const PTRACE_PEEKTEXT : PtraceRequest = 1 ;
23
- pub const PTRACE_PEEKDATA : PtraceRequest = 2 ;
24
- pub const PTRACE_PEEKUSER : PtraceRequest = 3 ;
25
- pub const PTRACE_POKETEXT : PtraceRequest = 4 ;
26
- pub const PTRACE_POKEDATA : PtraceRequest = 5 ;
27
- pub const PTRACE_POKEUSER : PtraceRequest = 6 ;
28
- pub const PTRACE_CONT : PtraceRequest = 7 ;
29
- pub const PTRACE_KILL : PtraceRequest = 8 ;
30
- pub const PTRACE_SINGLESTEP : PtraceRequest = 9 ;
31
- pub const PTRACE_GETREGS : PtraceRequest = 12 ;
32
- pub const PTRACE_SETREGS : PtraceRequest = 13 ;
33
- pub const PTRACE_GETFPREGS : PtraceRequest = 14 ;
34
- pub const PTRACE_SETFPREGS : PtraceRequest = 15 ;
35
- pub const PTRACE_ATTACH : PtraceRequest = 16 ;
36
- pub const PTRACE_DETACH : PtraceRequest = 17 ;
37
- pub const PTRACE_GETFPXREGS : PtraceRequest = 18 ;
38
- pub const PTRACE_SETFPXREGS : PtraceRequest = 19 ;
39
- pub const PTRACE_SYSCALL : PtraceRequest = 24 ;
40
- pub const PTRACE_SETOPTIONS : PtraceRequest = 0x4200 ;
41
- pub const PTRACE_GETEVENTMSG : PtraceRequest = 0x4201 ;
42
- pub const PTRACE_GETSIGINFO : PtraceRequest = 0x4202 ;
43
- pub const PTRACE_SETSIGINFO : PtraceRequest = 0x4203 ;
44
- pub const PTRACE_GETREGSET : PtraceRequest = 0x4204 ;
45
- pub const PTRACE_SETREGSET : PtraceRequest = 0x4205 ;
46
- pub const PTRACE_SEIZE : PtraceRequest = 0x4206 ;
47
- pub const PTRACE_INTERRUPT : PtraceRequest = 0x4207 ;
48
- pub const PTRACE_LISTEN : PtraceRequest = 0x4208 ;
49
- pub const PTRACE_PEEKSIGINFO : PtraceRequest = 0x4209 ;
50
-
51
- pub type PtraceEvent = c_int ;
52
-
53
- pub const PTRACE_EVENT_FORK : PtraceEvent = 1 ;
54
- pub const PTRACE_EVENT_VFORK : PtraceEvent = 2 ;
55
- pub const PTRACE_EVENT_CLONE : PtraceEvent = 3 ;
56
- pub const PTRACE_EVENT_EXEC : PtraceEvent = 4 ;
57
- pub const PTRACE_EVENT_VFORK_DONE : PtraceEvent = 5 ;
58
- pub const PTRACE_EVENT_EXIT : PtraceEvent = 6 ;
59
- pub const PTRACE_EVENT_SECCOMP : PtraceEvent = 6 ;
60
- pub const PTRACE_EVENT_STOP : PtraceEvent = 128 ;
61
-
62
- pub type PtraceOptions = c_int ;
63
- pub const PTRACE_O_TRACESYSGOOD : PtraceOptions = 1 ;
64
- pub const PTRACE_O_TRACEFORK : PtraceOptions = ( 1 << PTRACE_EVENT_FORK ) ;
65
- pub const PTRACE_O_TRACEVFORK : PtraceOptions = ( 1 << PTRACE_EVENT_VFORK ) ;
66
- pub const PTRACE_O_TRACECLONE : PtraceOptions = ( 1 << PTRACE_EVENT_CLONE ) ;
67
- pub const PTRACE_O_TRACEEXEC : PtraceOptions = ( 1 << PTRACE_EVENT_EXEC ) ;
68
- pub const PTRACE_O_TRACEVFORKDONE : PtraceOptions = ( 1 << PTRACE_EVENT_VFORK_DONE ) ;
69
- pub const PTRACE_O_TRACEEXIT : PtraceOptions = ( 1 << PTRACE_EVENT_EXIT ) ;
70
- pub const PTRACE_O_TRACESECCOMP : PtraceOptions = ( 1 << PTRACE_EVENT_SECCOMP ) ;
95
+ libc_bitflags ! {
96
+ /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
97
+ /// See `man ptrace` for more details.
98
+ pub struct Options : libc:: c_int {
99
+ /// When delivering system call traps set a bit to allow tracer to
100
+ /// distinguish between normal stops or syscall stops. May not work on
101
+ /// all systems.
102
+ PTRACE_O_TRACESYSGOOD ;
103
+ /// Stop tracee at next fork and start tracing the forked process.
104
+ PTRACE_O_TRACEFORK ;
105
+ /// Stop tracee at next vfork call and trace the vforked process.
106
+ PTRACE_O_TRACEVFORK ;
107
+ /// Stop tracee at next clone call and trace the cloned process.
108
+ PTRACE_O_TRACECLONE ;
109
+ /// Stop tracee at next execve call.
110
+ PTRACE_O_TRACEEXEC ;
111
+ /// Stop tracee at vfork completion.
112
+ PTRACE_O_TRACEVFORKDONE ;
113
+ /// Stop tracee at next exit call. Stops before exit commences allowing
114
+ /// tracer to see location of exit and register states.
115
+ PTRACE_O_TRACEEXIT ;
116
+ /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
117
+ /// details.
118
+ PTRACE_O_TRACESECCOMP ;
119
+ }
71
120
}
72
121
73
122
/// Performs a ptrace request. If the request in question is provided by a specialised function
@@ -76,20 +125,19 @@ pub mod ptrace {
76
125
since="0.10.0" ,
77
126
note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
78
127
) ]
79
- pub unsafe fn ptrace ( request : ptrace:: PtraceRequest , pid : Pid , addr : * mut c_void , data : * mut c_void ) -> Result < c_long > {
80
- use self :: ptrace:: * ;
81
-
128
+ pub unsafe fn ptrace ( request : Request , pid : Pid , addr : * mut c_void , data : * mut c_void ) -> Result < c_long > {
129
+ use self :: Request :: * ;
82
130
match request {
83
131
PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek ( request, pid, addr, data) ,
84
132
PTRACE_GETSIGINFO | PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS => Err ( Error :: UnsupportedOperation ) ,
85
133
_ => ptrace_other ( request, pid, addr, data)
86
134
}
87
135
}
88
136
89
- fn ptrace_peek ( request : ptrace :: PtraceRequest , pid : Pid , addr : * mut c_void , data : * mut c_void ) -> Result < c_long > {
137
+ fn ptrace_peek ( request : Request , pid : Pid , addr : * mut c_void , data : * mut c_void ) -> Result < c_long > {
90
138
let ret = unsafe {
91
139
Errno :: clear ( ) ;
92
- libc:: ptrace ( request, libc:: pid_t:: from ( pid) , addr, data)
140
+ libc:: ptrace ( request as RequestType , libc:: pid_t:: from ( pid) , addr, data)
93
141
} ;
94
142
match Errno :: result ( ret) {
95
143
Ok ( ..) | Err ( Error :: Sys ( Errno :: UnknownErrno ) ) => Ok ( ret) ,
@@ -101,45 +149,54 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data
101
149
/// Some ptrace get requests populate structs or larger elements than c_long
102
150
/// and therefore use the data field to return values. This function handles these
103
151
/// requests.
104
- fn ptrace_get_data < T > ( request : ptrace :: PtraceRequest , pid : Pid ) -> Result < T > {
152
+ fn ptrace_get_data < T > ( request : Request , pid : Pid ) -> Result < T > {
105
153
// Creates an uninitialized pointer to store result in
106
154
let data: T = unsafe { mem:: uninitialized ( ) } ;
107
- let res = unsafe { libc:: ptrace ( request, libc:: pid_t:: from ( pid) , ptr:: null_mut :: < T > ( ) , & data as * const _ as * const c_void ) } ;
155
+ let res = unsafe {
156
+ libc:: ptrace ( request as RequestType ,
157
+ libc:: pid_t:: from ( pid) ,
158
+ ptr:: null_mut :: < T > ( ) ,
159
+ & data as * const _ as * const c_void )
160
+ } ;
108
161
Errno :: result ( res) ?;
109
162
Ok ( data)
110
163
}
111
164
112
- unsafe fn ptrace_other ( request : ptrace :: PtraceRequest , pid : Pid , addr : * mut c_void , data : * mut c_void ) -> Result < c_long > {
113
- Errno :: result ( libc:: ptrace ( request, libc:: pid_t:: from ( pid) , addr, data) ) . map ( |_| 0 )
165
+ unsafe fn ptrace_other ( request : Request , pid : Pid , addr : * mut c_void , data : * mut c_void ) -> Result < c_long > {
166
+ Errno :: result ( libc:: ptrace ( request as RequestType , libc:: pid_t:: from ( pid) , addr, data) ) . map ( |_| 0 )
114
167
}
115
168
116
169
/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
117
- pub fn setoptions ( pid : Pid , options : ptrace:: PtraceOptions ) -> Result < ( ) > {
118
- use self :: ptrace:: * ;
170
+ pub fn setoptions ( pid : Pid , options : Options ) -> Result < ( ) > {
119
171
use std:: ptr;
120
172
121
- let res = unsafe { libc:: ptrace ( PTRACE_SETOPTIONS , libc:: pid_t:: from ( pid) , ptr:: null_mut :: < libc:: c_void > ( ) , options as * mut c_void ) } ;
173
+ let res = unsafe {
174
+ libc:: ptrace ( Request :: PTRACE_SETOPTIONS as RequestType ,
175
+ libc:: pid_t:: from ( pid) ,
176
+ ptr:: null_mut :: < libc:: c_void > ( ) ,
177
+ options. bits ( ) as * mut c_void )
178
+ } ;
122
179
Errno :: result ( res) . map ( |_| ( ) )
123
180
}
124
181
125
182
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
126
183
pub fn getevent ( pid : Pid ) -> Result < c_long > {
127
- use self :: ptrace:: * ;
128
- ptrace_get_data :: < c_long > ( PTRACE_GETEVENTMSG , pid)
184
+ ptrace_get_data :: < c_long > ( Request :: PTRACE_GETEVENTMSG , pid)
129
185
}
130
186
131
187
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
132
188
pub fn getsiginfo ( pid : Pid ) -> Result < siginfo_t > {
133
- use self :: ptrace:: * ;
134
- ptrace_get_data :: < siginfo_t > ( PTRACE_GETSIGINFO , pid)
189
+ ptrace_get_data :: < siginfo_t > ( Request :: PTRACE_GETSIGINFO , pid)
135
190
}
136
191
137
192
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
138
193
pub fn setsiginfo ( pid : Pid , sig : & siginfo_t ) -> Result < ( ) > {
139
- use self :: ptrace:: * ;
140
194
let ret = unsafe {
141
195
Errno :: clear ( ) ;
142
- libc:: ptrace ( PTRACE_SETSIGINFO , libc:: pid_t:: from ( pid) , ptr:: null_mut :: < libc:: c_void > ( ) , sig as * const _ as * const c_void )
196
+ libc:: ptrace ( Request :: PTRACE_SETSIGINFO as RequestType ,
197
+ libc:: pid_t:: from ( pid) ,
198
+ ptr:: null_mut :: < libc:: c_void > ( ) ,
199
+ sig as * const _ as * const c_void )
143
200
} ;
144
201
match Errno :: result ( ret) {
145
202
Ok ( _) => Ok ( ( ) ) ,
@@ -154,7 +211,7 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
154
211
pub fn traceme ( ) -> Result < ( ) > {
155
212
unsafe {
156
213
ptrace_other (
157
- ptrace :: PTRACE_TRACEME ,
214
+ Request :: PTRACE_TRACEME ,
158
215
Pid :: from_raw ( 0 ) ,
159
216
ptr:: null_mut ( ) ,
160
217
ptr:: null_mut ( ) ,
@@ -168,7 +225,7 @@ pub fn traceme() -> Result<()> {
168
225
pub fn syscall ( pid : Pid ) -> Result < ( ) > {
169
226
unsafe {
170
227
ptrace_other (
171
- ptrace :: PTRACE_SYSCALL ,
228
+ Request :: PTRACE_SYSCALL ,
172
229
pid,
173
230
ptr:: null_mut ( ) ,
174
231
ptr:: null_mut ( ) ,
@@ -182,14 +239,28 @@ pub fn syscall(pid: Pid) -> Result<()> {
182
239
pub fn attach ( pid : Pid ) -> Result < ( ) > {
183
240
unsafe {
184
241
ptrace_other (
185
- ptrace :: PTRACE_ATTACH ,
242
+ Request :: PTRACE_ATTACH ,
186
243
pid,
187
244
ptr:: null_mut ( ) ,
188
245
ptr:: null_mut ( ) ,
189
246
) . map ( |_| ( ) ) // ignore the useless return value
190
247
}
191
248
}
192
249
250
+ /// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
251
+ ///
252
+ /// Detaches from the process specified in pid allowing it to run freely
253
+ pub fn detach ( pid : Pid ) -> Result < ( ) > {
254
+ unsafe {
255
+ ptrace_other (
256
+ Request :: PTRACE_DETACH ,
257
+ pid,
258
+ ptr:: null_mut ( ) ,
259
+ ptr:: null_mut ( )
260
+ ) . map ( |_| ( ) )
261
+ }
262
+ }
263
+
193
264
/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
194
265
///
195
266
/// Continues the execution of the process with PID `pid`, optionally
@@ -200,7 +271,7 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
200
271
None => ptr:: null_mut ( ) ,
201
272
} ;
202
273
unsafe {
203
- ptrace_other ( ptrace :: PTRACE_CONT , pid, ptr:: null_mut ( ) , data) . map ( |_| ( ) ) // ignore the useless return value
274
+ ptrace_other ( Request :: PTRACE_CONT , pid, ptr:: null_mut ( ) , data) . map ( |_| ( ) ) // ignore the useless return value
204
275
}
205
276
}
206
277
0 commit comments