rust-vmm / seccompiler Goto Github PK
View Code? Open in Web Editor NEWProvides easy-to-use Linux seccomp-bpf jailing.
Home Page: https://crates.io/crates/seccompiler
License: Apache License 2.0
Provides easy-to-use Linux seccomp-bpf jailing.
Home Page: https://crates.io/crates/seccompiler
License: Apache License 2.0
Hi.
I have a question about seccomp. can we use seccomp as system-wide and trace all processes on system?
As far as I know, it can only be used with forking main process and exec certain process to trace or be restricted. how can we use this for all processes?
thank you.
Hi! I'm the author of extrasafe, a Rust wrapper around seccomp (and soon landlock as well, hopefully). I'm looking to switch from libseccomp-rs to seccompiler, mostly to make static compilation easier.
libseccomp supports the SECCOMP_FILTER_FLAG_TSYNC flag, which is a flag you can pass when calling the seccomp syscall directly. It allows you to apply the current seccomp filter to all running threads (TSYNC = thread sync).
Libseccomp achieves this by calling the seccomp syscall directly. It seems that seccompiler uses prctrl to enable seccomp, so in addition to adding a new flag to seccompiler::apply_filter
, it would also need to be modified to call the syscall itself rather than using prctl.
If you'd be open to accepting a patch I'd be glad to make it - maybe just extracting the body of apply_filter into a new function apply_filter_with_flags
, changing it to use the seccomp syscall, and then having apply_filter just proxy to apply_filter_with_flags
with empty flags.
If you have a better design or don't want to support it at all, that's fine, just let me know!
Just for reference (mostly for me), here's a convenient link to the seccomp syscall manpage
And here's the libseccomp code that calls the seccomp syscall directly, passing in the flags. See the few lines above it for where the flags are set: https://github.com/seccomp/libseccomp/blob/f1c3196d9b95de22dde8f23c5befcbeabef5711c/src/system.c#L414
Without this we need to add boiler plate code when creating custom filters:
....
SeccompFilter::new(
rules.into_iter().collect(),
SeccompAction::Trap,
SeccompAction::Allow,
ARCH.try_into().unwrap(),
)
.map_err(Error::Backend)?
.try_into()
.map_err(Error::Backend)
If we implement From, then this could be simplified by just having:
SeccompFilter::new(
rules.into_iter().collect(),
SeccompAction::Trap,
SeccompAction::Allow,
ARCH.try_into().unwrap(),
)?
.try_into()
In the case where the SeccompFilter rules are generated from a list of (syscall, Vec<SeccompRule)
(as in the doc examples), if a syscall is repeated with different args, the later rule will silently overwrite the earlier one. This is a limitation of the Vec->BTreeMap collect
implemenation. Given that rules
is converted into an iterator over (syscall, Vec<SeccompRule)
during try_from the use of a map doesn't seem to add anything.
This has implications for ease-of-use of the library. I came across this issue when implementing a port of OpenBSD pledge(). In pledge()
semantics, promises are additive; cpath
adds the ability to call open()
with O_CREAT
, and wpath
allows open()
with O_WRONLY
; to open and then write a file you would need to specify both.
The simplest way to implement this is a separate whitelist for each case, and then chain them together as needed, e.g:
let cpath = vec![(
libc::SYS_open,
vec![
Rule::new(vec![
Cond::new(
1,
ArgLen::Dword,
CmpOp::MaskedEq(libc::O_CREAT as u64),
libc::O_CREAT as u64,
)?])?,
])];
let wpath = vec![(
libc::SYS_open,
vec![
Rule::new(vec![Cond::new(
1,
ArgLen::Dword,
CmpOp::MaskedEq(libc::O_ACCMODE as u64),
libc::O_WRONLY as u64,
)?])?,
],
)];
// This list would actually be based on caller parameters
let rules: Vec<(i64, Vec<Rule>)> = cpath.into_iter()
.chain(wpath)
.collect();
let sf = SeccompFilter::new(
rules.into_iter().collect(),
Action::KillProcess,
Action::Allow,
ARCH.try_into()?,
)?;
However the use of BTreeMap means the cpath
rule would be completely overwritten by the wpath
rule, and attempts to create the file would fail.
The simplest solution would be to use a Vec for the syscall rule list (i.e. just skip the BTreeMap conversion) and leave the partitioning of the syscall rules up the caller. I've already tried this with v0.3.0 and it works fine; I'm happy to raise a PR. However it would obviously be a breaking change for current users of the lib.
As doc.rs does not include documentation for optional features, I would suggest we add a section in the ## Example Usage
in which to let users know about this limitation, and propose that people open the docs locally by running the command:
cargo doc --open --all-features
related to: SubconsciousCompute/seccomp-pledge#5
dora@openwrtbuildpc:~/coderepo/openwrt/seccomp-pledge$ cargo build --release --target mips-unknown-linux-musl
Compiling serde v1.0.152
Compiling libc v0.2.139
Compiling serde_json v1.0.91
Compiling itoa v1.0.5
Compiling ryu v1.0.12
Compiling optional-fields-serde-macro v0.1.1
Compiling optional-field v0.1.3
Compiling seccompiler v0.3.0
Compiling seccomp-pledge v0.1.0 (/home/dora/coderepo/openwrt/seccomp-pledge)
error[E0432]: unresolved import `seccompiler::BpfMap`
--> src/main.rs:2:5
|
2 | use seccompiler::BpfMap;
| ^^^^^^^^^^^^^^^^^^^ no `BpfMap` in the root
error[E0433]: failed to resolve: could not find `TargetArch` in `seccompiler`
--> src/main.rs:411:22
|
411 | seccompiler::TargetArch::x86_64,
| ^^^^^^^^^^ could not find `TargetArch` in `seccompiler`
error[E0425]: cannot find function `compile_from_json` in crate `seccompiler`
--> src/main.rs:409:66
|
409 | ...compiler::compile_from_json(
| ^^^^^^^^^^^^^^^^^ not found in `seccompiler`
error[E0425]: cannot find function `apply_filter` in crate `seccompiler`
--> src/main.rs:428:21
|
428 | if seccompiler::apply_filter(filter).is_err() {
| ^^^^^^^^^^^^ not found in `seccompiler`
Some errors have detailed explanations: E0425, E0432, E0433.
For more information about an error, try `rustc --explain E0425`.
error: could not compile `seccomp-pledge` due to 4 previous errors
dora@openwrtbuildpc:~/coderepo/openwrt/seccomp-pledge$
I think the issue is in the linker during cross compiling, seccompiler doesn’t define a linker target for mips https://github.com/rust-vmm/seccompiler/blob/main/.cargo/config, I found this that can help though rust-lang/rust#37507 (comment)
Hello, I'm writing concerning the following quote from the docs:
Before installing a filter, make sure that the current kernel version supports the actions of the filter. This can be checked by inspecting the output of:
cat /proc/sys/kernel/seccomp/actions_avail
or by calling theseccomp(SECCOMP_GET_ACTION_AVAIL)
syscall.
Are there any examples of using the second method in practice (seccomp(SECCOMP_GET_ACTION_AVAIL)
syscall)? It seems like seccompiler
does not expose any way to do this (would be nice if it did but maybe out of scope?), so it seems like I have to either:
libc
to get SECCOMP_GET_ACTION_AVAIL
, orIf you know of any code that already does this it would save me time, and it could be a useful addition to the docs. :)
The seccompiler code is now ready for a first release and satisfies the checklist here: https://github.com/rust-vmm/community#publishing-on-cratesio---requirements-list
One thing I'd like to do before publishing the crate is resolve this suggestion: #23
Is it basically always okay to use SeccompCmpArgLen::Qword on 64 bit systems? I'm doing so in my tests and I don't seem to see any issues, but I also don't have anything close to exhaustive tests of all syscalls.
Libseccomp seems to always do the full 64 bit comparison on 64 bit systems: https://github.com/seccomp/libseccomp/blob/main/src/db.c#L1665
I don't have any plans currently to support 32 bit systems but I'm just not sure when I might encounter issues. Does it exist basically so that the backend can generate either 32 or 64 bit ebpf regardless of what the host architecture is? i.e. When actually running the ebpf, you should always use Qword on 64 bit systems and Dword on 32 bit systems?
At the moment, it's not possible to filter both. If a filtered program call a 32 bits program, it will result in a bad system call. In libseccomp, one can differentiate between the 2 by checking for __X32_SYSCALL_BIT
mask on the system call number. It would be very useful for my use case, filtering calls from a sandbox environment that may use 32 bits applications.
i want to monitor all syscall and print the args value.
can anyone help me.
As mentioned in #58 once rust-lang/libc#3343 lands we should use libc's constants instead of redefining them.
https://github.com/rust-vmm/seccompiler/blob/main/src/backend/bpf.rs#L116
and SECCOMP_SET_MODE_FILTER which is being added to lib.rs in #58
The PR template says:
All commits in this PR are signed (with
git commit -s
)
As someone who doesn’t tend to remember which one is -s
and which one is -S
, I found this wording confusing: IMO the word “signed”, on its own, means cryptographically signed, i.e. -S
; I think this is probably the more common understanding. IMO something like “signed off” would be sufficient to eliminate the confusion, though there might be other rewordings that would be even more clear.
Currently it is not possible to only allow certain values in a filter that is permissive. If we had x in [values]
and x not_in [values]
operators, it would be possible to express such conditions. Currently we have to list all values that we want to deny. Example of the proposed:
"enable_only_inet": {
"mismatch_action": "allow",
"match_action": { "errno": 1},
"filter": [
{
"syscall": "socket",
"args": [
{
"index": 0,
"type": "dword",
"op", "not_in"
"val": [2, 10],
"comment": "deny all except AF_INET or AF_INET6"
}
]
}
]
}
Hi, I was wondering if you'd consider publishing a new version so that the apply_to_all_threads function is available for use in my own crate.
The errno
value in the mismatch_action
needs to be positive:
JsonFrontend(SerdeJson(Error("invalid value: integer `-1`, expected u32", line: 5, column: 0)))
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.