@@ -7,7 +7,7 @@ extern crate sys_util;
7
7
use std:: io;
8
8
use std:: result:: Result ;
9
9
10
- use libc:: { _exit, c_int, c_void, siginfo_t, SIGSYS } ;
10
+ use libc:: { _exit, c_int, c_void, siginfo_t, SIGBUS , SIGSEGV , SIGSYS } ;
11
11
12
12
use logger:: { Metric , LOGGER , METRICS } ;
13
13
use sys_util:: register_signal_handler;
@@ -53,12 +53,49 @@ extern "C" fn sigsys_handler(num: c_int, info: *mut siginfo_t, _unused: *mut c_v
53
53
} ;
54
54
}
55
55
56
+ extern "C" fn sigbus_sigsegv_handler ( num : c_int , info : * mut siginfo_t , _unused : * mut c_void ) {
57
+ // Safe because we're just reading some fields from a supposedly valid argument.
58
+ let si_signo = unsafe { ( * info) . si_signo } ;
59
+ let si_code = unsafe { ( * info) . si_code } ;
60
+
61
+ // Sanity check. The condition should never be true.
62
+ if num != si_signo || ( num != SIGBUS && num != SIGSEGV ) {
63
+ // Safe because we're terminating the process anyway.
64
+ unsafe { _exit ( i32:: from ( super :: FC_EXIT_CODE_UNEXPECTED_ERROR ) ) } ;
65
+ }
66
+
67
+ // Other signals which might do async unsafe things incompatible with the rest of this
68
+ // function are blocked due to the sa_mask used when registering the signal handler.
69
+ error ! (
70
+ "Shutting down VM after intercepting signal {}, code {}." ,
71
+ si_signo, si_code
72
+ ) ;
73
+ // Log the metrics before exiting.
74
+ if let Err ( e) = LOGGER . log_metrics ( ) {
75
+ error ! ( "Failed to log metrics while stopping: {}" , e) ;
76
+ }
77
+
78
+ // Safe because we're terminating the process anyway. We don't actually do anything when
79
+ // running unit tests.
80
+ #[ cfg( not( test) ) ]
81
+ unsafe {
82
+ _exit ( i32:: from ( match si_signo {
83
+ SIGBUS => super :: FC_EXIT_CODE_SIGBUS ,
84
+ SIGSEGV => super :: FC_EXIT_CODE_SIGSEGV ,
85
+ _ => super :: FC_EXIT_CODE_UNEXPECTED_ERROR ,
86
+ } ) )
87
+ } ;
88
+ }
89
+
56
90
/// Registers all the required signal handlers.
57
91
///
58
- /// Custom handlers are installed for: `SIGSYS`.
92
+ /// Custom handlers are installed for: `SIGBUS`, `SIGSEGV`, ` SIGSYS`.
59
93
///
60
94
pub fn register_signal_handlers ( ) -> Result < ( ) , io:: Error > {
61
- register_signal_handler ( SIGSYS , sigsys_handler)
95
+ register_signal_handler ( SIGSYS , sigsys_handler) ?;
96
+ register_signal_handler ( SIGBUS , sigbus_sigsegv_handler) ?;
97
+ register_signal_handler ( SIGSEGV , sigbus_sigsegv_handler) ?;
98
+ Ok ( ( ) )
62
99
}
63
100
64
101
#[ cfg( test) ]
@@ -104,6 +141,8 @@ mod tests {
104
141
allow_syscall( libc:: SYS_brk ) ,
105
142
allow_syscall( libc:: SYS_exit ) ,
106
143
allow_syscall( libc:: SYS_futex ) ,
144
+ allow_syscall( libc:: SYS_getpid ) ,
145
+ allow_syscall( libc:: SYS_kill ) ,
107
146
allow_syscall( libc:: SYS_munmap ) ,
108
147
allow_syscall( libc:: SYS_rt_sigprocmask ) ,
109
148
allow_syscall( libc:: SYS_rt_sigreturn ) ,
@@ -136,5 +175,11 @@ mod tests {
136
175
// The signal handler should let the program continue during unit tests.
137
176
assert_eq ! ( METRICS . seccomp. num_faults. count( ) , 1 ) ;
138
177
}
178
+
179
+ // Assert that the SIGBUS handler left the process alive.
180
+ unsafe {
181
+ syscall ( libc:: SYS_kill , process:: id ( ) , SIGBUS ) ;
182
+ }
183
+ assert ! ( true ) ;
139
184
}
140
185
}
0 commit comments