1package cap 2 3import ( 4 "errors" 5 "fmt" 6 "syscall" 7 "unsafe" 8) 9 10// This file contains convenience functions for libcap, to help 11// users do the right thing with respect to capabilities for 12// common actions. 13 14// Secbits capture the prctl settable secure-bits of a process. 15type Secbits uint 16 17// SecbitNoRoot etc are the bitmasks associated with the supported 18// Secbit masks. Source: uapi/linux/securebits.h 19const ( 20 SecbitNoRoot Secbits = 1 << iota 21 SecbitNoRootLocked 22 SecbitNoSetUIDFixup 23 SecbitNoSetUIDFixupLocked 24 SecbitKeepCaps 25 SecbitKeepCapsLocked 26 SecbitNoCapAmbientRaise 27 SecbitNoCapAmbientRaiseLocked 28) 29 30const ( 31 securedBasicBits = SecbitNoRoot | SecbitNoRootLocked | SecbitNoSetUIDFixup | SecbitNoSetUIDFixupLocked | SecbitKeepCapsLocked 32 securedAmbientBits = securedBasicBits | SecbitNoCapAmbientRaise | SecbitNoCapAmbientRaiseLocked 33) 34 35// defines from uapi/linux/prctl.h 36const ( 37 prGetKeepCaps = 7 38 prSetKeepCaps = 8 39 prGetSecureBits = 27 40 prSetSecureBits = 28 41 prSetNoNewPrivs = 38 42) 43 44// GetSecbits returns the current setting of the process' Secbits. 45func GetSecbits() Secbits { 46 v, err := multisc.prctlrcall(prGetSecureBits, 0, 0) 47 if err != nil { 48 panic(err) 49 } 50 return Secbits(v) 51} 52 53func (sc *syscaller) setSecbits(s Secbits) error { 54 _, err := sc.prctlwcall(prSetSecureBits, uintptr(s), 0) 55 return err 56} 57 58// Set attempts to force the process Secbits to a value. This function 59// will raise cap.SETPCAP in order to achieve this operation, and will 60// completely lower the Effective vector of the process returning. 61func (s Secbits) Set() error { 62 state, sc := scwStateSC() 63 defer scwSetState(launchBlocked, state, -1) 64 return sc.setSecbits(s) 65} 66 67// Mode summarizes a complicated secure-bits and capability mode in a 68// libcap preferred way. 69type Mode uint 70 71// ModeUncertain etc are how libcap summarizes security modes 72// involving capabilities and secure-bits. 73const ( 74 ModeUncertain Mode = iota 75 ModeNoPriv 76 ModePure1EInit 77 ModePure1E 78) 79 80// GetMode assesses the current process state and summarizes it as 81// a Mode. This function always succeeds. Unfamiliar modes are 82// declared ModeUncertain. 83func GetMode() Mode { 84 b := GetSecbits() 85 if b&securedBasicBits != securedBasicBits { 86 return ModeUncertain 87 } 88 89 for c := Value(0); ; c++ { 90 v, err := GetAmbient(c) 91 if err != nil { 92 if c != 0 && b != securedAmbientBits { 93 return ModeUncertain 94 } 95 break 96 } 97 if v { 98 return ModeUncertain 99 } 100 } 101 102 w := GetProc() 103 e := NewSet() 104 cf, _ := w.Compare(e) 105 106 if Differs(cf, Inheritable) { 107 return ModePure1E 108 } 109 if Differs(cf, Permitted) || Differs(cf, Effective) { 110 return ModePure1EInit 111 } 112 113 for c := Value(0); ; c++ { 114 v, err := GetBound(c) 115 if err != nil { 116 break 117 } 118 if v { 119 return ModePure1EInit 120 } 121 } 122 123 return ModeNoPriv 124} 125 126// ErrBadMode is the error returned when an attempt is made to set an 127// unrecognized libcap security mode. 128var ErrBadMode = errors.New("unsupported mode") 129 130func (sc *syscaller) setMode(m Mode) error { 131 w := GetProc() 132 defer func() { 133 w.ClearFlag(Effective) 134 sc.setProc(w) 135 }() 136 137 if err := w.SetFlag(Effective, true, SETPCAP); err != nil { 138 return err 139 } 140 if err := sc.setProc(w); err != nil { 141 return err 142 } 143 144 if m == ModeNoPriv || m == ModePure1EInit { 145 w.ClearFlag(Inheritable) 146 } else if m != ModePure1E { 147 return ErrBadMode 148 } 149 150 sb := securedAmbientBits 151 if _, err := GetAmbient(0); err != nil { 152 sb = securedBasicBits 153 } else if err := sc.resetAmbient(); err != nil { 154 return err 155 } 156 157 if err := sc.setSecbits(sb); err != nil { 158 return err 159 } 160 161 if m != ModeNoPriv { 162 return nil 163 } 164 165 for c := Value(0); sc.dropBound(c) == nil; c++ { 166 } 167 w.ClearFlag(Permitted) 168 169 // For good measure. 170 sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0) 171 172 return nil 173} 174 175// Set attempts to enter the specified mode. An attempt is made to 176// enter the mode, so if you prefer this operation to be a no-op if 177// entering the same mode, call only if CurrentMode() disagrees with 178// the desired mode. 179// 180// This function will raise cap.SETPCAP in order to achieve this 181// operation, and will completely lower the Effective Flag of the 182// process' Set before returning. This function may fail for lack of 183// permission or because (some of) the Secbits are already locked for 184// the current process. 185func (m Mode) Set() error { 186 state, sc := scwStateSC() 187 defer scwSetState(launchBlocked, state, -1) 188 return sc.setMode(m) 189} 190 191// String returns the libcap conventional string for this mode. 192func (m Mode) String() string { 193 switch m { 194 case ModeUncertain: 195 return "UNCERTAIN" 196 case ModeNoPriv: 197 return "NOPRIV" 198 case ModePure1EInit: 199 return "PURE1E_INIT" 200 case ModePure1E: 201 return "PURE1E" 202 default: 203 return "UNKNOWN" 204 } 205} 206 207func (sc *syscaller) setUID(uid int) error { 208 w := GetProc() 209 defer func() { 210 w.ClearFlag(Effective) 211 sc.setProc(w) 212 }() 213 214 if err := w.SetFlag(Effective, true, SETUID); err != nil { 215 return err 216 } 217 218 // these may or may not work depending on whether or not they 219 // are locked. We try them just in case. 220 sc.prctlwcall(prSetKeepCaps, 1, 0) 221 defer sc.prctlwcall(prSetKeepCaps, 0, 0) 222 223 if err := sc.setProc(w); err != nil { 224 return err 225 } 226 227 if _, _, err := sc.w3(syscall.SYS_SETUID, uintptr(uid), 0, 0); err != 0 { 228 return err 229 } 230 return nil 231} 232 233// SetUID is a convenience function for robustly setting the UID and 234// all other variants of UID (EUID etc) to the specified value without 235// dropping the privilege of the current process. This function will 236// raise cap.SETUID in order to achieve this operation, and will 237// completely lower the Effective vector of the process before 238// returning. Unlike the traditional method of dropping privilege when 239// changing from [E]UID=0 to some other UID, this function only 240// performs a change of UID cap.SETUID is available, and the action 241// does not alter the Permitted Flag of the process' Set. 242func SetUID(uid int) error { 243 state, sc := scwStateSC() 244 defer scwSetState(launchBlocked, state, -1) 245 return sc.setUID(uid) 246} 247 248//go:uintptrescapes 249func (sc *syscaller) setGroups(gid int, suppl []int) error { 250 w := GetProc() 251 defer func() { 252 w.ClearFlag(Effective) 253 sc.setProc(w) 254 }() 255 256 if err := w.SetFlag(Effective, true, SETGID); err != nil { 257 return err 258 } 259 if err := sc.setProc(w); err != nil { 260 return err 261 } 262 263 if _, _, err := sc.w3(syscall.SYS_SETGID, uintptr(gid), 0, 0); err != 0 { 264 return err 265 } 266 if len(suppl) == 0 { 267 if _, _, err := sc.w3(sysSetGroupsVariant, 0, 0, 0); err != 0 { 268 return err 269 } 270 return nil 271 } 272 273 // On linux gid values are 32-bits. 274 gs := make([]uint32, len(suppl)) 275 for i, g := range suppl { 276 gs[i] = uint32(g) 277 } 278 if _, _, err := sc.w3(sysSetGroupsVariant, uintptr(len(suppl)), uintptr(unsafe.Pointer(&gs[0])), 0); err != 0 { 279 return err 280 } 281 return nil 282} 283 284// SetGroups is a convenience function for robustly setting the GID 285// and all other variants of GID (EGID etc) to the specified value, as 286// well as setting all of the supplementary groups. This function will 287// raise cap.SETGID in order to achieve this operation, and will 288// completely lower the Effective Flag of the process Set before 289// returning. 290func SetGroups(gid int, suppl ...int) error { 291 state, sc := scwStateSC() 292 defer scwSetState(launchBlocked, state, -1) 293 return sc.setGroups(gid, suppl) 294} 295 296//go:uintptrescapes 297 298// Prctlw is a convenience function for performing a syscall.Prctl() 299// call that executes on all the threads of the process. It is called 300// Prctlw because it is only appropriate to call this function when it 301// is writing thread state that the caller wants to set on all OS 302// threads of the process to observe POSIX semantics when Linux 303// doesn't natively honor them. (Check prctl documentation for when it 304// is appropriate to use this vs. a normal syscall.Prctl() call.) 305func Prctlw(prVal uintptr, args ...uintptr) (int, error) { 306 if n := len(args); n > 5 { 307 return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n) 308 } 309 state, sc := scwStateSC() 310 defer scwSetState(launchBlocked, state, -1) 311 as := make([]uintptr, 5) 312 copy(as, args) 313 return sc.prctlwcall6(prVal, as[0], as[1], as[2], as[3], as[4]) 314} 315 316//go:uintptrescapes 317 318// Prctl is a convenience function that performs a syscall.Prctl() 319// that either reads state using a single OS thread, or performs a 320// Prctl that is treated as a process wide setting. It is provided for 321// symmetry reasons, but is equivalent to simply calling the 322// corresponding syscall function. 323func Prctl(prVal uintptr, args ...uintptr) (int, error) { 324 if n := len(args); n > 5 { 325 return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n) 326 } 327 as := make([]uintptr, 5) 328 copy(as, args) 329 return singlesc.prctlrcall6(prVal, as[0], as[1], as[2], as[3], as[4]) 330} 331