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