lucab / caps-rs

A pure-Rust library to work with Linux capabilities
https://docs.rs/caps
Other
83 stars 20 forks source link

Permitted set can be cleared but not set #28

Closed kpcyrd closed 6 years ago

kpcyrd commented 6 years ago

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).

lucab commented 6 years ago

Although surprising, I think this is normal kernel behavior. In particular, capabilities(7) manpage says:

The following rules govern changes to the thread capability sets: ...

  1. The new effective set must be a subset of the new permitted set.

I tried to respect this invariant in your sandbox explorer (which is great!) and it seems to work:

 [%]> id
uid=0 euid=0 suid=0 gid=0 egid=0 sgid=0 groups=[0]
 [%]> caps
{CAP_SYS_ADMIN, CAP_SETUID, CAP_SYS_BOOT, CAP_CHOWN, CAP_MAC_OVERRIDE, CAP_LINUX_IMMUTABLE, CAP_SYS_RESOURCE, CAP_FOWNER, CAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_LEASE, CAP_MKNOD, CAP_SYS_TIME, CAP_KILL, CAP_MAC_ADMIN, CAP_AUDIT_WRITE, CAP_SYSLOG, CAP_SETFCAP, CAP_SETGID, CAP_SYS_TTY_CONFIG, CAP_FSETID, CAP_NET_BROADCAST, CAP_DAC_READ_SEARCH, CAP_AUDIT_CONTROL, CAP_SYS_PTRACE, CAP_AUDIT_READ, CAP_SETPCAP, CAP_SYS_CHROOT, CAP_DAC_OVERRIDE, CAP_SYS_PACCT, CAP_IPC_OWNER, CAP_BLOCK_SUSPEND, CAP_NET_ADMIN, CAP_NET_RAW, CAP_NET_BIND_SERVICE, CAP_WAKE_ALARM, CAP_IPC_LOCK, CAP_SYS_NICE}
 [%]> caps -e -d CAP_SYS_NICE
 [%]> caps -d CAP_SYS_NICE
 [%]> caps
{CAP_SYS_BOOT, CAP_DAC_READ_SEARCH, CAP_SYS_RAWIO, CAP_IPC_OWNER, CAP_FOWNER, CAP_LEASE, CAP_SYS_MODULE, CAP_SYS_RESOURCE, CAP_SYS_ADMIN, CAP_CHOWN, CAP_MAC_ADMIN, CAP_MAC_OVERRIDE, CAP_NET_ADMIN, CAP_DAC_OVERRIDE, CAP_SETPCAP, CAP_SETFCAP, CAP_SYSLOG, CAP_AUDIT_CONTROL, CAP_NET_BROADCAST, CAP_SETGID, CAP_NET_RAW, CAP_SYS_TTY_CONFIG, CAP_SYS_CHROOT, CAP_AUDIT_READ, CAP_LINUX_IMMUTABLE, CAP_SYS_PACCT, CAP_KILL, CAP_WAKE_ALARM, CAP_BLOCK_SUSPEND, CAP_SETUID, CAP_AUDIT_WRITE, CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_SYS_PTRACE, CAP_FSETID, CAP_IPC_LOCK, CAP_SYS_TIME}
kpcyrd commented 6 years ago

Thank you. :)

I missed that while reading the man page, this answers my question. Also thanks for the example. :heart: