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