| package cap |
| |
| import ( |
| "errors" |
| "syscall" |
| "unsafe" |
| ) |
| |
| // This file contains convenience functions for libcap, to help |
| // users do the right thing with respect to capabilities for |
| // common actions. |
| |
| // Secbits capture the prctl settable secure-bits of a process. |
| type Secbits uint |
| |
| // SecbitNoRoot etc are the bitmasks associated with the supported |
| // Secbit masks. Source: uapi/linux/securebits.h |
| const ( |
| SecbitNoRoot Secbits = 1 << iota |
| SecbitNoRootLocked |
| SecbitNoSetUIDFixup |
| SecbitNoSetUIDFixupLocked |
| SecbitKeepCaps |
| SecbitKeepCapsLocked |
| SecbitNoCapAmbientRaise |
| SecbitNoCapAmbientRaiseLocked |
| ) |
| |
| const ( |
| securedBasicBits = SecbitNoRoot | SecbitNoRootLocked | SecbitNoSetUIDFixup | SecbitNoSetUIDFixupLocked | SecbitKeepCapsLocked |
| securedAmbientBits = securedBasicBits | SecbitNoCapAmbientRaise | SecbitNoCapAmbientRaiseLocked |
| ) |
| |
| // defines from uapi/linux/prctl.h |
| const ( |
| prSetKeepCaps = 8 |
| prGetSecureBits = 27 |
| prSetSecureBits = 28 |
| prSetNoNewPrivs = 38 |
| ) |
| |
| // GetSecbits returns the current setting of the process' Secbits. |
| func GetSecbits() Secbits { |
| v, err := multisc.prctlrcall(prGetSecureBits, 0, 0) |
| if err != nil { |
| panic(err) |
| } |
| return Secbits(v) |
| } |
| |
| func (sc *syscaller) setSecbits(s Secbits) error { |
| _, err := sc.prctlwcall(prSetSecureBits, uintptr(s), 0) |
| return err |
| } |
| |
| // Set attempts to force the process Secbits to a value. This function |
| // will raise cap.SETPCAP in order to achieve this operation, and will |
| // completely lower the Effective vector of the process returning. |
| func (s Secbits) Set() error { |
| scwMu.Lock() |
| defer scwMu.Unlock() |
| return multisc.setSecbits(s) |
| } |
| |
| // Mode summarizes a complicated secure-bits and capability mode in a |
| // libcap preferred way. |
| type Mode uint |
| |
| // ModeUncertain etc are how libcap summarizes security modes |
| // involving capabilities and secure-bits. |
| const ( |
| ModeUncertain Mode = iota |
| ModeNoPriv |
| ModePure1EInit |
| ModePure1E |
| ) |
| |
| // GetMode assesses the current process state and summarizes it as |
| // a Mode. This function always succeeds. Unfamiliar modes are |
| // declared ModeUncertain. |
| func GetMode() Mode { |
| b := GetSecbits() |
| if b&securedBasicBits != securedBasicBits { |
| return ModeUncertain |
| } |
| |
| for c := Value(0); ; c++ { |
| v, err := GetAmbient(c) |
| if err != nil { |
| if c != 0 && b != securedAmbientBits { |
| return ModeUncertain |
| } |
| break |
| } |
| if v { |
| return ModeUncertain |
| } |
| } |
| |
| w := GetProc() |
| e := NewSet() |
| cf, _ := w.Compare(e) |
| |
| if Differs(cf, Inheritable) { |
| return ModePure1E |
| } |
| if Differs(cf, Permitted) || Differs(cf, Effective) { |
| return ModePure1EInit |
| } |
| |
| for c := Value(0); ; c++ { |
| v, err := GetBound(c) |
| if err != nil { |
| break |
| } |
| if v { |
| return ModePure1EInit |
| } |
| } |
| |
| return ModeNoPriv |
| } |
| |
| // ErrBadMode is the error returned when an attempt is made to set an |
| // unrecognized libcap security mode. |
| var ErrBadMode = errors.New("unsupported mode") |
| |
| func (sc *syscaller) setMode(m Mode) error { |
| w := GetProc() |
| defer func() { |
| w.ClearFlag(Effective) |
| sc.setProc(w) |
| }() |
| |
| if err := w.SetFlag(Effective, true, SETPCAP); err != nil { |
| return err |
| } |
| if err := sc.setProc(w); err != nil { |
| return err |
| } |
| |
| if m == ModeNoPriv || m == ModePure1EInit { |
| w.ClearFlag(Inheritable) |
| } else if m != ModePure1E { |
| return ErrBadMode |
| } |
| |
| sb := securedAmbientBits |
| if _, err := GetAmbient(0); err != nil { |
| sb = securedBasicBits |
| } else if err := sc.resetAmbient(); err != nil { |
| return err |
| } |
| |
| if err := sc.setSecbits(sb); err != nil { |
| return err |
| } |
| |
| if m != ModeNoPriv { |
| return nil |
| } |
| |
| for c := Value(0); sc.dropBound(c) == nil; c++ { |
| } |
| w.ClearFlag(Permitted) |
| |
| // For good measure. |
| sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0) |
| |
| return nil |
| } |
| |
| // Set attempts to enter the specified mode. An attempt is made to |
| // enter the mode, so if you prefer this operation to be a no-op if |
| // entering the same mode, call only if CurrentMode() disagrees with |
| // the desired mode. |
| // |
| // This function will raise cap.SETPCAP in order to achieve this |
| // operation, and will completely lower the Effective Flag of the |
| // process' Set before returning. This function may fail for lack of |
| // permission or because (some of) the Secbits are already locked for |
| // the current process. |
| func (m Mode) Set() error { |
| scwMu.Lock() |
| defer scwMu.Unlock() |
| return multisc.setMode(m) |
| } |
| |
| // String returns the libcap conventional string for this mode. |
| func (m Mode) String() string { |
| switch m { |
| case ModeUncertain: |
| return "UNCERTAIN" |
| case ModeNoPriv: |
| return "NOPRIV" |
| case ModePure1EInit: |
| return "PURE1E_INIT" |
| case ModePure1E: |
| return "PURE1E" |
| default: |
| return "UNKNOWN" |
| } |
| } |
| |
| func (sc *syscaller) setUID(uid int) error { |
| w := GetProc() |
| defer func() { |
| w.ClearFlag(Effective) |
| sc.setProc(w) |
| }() |
| |
| if err := w.SetFlag(Effective, true, SETUID); err != nil { |
| return err |
| } |
| |
| // these may or may not work depending on whether or not they |
| // are locked. We try them just in case. |
| sc.prctlwcall(prSetKeepCaps, 1, 0) |
| defer sc.prctlwcall(prSetKeepCaps, 0, 0) |
| |
| if err := sc.setProc(w); err != nil { |
| return err |
| } |
| |
| if _, _, err := sc.w3(syscall.SYS_SETUID, uintptr(uid), 0, 0); err != 0 { |
| return err |
| } |
| return nil |
| } |
| |
| // SetUID is a convenience function for robustly setting the UID and |
| // all other variants of UID (EUID etc) to the specified value without |
| // dropping the privilege of the current process. This function will |
| // raise cap.SETUID in order to achieve this operation, and will |
| // completely lower the Effective vector of the process before |
| // returning. Unlike the traditional method of dropping privilege when |
| // changing from [E]UID=0 to some other UID, this function only |
| // performs a change of UID cap.SETUID is available, and the action |
| // does not alter the Permitted Flag of the process' Set. |
| func SetUID(uid int) error { |
| scwMu.Lock() |
| defer scwMu.Unlock() |
| return multisc.setUID(uid) |
| } |
| |
| //go:uintptrescapes |
| func (sc *syscaller) setGroups(gid int, suppl []int) error { |
| w := GetProc() |
| defer func() { |
| w.ClearFlag(Effective) |
| sc.setProc(w) |
| }() |
| |
| if err := w.SetFlag(Effective, true, SETGID); err != nil { |
| return err |
| } |
| if err := sc.setProc(w); err != nil { |
| return err |
| } |
| |
| if _, _, err := sc.w3(syscall.SYS_SETGID, uintptr(gid), 0, 0); err != 0 { |
| return err |
| } |
| if len(suppl) == 0 { |
| if _, _, err := sc.w3(sysSetGroupsVariant, 0, 0, 0); err != 0 { |
| return err |
| } |
| return nil |
| } |
| |
| // On linux gid values are 32-bits. |
| gs := make([]uint32, len(suppl)) |
| for i, g := range suppl { |
| gs[i] = uint32(g) |
| } |
| if _, _, err := sc.w3(sysSetGroupsVariant, uintptr(len(suppl)), uintptr(unsafe.Pointer(&gs[0])), 0); err != 0 { |
| return err |
| } |
| return nil |
| } |
| |
| // SetGroups is a convenience function for robustly setting the GID |
| // and all other variants of GID (EGID etc) to the specified value, as |
| // well as setting all of the supplementary groups. This function will |
| // raise cap.SETGID in order to achieve this operation, and will |
| // completely lower the Effective Flag of the process Set before |
| // returning. |
| func SetGroups(gid int, suppl ...int) error { |
| scwMu.Lock() |
| defer scwMu.Unlock() |
| return multisc.setGroups(gid, suppl) |
| } |