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