@@ -208,6 +208,10 @@ pub use backend::{
208
208
SeccompCmpOp , SeccompCondition , SeccompFilter , SeccompRule , TargetArch ,
209
209
} ;
210
210
211
+ // Until https://github.com/rust-lang/libc/issues/3342 is fixed, define locally
212
+ // From <linux/seccomp.h>
213
+ const SECCOMP_SET_MODE_FILTER : libc:: c_int = 1 ;
214
+
211
215
// BPF structure definition for filter array.
212
216
// See /usr/include/linux/filter.h .
213
217
#[ repr( C ) ]
@@ -231,6 +235,11 @@ pub enum Error {
231
235
EmptyFilter ,
232
236
/// System error related to calling `prctl`.
233
237
Prctl ( io:: Error ) ,
238
+ /// System error related to calling `seccomp` syscall.
239
+ Seccomp ( io:: Error ) ,
240
+ /// Returned when calling `seccomp` with the thread sync flag (TSYNC) fails. Contains the pid
241
+ /// of the thread that caused the failure.
242
+ ThreadSync ( libc:: c_long ) ,
234
243
/// Json Frontend Error.
235
244
#[ cfg( feature = "json" ) ]
236
245
JsonFrontend ( JsonFrontendError ) ,
@@ -243,6 +252,8 @@ impl std::error::Error for Error {
243
252
match self {
244
253
Backend ( error) => Some ( error) ,
245
254
Prctl ( error) => Some ( error) ,
255
+ Seccomp ( error) => Some ( error) ,
256
+ ThreadSync ( _) => None ,
246
257
#[ cfg( feature = "json" ) ]
247
258
JsonFrontend ( error) => Some ( error) ,
248
259
_ => None ,
@@ -264,6 +275,16 @@ impl Display for Error {
264
275
Prctl ( errno) => {
265
276
write ! ( f, "Error calling `prctl`: {}" , errno)
266
277
}
278
+ Seccomp ( errno) => {
279
+ write ! ( f, "Error calling `seccomp`: {}" , errno)
280
+ }
281
+ ThreadSync ( pid) => {
282
+ write ! (
283
+ f,
284
+ "Seccomp filter synchronization failed in thread `{}`" ,
285
+ pid
286
+ )
287
+ }
267
288
#[ cfg( feature = "json" ) ]
268
289
JsonFrontend ( error) => {
269
290
write ! ( f, "Json Frontend error: {}" , error)
@@ -292,6 +313,30 @@ impl From<JsonFrontendError> for Error {
292
313
///
293
314
/// [`BpfProgram`]: type.BpfProgram.html
294
315
pub fn apply_filter ( bpf_filter : BpfProgramRef ) -> Result < ( ) > {
316
+ apply_filter_with_flags ( bpf_filter, 0 )
317
+ }
318
+
319
+ /// Apply a BPF filter to the all threads in the process via the TSYNC feature. Please read the
320
+ /// man page for seccomp (`man 2 seccomp`) for more information.
321
+ ///
322
+ /// # Arguments
323
+ ///
324
+ /// * `bpf_filter` - A reference to the [`BpfProgram`] to be installed.
325
+ ///
326
+ /// [`BpfProgram`]: type.BpfProgram.html
327
+ pub fn apply_filter_all_threads ( bpf_filter : BpfProgramRef ) -> Result < ( ) > {
328
+ apply_filter_with_flags ( bpf_filter, libc:: SECCOMP_FILTER_FLAG_TSYNC )
329
+ }
330
+
331
+ /// Apply a BPF filter to the calling thread.
332
+ ///
333
+ /// # Arguments
334
+ ///
335
+ /// * `bpf_filter` - A reference to the [`BpfProgram`] to be installed.
336
+ /// * `flags` - A u64 representing a bitset of seccomp's flags parameter.
337
+ ///
338
+ /// [`BpfProgram`]: type.BpfProgram.html
339
+ fn apply_filter_with_flags ( bpf_filter : BpfProgramRef , flags : libc:: c_ulong ) -> Result < ( ) > {
295
340
// If the program is empty, don't install the filter.
296
341
if bpf_filter. is_empty ( ) {
297
342
return Err ( Error :: EmptyFilter ) ;
@@ -314,14 +359,21 @@ pub fn apply_filter(bpf_filter: BpfProgramRef) -> Result<()> {
314
359
// Safe because the kernel performs a `copy_from_user` on the filter and leaves the memory
315
360
// untouched. We can therefore use a reference to the BpfProgram, without needing ownership.
316
361
let rc = unsafe {
317
- libc:: prctl (
318
- libc:: PR_SET_SECCOMP ,
319
- libc:: SECCOMP_MODE_FILTER ,
362
+ libc:: syscall (
363
+ libc:: SYS_seccomp ,
364
+ SECCOMP_SET_MODE_FILTER ,
365
+ flags,
320
366
bpf_prog_ptr,
321
367
)
322
368
} ;
323
- if rc != 0 {
324
- return Err ( Error :: Prctl ( io:: Error :: last_os_error ( ) ) ) ;
369
+
370
+ #[ allow( clippy:: comparison_chain) ]
371
+ // Per manpage, if TSYNC fails, retcode is >0 and equals the pid of the thread that caused the
372
+ // failure. Otherwise, error code is -1 and errno is set.
373
+ if rc < 0 {
374
+ return Err ( Error :: Seccomp ( io:: Error :: last_os_error ( ) ) ) ;
375
+ } else if rc > 0 {
376
+ return Err ( Error :: ThreadSync ( rc) ) ;
325
377
}
326
378
327
379
Ok ( ( ) )
0 commit comments