lucab / caps-rs Goto Github PK
View Code? Open in Web Editor NEWA pure-Rust library to work with Linux capabilities
Home Page: https://docs.rs/caps
License: Other
A pure-Rust library to work with Linux capabilities
Home Page: https://docs.rs/caps
License: Other
There are currently two new capabilities sitting in the net-next
tree which will land in a Linux version soon-ish, CAP_BPF
and CAP_PERFMON
:
I'm entirely unfamiliar with Rust but, attempting to compile railcar (https://github.com/oracle/railcar) on an armv7 device, throws errors in caps-rs that I suspect are due to the absence of armv7 target references in nr.rs
error[E0425]: cannot find value `CAPGET` in module `nr`
--> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/caps-0.0.1/src/base.rs:10:40
|
10 | let r = unsafe { libc::syscall(nr::CAPGET, hdr, data) };
| ^^^^^^ not found in `nr`
error[E0425]: cannot find value `CAPSET` in module `nr`
--> /root/.cargo/registry/src/github.com-1ecc6299db9ec823/caps-0.0.1/src/base.rs:18:40
|
18 | let r = unsafe { libc::syscall(nr::CAPSET, hdr, data) };
| ^^^^^^ not found in `nr`
I tried (!) with:
#[cfg(target_arch = "arm")]
pub const CAPGET: i32 = 184;
#[cfg(target_arch = "arm")]
pub const CAPSET: i32 = 185;
and this appears (!) to resolve the error; at least it permits the compilation to proceed further.
I'm uncertain:
target_arch
must be arm
for and not armv7
(as I'm using armv7-unknown-linux-gnueabihf)CAPGET
==184 and CAPSET
==185 but was unable to find a syscall listIs it even possible to support Darwin or the BSDs using equivalent APIs?
If you attempt to set capabilities in the Permitted capabilities set to a strict subset of the current capabilities without first dropping them in the Effective set, then this library returns an unhelpful error message CapsError("capset failure: Operation not permitted (os error 1)")
.
Under the hood, this library sets exactly what you tell it to and otherwise preserves the current state. This causes issues when using set
to drop a lot of capabilities at once (for my application, I only need a few capabilities, so it's easier to set
what I need than to clear
what I don't). If I immediately set the Permitted capabilities, then the syscall it produces tries to preserve the current Effective capabilities and set the Permitted capabilities, which produces an Effective set that is no longer a subset of the Permitted set (which isn't allowed, hence the error return).
I'd prefer if calling set
on the Permitted capabilities could also intersect the provided capabilities with the current Effective set and only set those Effective capabilities, so you can just make one call to set
to drop the capabilities. However, that would be changing the API in ways that I'm not sure if you'd want, so if that's not allowed, then I'd prefer for this failure mode to get a more descriptive error message (likely has to be manually inserted as a check before we syscall into the kernel) and for documentation of this limitation could be put into set
(and other methods if they also have this behavior).
hey! I've noticed that the crate is currently not able to retain capabilities across a uid transition. It might be useful to have a function that corresponds to:
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
Thanks for the crate! I'm trying to use it for Nix's CI tests. However, the build fails for powerpc64-unknown-linux-gnu, powerpc64le-unknown-linux-gnu, mips64-unknown-linux-gnu, and mips64el-unknown-linux-gnu.
Compiling caps v0.3.0
error[E0425]: cannot find value `CAPGET` in module `nr`
--> /cargo/registry/src/github.com-1ecc6299db9ec823/caps-0.3.0/src/base.rs:12:40
|
12 | let r = unsafe { libc::syscall(nr::CAPGET, hdr, data) };
| ^^^^^^ not found in `nr`
error[E0425]: cannot find value `CAPSET` in module `nr`
--> /cargo/registry/src/github.com-1ecc6299db9ec823/caps-0.3.0/src/base.rs:20:40
|
20 | let r = unsafe { libc::syscall(nr::CAPSET, hdr, data) };
| ^^^^^^ not found in `nr`
error: aborting due to 2 previous errors
error: Could not compile `caps`.
While testing the keepcaps code I noticed I'm not able to drop capabilities from the permitted set:
[%]> id
uid=0 euid=0 suid=0 gid=0 egid=0 sgid=0 groups=[0]
[%]> caps
{CAP_SYS_RAWIO, CAP_LINUX_IMMUTABLE, CAP_MAC_OVERRIDE, CAP_SETUID, CAP_DAC_OVERRIDE, CAP_NET_ADMIN, CAP_IPC_LOCK, CAP_CHOWN, CAP_SETFCAP, CAP_AUDIT_READ, CAP_SYS_TIME, CAP_FOWNER, CAP_SYS_CHROOT, CAP_WAKE_ALARM, CAP_BLOCK_SUSPEND, CAP_MKNOD, CAP_AUDIT_CONTROL, CAP_MAC_ADMIN, CAP_SYSLOG, CAP_NET_RAW, CAP_SYS_RESOURCE, CAP_NET_BIND_SERVICE, CAP_SYS_TTY_CONFIG, CAP_LEASE, CAP_SYS_BOOT, CAP_KILL, CAP_SYS_NICE, CAP_FSETID, CAP_SYS_MODULE, CAP_NET_BROADCAST, CAP_SYS_PTRACE, CAP_SETPCAP, CAP_SYS_PACCT, CAP_DAC_READ_SEARCH, CAP_SYS_ADMIN, CAP_SETGID, CAP_IPC_OWNER, CAP_AUDIT_WRITE}
[%]> caps -d CAP_SYS_NICE
error: Error(Caps(Error(Msg("capset error"), State { next_error: Some(Error(Sys(Errno { code: 1, description: Some("Operation not permitted") }), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })), backtrace: InternalBacktrace { backtrace: None } })), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })
[%]>
This translates to this call in rust:
caps::drop(None, CapSet::Permitted, cap)?;
I have the same issue with caps::set
(which is used by drop
under the hood). Dropping/Setting other capability sets is working correctly and I can also clear the permitted set using caps::clear(None, CapSet::Permitted)
.
At some point in the future I will re-evaluate how we define Capability
and CapsHashSet
and possibly switch to use https://docs.rs/bitflags/latest/bitflags/index.html for those.
Unfortunately, we I started writing this library, the types generated by bitflags
were not very ergonomic so it was better to go with a plain enum
plus HashSet
.
On the positive side, this will make the library a bit more lean, as flags manipulation will be done through integer arithmetic without allocating containers. However this is not really a pressing point, as capabilities introspection/manipulation is basically never done in any kind of hot-loop or sensitive spot.
On the negative side, this will require re-arranging most of the public interfaces and breaking the API. The latter cascades into all consumers of the library.
For these reasons I'm not currently going after this in the short term, but I'm leaving this open as a future working item.
Please include them and release new version.
custom-derive 0.1.7 was superseded by macro-attr 0.2. I tried updating it with this diff (using macro-attr 0.2.1 from git, because enum-derive 0.2 was not yet uploaded to crates.io):
diff --git a/Cargo.toml b/Cargo.toml
index 7dd5afc..481792f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,8 +15,8 @@ exclude = [
[dependencies]
libc = "0.2"
error-chain = {version = "0.9", default-features = false}
-enum_derive = "0.1"
-custom_derive ="0.1"
+enum_derive = {path = "../rust-custom-derive/enum_derive"}
+macro-attr = {path = "../rust-custom-derive"}
[package.metadata.release]
sign-commit = true
diff --git a/src/lib.rs b/src/lib.rs
index 7fa8772..db1df2e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -23,7 +23,7 @@ extern crate libc;
#[macro_use]
extern crate error_chain;
#[macro_use]
-extern crate custom_derive;
+extern crate macro_attr;
#[macro_use]
extern crate enum_derive;
@@ -61,7 +61,7 @@ pub enum CapSet {
Permitted,
}
-custom_derive! {
+macro_attr! {
/// Linux capabilities.
///
/// All capabilities supported by Linux, including standard
However cargo / rustc 1.19 gives me this error:
error: no rules expected the token `split_derive_attrs`
--> src/lib.rs:64:1
|
64 | / macro_attr! {
65 | | /// Linux capabilities.
66 | | ///
67 | | /// All capabilities supported by Linux, including standard
... |
138 | | }
139 | | }
| |_^
|
= note: this error originates in a macro outside of the current crate
error: Could not compile `caps`.
To learn more, run the command again with --verbose.
exit code 101
it's possible this is a bug in macro-attr (@split_derive_attrs is from there) but I'm not sure.
It would be nice if the error code in errno would be accessible if an error happens. The error currently looks like this:
Error(Msg("capset error -1"), State { next_error: None, backtrace: None })
This could be improved with the error code why it failed, like permission denied
. errno is useful for this.
The idea is to use the strum crate to be able to make the Capability
enum more compact and Rusty. This means that we could reduce this:
Lines 75 to 77 in cb54844
to
#[strum(serialize_all = "shouty_snake_case")]
/// All available capabilities.
pub enum Capability {
#[strum(serialize = "CHOWN", serialize = "CAP_CHOWN")]
// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
// overrides the restriction of changing file ownership and group ownership.
Chown,
We already use this method in containrs, which is a WIP project: https://github.com/cri-o/containrs/blob/master/src/capability.rs
Do you think this makes sense?
A new capability CAP_CHECKPOINT_RESTORE
(number 40
) just landed in the 5.9 merge window.
When trying to compile this crate on a x86_32
linux machine I get a type error because nr::{CapSet, CapGet}
are i64
but libc::syscall
expects an i32
.
Capturing my previous comment from #2 (comment).
This is a placeholder ticket, I will detail the scope of problem a bit more after initial investigation.
Currently, the error type is just a wrapper around String and the functions do not have descriptions on how they might fail either. It would be nice to have some information on error handling.
Release 0.3.0 introduced support for a single flag in securebits, namely SECBIT_KEEP_CAPS
.
There are three more flags missing, with their corresponding "locked" twins. All of those should be implemented via PR_SET_SECUREBITS
and PR_GET_SECUREBITS
.
This is a followup to #26.
This is an enhancement ticket to add run-time detection of ambient set support, which is only available on kernels >= 4.3.
The proposed signature is as follow:
pub fn ambient_set_supported() -> Result<(), Err(i32)>
(or maybe only a bool
which just swallows all errno into false
?)
This can be implement via PR_CAP_AMBIENT
+PR_CAP_AMBIENT_IS_SET
+CAP_CHOWN
which should always return >=0 when the set is supported.
/cc @vishvananda and @aep for feedback on the ergonomic/signature. This is intended to provide a simple way for consumers to opt out ambient-set manipulation on kernels where it is unsupported: a conditional on caps::ambient_set_supported().is_ok()
.
Is there any pending changes for 0.5.3? I think the serde
support is big enough feature.
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.