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 Flag of the process upon 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 ModeHybrid 79) 80 81// GetMode assesses the current process state and summarizes it as 82// a Mode. This function always succeeds. Unfamiliar modes are 83// declared ModeUncertain. 84func GetMode() Mode { 85 b := GetSecbits() 86 if b == 0 { 87 return ModeHybrid 88 } 89 if b&securedBasicBits != securedBasicBits { 90 return ModeUncertain 91 } 92 93 for c := Value(0); ; c++ { 94 v, err := GetAmbient(c) 95 if err != nil { 96 if c != 0 && b != securedAmbientBits { 97 return ModeUncertain 98 } 99 break 100 } 101 if v { 102 return ModeUncertain 103 } 104 } 105 106 w := GetProc() 107 e := NewSet() 108 cf, _ := w.Cf(e) 109 110 if cf.Has(Inheritable) { 111 return ModePure1E 112 } 113 if cf.Has(Permitted) || cf.Has(Effective) { 114 return ModePure1EInit 115 } 116 117 for c := Value(0); ; c++ { 118 v, err := GetBound(c) 119 if err != nil { 120 break 121 } 122 if v { 123 return ModePure1EInit 124 } 125 } 126 127 return ModeNoPriv 128} 129 130// ErrBadMode is the error returned when an attempt is made to set an 131// unrecognized libcap security mode. 132var ErrBadMode = errors.New("unsupported mode") 133 134func (sc *syscaller) setMode(m Mode) error { 135 w := GetProc() 136 defer func() { 137 w.ClearFlag(Effective) 138 sc.setProc(w) 139 }() 140 141 if err := w.SetFlag(Effective, true, SETPCAP); err != nil { 142 return err 143 } 144 if err := sc.setProc(w); err != nil { 145 return err 146 } 147 148 if m == ModeHybrid { 149 return sc.setSecbits(0) 150 } 151 152 if m == ModeNoPriv || m == ModePure1EInit { 153 w.ClearFlag(Inheritable) 154 } else if m != ModePure1E { 155 return ErrBadMode 156 } 157 158 sb := securedAmbientBits 159 if _, err := GetAmbient(0); err != nil { 160 sb = securedBasicBits 161 } else if err := sc.resetAmbient(); err != nil { 162 return err 163 } 164 165 if err := sc.setSecbits(sb); err != nil { 166 return err 167 } 168 169 if m != ModeNoPriv { 170 return nil 171 } 172 173 for c := Value(0); sc.dropBound(c) == nil; c++ { 174 } 175 w.ClearFlag(Permitted) 176 177 // For good measure. 178 sc.prctlwcall6(prSetNoNewPrivs, 1, 0, 0, 0, 0) 179 180 return nil 181} 182 183// Set attempts to enter the specified mode. An attempt is made to 184// enter the mode, so if you prefer this operation to be a no-op if 185// entering the same mode, call only if CurrentMode() disagrees with 186// the desired mode. 187// 188// This function will raise cap.SETPCAP in order to achieve this 189// operation, and will completely lower the Effective Flag of the 190// process' Set before returning. This function may fail for lack of 191// permission or because (some of) the Secbits are already locked for 192// the current process. 193func (m Mode) Set() error { 194 state, sc := scwStateSC() 195 defer scwSetState(launchBlocked, state, -1) 196 return sc.setMode(m) 197} 198 199// String returns the libcap conventional string for this mode. 200func (m Mode) String() string { 201 switch m { 202 case ModeUncertain: 203 return "UNCERTAIN" 204 case ModeNoPriv: 205 return "NOPRIV" 206 case ModePure1EInit: 207 return "PURE1E_INIT" 208 case ModePure1E: 209 return "PURE1E" 210 case ModeHybrid: 211 return "HYBRID" 212 default: 213 return "UNKNOWN" 214 } 215} 216 217func (sc *syscaller) setUID(uid int) error { 218 w := GetProc() 219 defer func() { 220 w.ClearFlag(Effective) 221 sc.setProc(w) 222 }() 223 224 if err := w.SetFlag(Effective, true, SETUID); err != nil { 225 return err 226 } 227 228 // these may or may not work depending on whether or not they 229 // are locked. We try them just in case. 230 sc.prctlwcall(prSetKeepCaps, 1, 0) 231 defer sc.prctlwcall(prSetKeepCaps, 0, 0) 232 233 if err := sc.setProc(w); err != nil { 234 return err 235 } 236 237 if _, _, err := sc.w3(syscall.SYS_SETUID, uintptr(uid), 0, 0); err != 0 { 238 return err 239 } 240 return nil 241} 242 243// SetUID is a convenience function for robustly setting the UID and 244// all other variants of UID (EUID etc) to the specified value without 245// dropping the privilege of the current process. This function will 246// raise cap.SETUID in order to achieve this operation, and will 247// completely lower the Effective Flag of the process before 248// returning. Unlike the traditional method of dropping privilege when 249// changing from [E]UID=0 to some other UID, this function only can 250// perform any change of UID if cap.SETUID is available, and this 251// operation will not alter the Permitted Flag of the process' Set. 252func SetUID(uid int) error { 253 state, sc := scwStateSC() 254 defer scwSetState(launchBlocked, state, -1) 255 return sc.setUID(uid) 256} 257 258//go:uintptrescapes 259func (sc *syscaller) setGroups(gid int, suppl []int) error { 260 w := GetProc() 261 defer func() { 262 w.ClearFlag(Effective) 263 sc.setProc(w) 264 }() 265 266 if err := w.SetFlag(Effective, true, SETGID); err != nil { 267 return err 268 } 269 if err := sc.setProc(w); err != nil { 270 return err 271 } 272 273 if _, _, err := sc.w3(syscall.SYS_SETGID, uintptr(gid), 0, 0); err != 0 { 274 return err 275 } 276 if len(suppl) == 0 { 277 if _, _, err := sc.w3(sysSetGroupsVariant, 0, 0, 0); err != 0 { 278 return err 279 } 280 return nil 281 } 282 283 // On linux gid values are 32-bits. 284 gs := make([]uint32, len(suppl)) 285 for i, g := range suppl { 286 gs[i] = uint32(g) 287 } 288 if _, _, err := sc.w3(sysSetGroupsVariant, uintptr(len(suppl)), uintptr(unsafe.Pointer(&gs[0])), 0); err != 0 { 289 return err 290 } 291 return nil 292} 293 294// SetGroups is a convenience function for robustly setting the GID 295// and all other variants of GID (EGID etc) to the specified value, as 296// well as setting all of the supplementary groups. This function will 297// raise cap.SETGID in order to achieve this operation, and will 298// completely lower the Effective Flag of the process Set before 299// returning. 300func SetGroups(gid int, suppl ...int) error { 301 state, sc := scwStateSC() 302 defer scwSetState(launchBlocked, state, -1) 303 return sc.setGroups(gid, suppl) 304} 305 306//go:uintptrescapes 307 308// Prctlw is a convenience function for performing a syscall.Prctl() 309// call that executes on all the threads of the process. It is called 310// Prctlw because it is only appropriate to call this function when it 311// is writing thread state that the caller wants to set on all OS 312// threads of the process to observe POSIX semantics when Linux 313// doesn't natively honor them. (Check prctl documentation for when it 314// is appropriate to use this vs. a normal syscall.Prctl() call.) 315func Prctlw(prVal uintptr, args ...uintptr) (int, error) { 316 if n := len(args); n > 5 { 317 return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n) 318 } 319 state, sc := scwStateSC() 320 defer scwSetState(launchBlocked, state, -1) 321 as := make([]uintptr, 5) 322 copy(as, args) 323 return sc.prctlwcall6(prVal, as[0], as[1], as[2], as[3], as[4]) 324} 325 326//go:uintptrescapes 327 328// Prctl is a convenience function that performs a syscall.Prctl() 329// that either reads state using a single OS thread, or performs a 330// Prctl that is treated as a process wide setting. It is provided for 331// symmetry reasons, but is equivalent to simply calling the 332// corresponding syscall function. 333func Prctl(prVal uintptr, args ...uintptr) (int, error) { 334 if n := len(args); n > 5 { 335 return -1, fmt.Errorf("prctl supports up to 5 arguments (not %d)", n) 336 } 337 as := make([]uintptr, 5) 338 copy(as, args) 339 return singlesc.prctlrcall6(prVal, as[0], as[1], as[2], as[3], as[4]) 340} 341