Skip to content

Commit

Permalink
feat(decl/proc-chain): add user and capabilities support
Browse files Browse the repository at this point in the history
Add the capability to specify the user and the linux capabilities
a process in the process chain can be run with. Capabilities can
only be specified for the leaf process. Omitting capabilities is
equivalent to specify 'all=iep'. Each process in the chain runs
with real user/group ID equals to 0 (root). Specifying a user sets
the effective and the saved set-user/group-ID to the corresponding
user/group IDs. If a user specified in the chain doesn't exist, it
is created before running the test and deleted after test
execution. The securebit SECBBIT_NOROOT is enabled before creating
any child process: this is done in order to prevent the kernel from
ignoring the specified capabilities when the real user ID is zero
(see 'Capabilities and execution of programs by root' in
capabilities(7)). Users who wish to run the before and after script
or creating a 'process' test resource  must take into account to
provide at least CAP_SETPCAP in its permitted and effective set.

Signed-off-by: Leonardo Di Giovanna <[email protected]>
  • Loading branch information
ekoops committed Nov 22, 2024
1 parent 955486a commit 46b490d
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 62 deletions.
47 changes: 21 additions & 26 deletions pkg/capability/capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package capability

import (
"errors"
"fmt"
"runtime"

Expand All @@ -30,37 +31,19 @@ func Parse(capabilities string) (*cap.Set, error) {
}

// RunWithSecBitNoRootEnabled runs the provided function with the thread secure bit SECBIT_NOROOT enabled.
func RunWithSecBitNoRootEnabled(f func() error) (err error) {
func RunWithSecBitNoRootEnabled(f func() error) error {
runtime.LockOSThread()
secureBits, err := unix.PrctlRetInt(unix.PR_GET_SECUREBITS, 0, 0, 0, 0)
if err != nil {
return fmt.Errorf("error retrieving thread secure bits: %w", err)
}

secureBitsPlusSecBitNoRoot := secureBits | int(cap.SecbitNoRoot)
if secureBits == secureBitsPlusSecBitNoRoot {
return runFuncAndWrapErr(f)
}

if err := unix.Prctl(unix.PR_SET_SECUREBITS, uintptr(secureBitsPlusSecBitNoRoot), 0, 0, 0); err != nil {
return fmt.Errorf("error setting thread secure bits: %w", err)
}
defer func() {
if e := unix.Prctl(unix.PR_SET_SECUREBITS, uintptr(secureBits), 0, 0, 0); e != nil {
e = fmt.Errorf("error restoring secure bits: %w", err)
if err != nil {
err = fmt.Errorf("%w; %w", err, e)
} else {
err = e
}
}
}()

return runFuncAndWrapErr(f)
return runWithSecBits(f, secureBits, secureBitsPlusSecBitNoRoot)
}

// RunWithSecBitNoRootDisabled runs the provided function with the thread secure bit SECBIT_NOROOT disable.
func RunWithSecBitNoRootDisabled(f func() error) (err error) {
// RunWithSecBitNoRootDisabled runs the provided function with the thread secure bit SECBIT_NOROOT disabled.
func RunWithSecBitNoRootDisabled(f func() error) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
secureBits, err := unix.PrctlRetInt(unix.PR_GET_SECUREBITS, 0, 0, 0, 0)
Expand All @@ -69,16 +52,28 @@ func RunWithSecBitNoRootDisabled(f func() error) (err error) {
}

secureBitsMinusSecBitNoRoot := secureBits & ^int(cap.SecbitNoRoot)
if secureBits == secureBitsMinusSecBitNoRoot {
return runWithSecBits(f, secureBits, secureBitsMinusSecBitNoRoot)
}

// runWithSecBits runs the provided function with the new secure bits set, and restores the old secure bits set at the
// end of its execution.
func runWithSecBits(f func() error, oldSecBits, newSecBits int) (err error) {
if oldSecBits == newSecBits {
return runFuncAndWrapErr(f)
}

if err := unix.Prctl(unix.PR_SET_SECUREBITS, uintptr(secureBitsMinusSecBitNoRoot), 0, 0, 0); err != nil {
if err := unix.Prctl(unix.PR_SET_SECUREBITS, uintptr(newSecBits), 0, 0, 0); err != nil {
if errors.Is(err, unix.EPERM) {
err = fmt.Errorf("%w (consider adding the CAP_SETPCAP capability)", err)
}
return fmt.Errorf("error setting thread secure bits: %w", err)
}
defer func() {
if e := unix.Prctl(unix.PR_SET_SECUREBITS, uintptr(secureBits), 0, 0, 0); e != nil {
e = fmt.Errorf("error restoring secure bits: %w", err)
if e := unix.Prctl(unix.PR_SET_SECUREBITS, uintptr(oldSecBits), 0, 0, 0); e != nil {
if errors.Is(e, unix.EPERM) {
e = fmt.Errorf("%w (consider adding the CAP_SETPCAP capability)", e)
}
e = fmt.Errorf("error restoring thread secure bits: %w", e)
if err != nil {
err = fmt.Errorf("%w; %w", err, e)
} else {
Expand Down
Loading

0 comments on commit 46b490d

Please sign in to comment.