1*2810ac1bSKiyoung Kimpackage cap 2*2810ac1bSKiyoung Kim 3*2810ac1bSKiyoung Kimimport ( 4*2810ac1bSKiyoung Kim "bytes" 5*2810ac1bSKiyoung Kim "encoding/binary" 6*2810ac1bSKiyoung Kim "errors" 7*2810ac1bSKiyoung Kim "io" 8*2810ac1bSKiyoung Kim "os" 9*2810ac1bSKiyoung Kim "syscall" 10*2810ac1bSKiyoung Kim "unsafe" 11*2810ac1bSKiyoung Kim) 12*2810ac1bSKiyoung Kim 13*2810ac1bSKiyoung Kim// uapi/linux/xattr.h defined. 14*2810ac1bSKiyoung Kimvar ( 15*2810ac1bSKiyoung Kim xattrNameCaps, _ = syscall.BytePtrFromString("security.capability") 16*2810ac1bSKiyoung Kim) 17*2810ac1bSKiyoung Kim 18*2810ac1bSKiyoung Kim// uapi/linux/capability.h defined. 19*2810ac1bSKiyoung Kimconst ( 20*2810ac1bSKiyoung Kim vfsCapRevisionMask = uint32(0xff000000) 21*2810ac1bSKiyoung Kim vfsCapFlagsMask = ^vfsCapRevisionMask 22*2810ac1bSKiyoung Kim vfsCapFlagsEffective = uint32(1) 23*2810ac1bSKiyoung Kim 24*2810ac1bSKiyoung Kim vfsCapRevision1 = uint32(0x01000000) 25*2810ac1bSKiyoung Kim vfsCapRevision2 = uint32(0x02000000) 26*2810ac1bSKiyoung Kim vfsCapRevision3 = uint32(0x03000000) 27*2810ac1bSKiyoung Kim) 28*2810ac1bSKiyoung Kim 29*2810ac1bSKiyoung Kim// Data types stored in little-endian order. 30*2810ac1bSKiyoung Kim 31*2810ac1bSKiyoung Kimtype vfsCaps1 struct { 32*2810ac1bSKiyoung Kim MagicEtc uint32 33*2810ac1bSKiyoung Kim Data [1]struct { 34*2810ac1bSKiyoung Kim Permitted, Inheritable uint32 35*2810ac1bSKiyoung Kim } 36*2810ac1bSKiyoung Kim} 37*2810ac1bSKiyoung Kim 38*2810ac1bSKiyoung Kimtype vfsCaps2 struct { 39*2810ac1bSKiyoung Kim MagicEtc uint32 40*2810ac1bSKiyoung Kim Data [2]struct { 41*2810ac1bSKiyoung Kim Permitted, Inheritable uint32 42*2810ac1bSKiyoung Kim } 43*2810ac1bSKiyoung Kim} 44*2810ac1bSKiyoung Kim 45*2810ac1bSKiyoung Kimtype vfsCaps3 struct { 46*2810ac1bSKiyoung Kim MagicEtc uint32 47*2810ac1bSKiyoung Kim Data [2]struct { 48*2810ac1bSKiyoung Kim Permitted, Inheritable uint32 49*2810ac1bSKiyoung Kim } 50*2810ac1bSKiyoung Kim RootID uint32 51*2810ac1bSKiyoung Kim} 52*2810ac1bSKiyoung Kim 53*2810ac1bSKiyoung Kim// ErrBadSize indicates the loaded file capability has 54*2810ac1bSKiyoung Kim// an invalid number of bytes in it. 55*2810ac1bSKiyoung Kimvar ErrBadSize = errors.New("filecap bad size") 56*2810ac1bSKiyoung Kim 57*2810ac1bSKiyoung Kim// ErrBadMagic indicates that the kernel preferred magic number for 58*2810ac1bSKiyoung Kim// capability Set values is not supported by this package. This 59*2810ac1bSKiyoung Kim// generally implies you are using an exceptionally old 60*2810ac1bSKiyoung Kim// "../libcap/cap" package. An upgrade is needed, or failing that see 61*2810ac1bSKiyoung Kim// https://sites.google.com/site/fullycapable/ for how to file a bug. 62*2810ac1bSKiyoung Kimvar ErrBadMagic = errors.New("unsupported magic") 63*2810ac1bSKiyoung Kim 64*2810ac1bSKiyoung Kim// ErrBadPath indicates a failed attempt to set a file capability on 65*2810ac1bSKiyoung Kim// an irregular (non-executable) file. 66*2810ac1bSKiyoung Kimvar ErrBadPath = errors.New("file is not a regular executable") 67*2810ac1bSKiyoung Kim 68*2810ac1bSKiyoung Kim// ErrOutOfRange indicates an erroneous value for MinExtFlagSize. 69*2810ac1bSKiyoung Kimvar ErrOutOfRange = errors.New("flag length invalid for export") 70*2810ac1bSKiyoung Kim 71*2810ac1bSKiyoung Kim// digestFileCap unpacks a file capability and returns it in a *Set 72*2810ac1bSKiyoung Kim// form. 73*2810ac1bSKiyoung Kimfunc digestFileCap(d []byte, sz int, err error) (*Set, error) { 74*2810ac1bSKiyoung Kim if err != nil { 75*2810ac1bSKiyoung Kim return nil, err 76*2810ac1bSKiyoung Kim } 77*2810ac1bSKiyoung Kim var raw1 vfsCaps1 78*2810ac1bSKiyoung Kim var raw2 vfsCaps2 79*2810ac1bSKiyoung Kim var raw3 vfsCaps3 80*2810ac1bSKiyoung Kim if sz < binary.Size(raw1) || sz > binary.Size(raw3) { 81*2810ac1bSKiyoung Kim return nil, ErrBadSize 82*2810ac1bSKiyoung Kim } 83*2810ac1bSKiyoung Kim b := bytes.NewReader(d[:sz]) 84*2810ac1bSKiyoung Kim var magicEtc uint32 85*2810ac1bSKiyoung Kim if err = binary.Read(b, binary.LittleEndian, &magicEtc); err != nil { 86*2810ac1bSKiyoung Kim return nil, err 87*2810ac1bSKiyoung Kim } 88*2810ac1bSKiyoung Kim 89*2810ac1bSKiyoung Kim c := NewSet() 90*2810ac1bSKiyoung Kim b.Seek(0, io.SeekStart) 91*2810ac1bSKiyoung Kim switch magicEtc & vfsCapRevisionMask { 92*2810ac1bSKiyoung Kim case vfsCapRevision1: 93*2810ac1bSKiyoung Kim if err = binary.Read(b, binary.LittleEndian, &raw1); err != nil { 94*2810ac1bSKiyoung Kim return nil, err 95*2810ac1bSKiyoung Kim } 96*2810ac1bSKiyoung Kim data := raw1.Data[0] 97*2810ac1bSKiyoung Kim c.flat[0][Permitted] = data.Permitted 98*2810ac1bSKiyoung Kim c.flat[0][Inheritable] = data.Inheritable 99*2810ac1bSKiyoung Kim if raw1.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective { 100*2810ac1bSKiyoung Kim c.flat[0][Effective] = data.Inheritable | data.Permitted 101*2810ac1bSKiyoung Kim } 102*2810ac1bSKiyoung Kim case vfsCapRevision2: 103*2810ac1bSKiyoung Kim if err = binary.Read(b, binary.LittleEndian, &raw2); err != nil { 104*2810ac1bSKiyoung Kim return nil, err 105*2810ac1bSKiyoung Kim } 106*2810ac1bSKiyoung Kim for i, data := range raw2.Data { 107*2810ac1bSKiyoung Kim c.flat[i][Permitted] = data.Permitted 108*2810ac1bSKiyoung Kim c.flat[i][Inheritable] = data.Inheritable 109*2810ac1bSKiyoung Kim if raw2.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective { 110*2810ac1bSKiyoung Kim c.flat[i][Effective] = data.Inheritable | data.Permitted 111*2810ac1bSKiyoung Kim } 112*2810ac1bSKiyoung Kim } 113*2810ac1bSKiyoung Kim case vfsCapRevision3: 114*2810ac1bSKiyoung Kim if err = binary.Read(b, binary.LittleEndian, &raw3); err != nil { 115*2810ac1bSKiyoung Kim return nil, err 116*2810ac1bSKiyoung Kim } 117*2810ac1bSKiyoung Kim for i, data := range raw3.Data { 118*2810ac1bSKiyoung Kim c.flat[i][Permitted] = data.Permitted 119*2810ac1bSKiyoung Kim c.flat[i][Inheritable] = data.Inheritable 120*2810ac1bSKiyoung Kim if raw3.MagicEtc&vfsCapFlagsMask == vfsCapFlagsEffective { 121*2810ac1bSKiyoung Kim c.flat[i][Effective] = data.Inheritable | data.Permitted 122*2810ac1bSKiyoung Kim } 123*2810ac1bSKiyoung Kim } 124*2810ac1bSKiyoung Kim c.nsRoot = int(raw3.RootID) 125*2810ac1bSKiyoung Kim default: 126*2810ac1bSKiyoung Kim return nil, ErrBadMagic 127*2810ac1bSKiyoung Kim } 128*2810ac1bSKiyoung Kim return c, nil 129*2810ac1bSKiyoung Kim} 130*2810ac1bSKiyoung Kim 131*2810ac1bSKiyoung Kim//go:uintptrescapes 132*2810ac1bSKiyoung Kim 133*2810ac1bSKiyoung Kim// GetFd returns the file capabilities of an open (*os.File).Fd(). 134*2810ac1bSKiyoung Kimfunc GetFd(file *os.File) (*Set, error) { 135*2810ac1bSKiyoung Kim var raw3 vfsCaps3 136*2810ac1bSKiyoung Kim d := make([]byte, binary.Size(raw3)) 137*2810ac1bSKiyoung Kim sz, _, oErr := multisc.r6(syscall.SYS_FGETXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0) 138*2810ac1bSKiyoung Kim var err error 139*2810ac1bSKiyoung Kim if oErr != 0 { 140*2810ac1bSKiyoung Kim err = oErr 141*2810ac1bSKiyoung Kim } 142*2810ac1bSKiyoung Kim return digestFileCap(d, int(sz), err) 143*2810ac1bSKiyoung Kim} 144*2810ac1bSKiyoung Kim 145*2810ac1bSKiyoung Kim//go:uintptrescapes 146*2810ac1bSKiyoung Kim 147*2810ac1bSKiyoung Kim// GetFile returns the file capabilities of a named file. 148*2810ac1bSKiyoung Kimfunc GetFile(path string) (*Set, error) { 149*2810ac1bSKiyoung Kim p, err := syscall.BytePtrFromString(path) 150*2810ac1bSKiyoung Kim if err != nil { 151*2810ac1bSKiyoung Kim return nil, err 152*2810ac1bSKiyoung Kim } 153*2810ac1bSKiyoung Kim var raw3 vfsCaps3 154*2810ac1bSKiyoung Kim d := make([]byte, binary.Size(raw3)) 155*2810ac1bSKiyoung Kim sz, _, oErr := multisc.r6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0) 156*2810ac1bSKiyoung Kim if oErr != 0 { 157*2810ac1bSKiyoung Kim err = oErr 158*2810ac1bSKiyoung Kim } 159*2810ac1bSKiyoung Kim return digestFileCap(d, int(sz), err) 160*2810ac1bSKiyoung Kim} 161*2810ac1bSKiyoung Kim 162*2810ac1bSKiyoung Kim// GetNSOwner returns the namespace owner UID of the capability Set. 163*2810ac1bSKiyoung Kimfunc (c *Set) GetNSOwner() (int, error) { 164*2810ac1bSKiyoung Kim if magic < kv3 { 165*2810ac1bSKiyoung Kim return 0, ErrBadMagic 166*2810ac1bSKiyoung Kim } 167*2810ac1bSKiyoung Kim c.mu.RLock() 168*2810ac1bSKiyoung Kim defer c.mu.RUnlock() 169*2810ac1bSKiyoung Kim return c.nsRoot, nil 170*2810ac1bSKiyoung Kim} 171*2810ac1bSKiyoung Kim 172*2810ac1bSKiyoung Kim// SetNSOwner adds an explicit namespace owner UID to the capability 173*2810ac1bSKiyoung Kim// Set. This is only honored when generating file capabilities, and is 174*2810ac1bSKiyoung Kim// generally for use by a setup process when installing binaries that 175*2810ac1bSKiyoung Kim// use file capabilities to become capable inside a namespace to be 176*2810ac1bSKiyoung Kim// administered by that UID. If capability aware code within that 177*2810ac1bSKiyoung Kim// namespace writes file capabilities without explicitly setting such 178*2810ac1bSKiyoung Kim// a UID, the kernel will fix-up the capabilities to be specific to 179*2810ac1bSKiyoung Kim// that owner. In this way, the kernel prevents filesystem 180*2810ac1bSKiyoung Kim// capabilities from leaking out of that restricted namespace. 181*2810ac1bSKiyoung Kimfunc (c *Set) SetNSOwner(uid int) { 182*2810ac1bSKiyoung Kim c.mu.Lock() 183*2810ac1bSKiyoung Kim defer c.mu.Unlock() 184*2810ac1bSKiyoung Kim c.nsRoot = uid 185*2810ac1bSKiyoung Kim} 186*2810ac1bSKiyoung Kim 187*2810ac1bSKiyoung Kim// packFileCap transforms a system capability into a VFS form. Because 188*2810ac1bSKiyoung Kim// of the way Linux stores capabilities in the file extended 189*2810ac1bSKiyoung Kim// attributes, the process is a little lossy with respect to effective 190*2810ac1bSKiyoung Kim// bits. 191*2810ac1bSKiyoung Kimfunc (c *Set) packFileCap() ([]byte, error) { 192*2810ac1bSKiyoung Kim c.mu.RLock() 193*2810ac1bSKiyoung Kim defer c.mu.RUnlock() 194*2810ac1bSKiyoung Kim 195*2810ac1bSKiyoung Kim var magic uint32 196*2810ac1bSKiyoung Kim switch words { 197*2810ac1bSKiyoung Kim case 1: 198*2810ac1bSKiyoung Kim if c.nsRoot != 0 { 199*2810ac1bSKiyoung Kim return nil, ErrBadSet // nsRoot not supported for single DWORD caps. 200*2810ac1bSKiyoung Kim } 201*2810ac1bSKiyoung Kim magic = vfsCapRevision1 202*2810ac1bSKiyoung Kim case 2: 203*2810ac1bSKiyoung Kim if c.nsRoot == 0 { 204*2810ac1bSKiyoung Kim magic = vfsCapRevision2 205*2810ac1bSKiyoung Kim break 206*2810ac1bSKiyoung Kim } 207*2810ac1bSKiyoung Kim magic = vfsCapRevision3 208*2810ac1bSKiyoung Kim } 209*2810ac1bSKiyoung Kim if magic == 0 { 210*2810ac1bSKiyoung Kim return nil, ErrBadSize 211*2810ac1bSKiyoung Kim } 212*2810ac1bSKiyoung Kim eff := uint32(0) 213*2810ac1bSKiyoung Kim for _, f := range c.flat { 214*2810ac1bSKiyoung Kim eff |= (f[Permitted] | f[Inheritable]) & f[Effective] 215*2810ac1bSKiyoung Kim } 216*2810ac1bSKiyoung Kim if eff != 0 { 217*2810ac1bSKiyoung Kim magic |= vfsCapFlagsEffective 218*2810ac1bSKiyoung Kim } 219*2810ac1bSKiyoung Kim b := new(bytes.Buffer) 220*2810ac1bSKiyoung Kim binary.Write(b, binary.LittleEndian, magic) 221*2810ac1bSKiyoung Kim for _, f := range c.flat { 222*2810ac1bSKiyoung Kim binary.Write(b, binary.LittleEndian, f[Permitted]) 223*2810ac1bSKiyoung Kim binary.Write(b, binary.LittleEndian, f[Inheritable]) 224*2810ac1bSKiyoung Kim } 225*2810ac1bSKiyoung Kim if c.nsRoot != 0 { 226*2810ac1bSKiyoung Kim binary.Write(b, binary.LittleEndian, c.nsRoot) 227*2810ac1bSKiyoung Kim } 228*2810ac1bSKiyoung Kim return b.Bytes(), nil 229*2810ac1bSKiyoung Kim} 230*2810ac1bSKiyoung Kim 231*2810ac1bSKiyoung Kim//go:uintptrescapes 232*2810ac1bSKiyoung Kim 233*2810ac1bSKiyoung Kim// SetFd attempts to set the file capabilities of an open 234*2810ac1bSKiyoung Kim// (*os.File).Fd(). This function can also be used to delete a file's 235*2810ac1bSKiyoung Kim// capabilities, by calling with c = nil. 236*2810ac1bSKiyoung Kim// 237*2810ac1bSKiyoung Kim// Note, Linux does not store the full Effective Flag in the metadata 238*2810ac1bSKiyoung Kim// for the file. Only a single Effective bit is stored in this 239*2810ac1bSKiyoung Kim// metadata. This single bit is non-zero if the Effective Flag has any 240*2810ac1bSKiyoung Kim// overlapping bits with the Permitted or Inheritable Flags of c. This 241*2810ac1bSKiyoung Kim// may appear suboptimal, but the reasoning behind it is sound. 242*2810ac1bSKiyoung Kim// Namely, the purpose of the Effective bit it to support capabability 243*2810ac1bSKiyoung Kim// unaware binaries that will only work if they magically launch with 244*2810ac1bSKiyoung Kim// the needed Values already raised (this bit is sometimes referred to 245*2810ac1bSKiyoung Kim// simply as the 'legacy' bit). 246*2810ac1bSKiyoung Kim// 247*2810ac1bSKiyoung Kim// Historical note: without *full* support for runtime capability 248*2810ac1bSKiyoung Kim// manipulation, as it is provided in this "../libcap/cap" package, 249*2810ac1bSKiyoung Kim// this was previously the only way for Go programs to make use of 250*2810ac1bSKiyoung Kim// file capabilities. 251*2810ac1bSKiyoung Kim// 252*2810ac1bSKiyoung Kim// The preferred way that a binary will actually manipulate its 253*2810ac1bSKiyoung Kim// file-acquired capabilities is to carefully and deliberately use 254*2810ac1bSKiyoung Kim// this package (or libcap, assisted by libpsx, for threaded C/C++ 255*2810ac1bSKiyoung Kim// family code). 256*2810ac1bSKiyoung Kimfunc (c *Set) SetFd(file *os.File) error { 257*2810ac1bSKiyoung Kim if c == nil { 258*2810ac1bSKiyoung Kim if _, _, err := multisc.r6(syscall.SYS_FREMOVEXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), 0, 0, 0, 0); err != 0 { 259*2810ac1bSKiyoung Kim return err 260*2810ac1bSKiyoung Kim } 261*2810ac1bSKiyoung Kim return nil 262*2810ac1bSKiyoung Kim } 263*2810ac1bSKiyoung Kim c.mu.RLock() 264*2810ac1bSKiyoung Kim defer c.mu.RUnlock() 265*2810ac1bSKiyoung Kim d, err := c.packFileCap() 266*2810ac1bSKiyoung Kim if err != nil { 267*2810ac1bSKiyoung Kim return err 268*2810ac1bSKiyoung Kim } 269*2810ac1bSKiyoung Kim if _, _, err := multisc.r6(syscall.SYS_FSETXATTR, uintptr(file.Fd()), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0); err != 0 { 270*2810ac1bSKiyoung Kim return err 271*2810ac1bSKiyoung Kim } 272*2810ac1bSKiyoung Kim return nil 273*2810ac1bSKiyoung Kim} 274*2810ac1bSKiyoung Kim 275*2810ac1bSKiyoung Kim//go:uintptrescapes 276*2810ac1bSKiyoung Kim 277*2810ac1bSKiyoung Kim// SetFile attempts to set the file capabilities of the specified 278*2810ac1bSKiyoung Kim// filename. This function can also be used to delete a file's 279*2810ac1bSKiyoung Kim// capabilities, by calling with c = nil. 280*2810ac1bSKiyoung Kim// 281*2810ac1bSKiyoung Kim// Note, see the comment for SetFd() for some non-obvious behavior of 282*2810ac1bSKiyoung Kim// Linux for the Effective Flag on the modified file. 283*2810ac1bSKiyoung Kimfunc (c *Set) SetFile(path string) error { 284*2810ac1bSKiyoung Kim fi, err := os.Stat(path) 285*2810ac1bSKiyoung Kim if err != nil { 286*2810ac1bSKiyoung Kim return err 287*2810ac1bSKiyoung Kim } 288*2810ac1bSKiyoung Kim mode := fi.Mode() 289*2810ac1bSKiyoung Kim if mode&os.ModeType != 0 { 290*2810ac1bSKiyoung Kim return ErrBadPath 291*2810ac1bSKiyoung Kim } 292*2810ac1bSKiyoung Kim if mode&os.FileMode(0111) == 0 { 293*2810ac1bSKiyoung Kim return ErrBadPath 294*2810ac1bSKiyoung Kim } 295*2810ac1bSKiyoung Kim p, err := syscall.BytePtrFromString(path) 296*2810ac1bSKiyoung Kim if err != nil { 297*2810ac1bSKiyoung Kim return err 298*2810ac1bSKiyoung Kim } 299*2810ac1bSKiyoung Kim if c == nil { 300*2810ac1bSKiyoung Kim if _, _, err := multisc.r6(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), 0, 0, 0, 0); err != 0 { 301*2810ac1bSKiyoung Kim return err 302*2810ac1bSKiyoung Kim } 303*2810ac1bSKiyoung Kim return nil 304*2810ac1bSKiyoung Kim } 305*2810ac1bSKiyoung Kim c.mu.RLock() 306*2810ac1bSKiyoung Kim defer c.mu.RUnlock() 307*2810ac1bSKiyoung Kim d, err := c.packFileCap() 308*2810ac1bSKiyoung Kim if err != nil { 309*2810ac1bSKiyoung Kim return err 310*2810ac1bSKiyoung Kim } 311*2810ac1bSKiyoung Kim if _, _, err := multisc.r6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(p)), uintptr(unsafe.Pointer(xattrNameCaps)), uintptr(unsafe.Pointer(&d[0])), uintptr(len(d)), 0, 0); err != 0 { 312*2810ac1bSKiyoung Kim return err 313*2810ac1bSKiyoung Kim } 314*2810ac1bSKiyoung Kim return nil 315*2810ac1bSKiyoung Kim} 316*2810ac1bSKiyoung Kim 317*2810ac1bSKiyoung Kim// ExtMagic is the 32-bit (little endian) magic for an external 318*2810ac1bSKiyoung Kim// capability set. It can be used to transmit capabilities in binary 319*2810ac1bSKiyoung Kim// format in a Linux portable way. The format is: 320*2810ac1bSKiyoung Kim// <ExtMagic><byte:length><length-bytes*3-of-cap-data>. 321*2810ac1bSKiyoung Kimconst ExtMagic = uint32(0x5101c290) 322*2810ac1bSKiyoung Kim 323*2810ac1bSKiyoung Kim// Import imports a Set from a byte array where it has been stored in 324*2810ac1bSKiyoung Kim// a portable (lossless) way. That is values exported by 325*2810ac1bSKiyoung Kim// libcap.cap_copy_ext() and Export(). 326*2810ac1bSKiyoung Kimfunc Import(d []byte) (*Set, error) { 327*2810ac1bSKiyoung Kim b := bytes.NewBuffer(d) 328*2810ac1bSKiyoung Kim var m uint32 329*2810ac1bSKiyoung Kim if err := binary.Read(b, binary.LittleEndian, &m); err != nil { 330*2810ac1bSKiyoung Kim return nil, ErrBadSize 331*2810ac1bSKiyoung Kim } else if m != ExtMagic { 332*2810ac1bSKiyoung Kim return nil, ErrBadMagic 333*2810ac1bSKiyoung Kim } 334*2810ac1bSKiyoung Kim var n byte 335*2810ac1bSKiyoung Kim if err := binary.Read(b, binary.LittleEndian, &n); err != nil { 336*2810ac1bSKiyoung Kim return nil, ErrBadSize 337*2810ac1bSKiyoung Kim } 338*2810ac1bSKiyoung Kim c := NewSet() 339*2810ac1bSKiyoung Kim if int(n) > 4*words { 340*2810ac1bSKiyoung Kim return nil, ErrBadSize 341*2810ac1bSKiyoung Kim } 342*2810ac1bSKiyoung Kim f := make([]byte, 3) 343*2810ac1bSKiyoung Kim for i := 0; i < words; i++ { 344*2810ac1bSKiyoung Kim for j := uint(0); n > 0 && j < 4; j++ { 345*2810ac1bSKiyoung Kim n-- 346*2810ac1bSKiyoung Kim if x, err := b.Read(f); err != nil || x != 3 { 347*2810ac1bSKiyoung Kim return nil, ErrBadSize 348*2810ac1bSKiyoung Kim } 349*2810ac1bSKiyoung Kim sh := 8 * j 350*2810ac1bSKiyoung Kim c.flat[i][Effective] |= uint32(f[0]) << sh 351*2810ac1bSKiyoung Kim c.flat[i][Permitted] |= uint32(f[1]) << sh 352*2810ac1bSKiyoung Kim c.flat[i][Inheritable] |= uint32(f[2]) << sh 353*2810ac1bSKiyoung Kim } 354*2810ac1bSKiyoung Kim } 355*2810ac1bSKiyoung Kim return c, nil 356*2810ac1bSKiyoung Kim} 357*2810ac1bSKiyoung Kim 358*2810ac1bSKiyoung Kim// MinExtFlagSize defaults to 8 in order to be equivalent to libcap 359*2810ac1bSKiyoung Kim// defaults. Setting it to zero can generate smaller external 360*2810ac1bSKiyoung Kim// representations. Such smaller representations can be imported by 361*2810ac1bSKiyoung Kim// libcap and the Go package just fine, we just default to the default 362*2810ac1bSKiyoung Kim// libcap representation for legacy reasons. 363*2810ac1bSKiyoung Kimvar MinExtFlagSize = uint(8) 364*2810ac1bSKiyoung Kim 365*2810ac1bSKiyoung Kim// Export exports a Set into a lossless byte array format where it is 366*2810ac1bSKiyoung Kim// stored in a portable way. Note, any namespace owner in the Set 367*2810ac1bSKiyoung Kim// content is not exported by this function. 368*2810ac1bSKiyoung Kim// 369*2810ac1bSKiyoung Kim// Note, Export() generates exported byte streams that are importable 370*2810ac1bSKiyoung Kim// by libcap.cap_copy_int() as well as Import(). 371*2810ac1bSKiyoung Kimfunc (c *Set) Export() ([]byte, error) { 372*2810ac1bSKiyoung Kim if err := c.good(); err != nil { 373*2810ac1bSKiyoung Kim return nil, err 374*2810ac1bSKiyoung Kim } 375*2810ac1bSKiyoung Kim if MinExtFlagSize > 255 { 376*2810ac1bSKiyoung Kim return nil, ErrOutOfRange 377*2810ac1bSKiyoung Kim } 378*2810ac1bSKiyoung Kim b := new(bytes.Buffer) 379*2810ac1bSKiyoung Kim binary.Write(b, binary.LittleEndian, ExtMagic) 380*2810ac1bSKiyoung Kim c.mu.RLock() 381*2810ac1bSKiyoung Kim defer c.mu.RUnlock() 382*2810ac1bSKiyoung Kim var n = uint(0) 383*2810ac1bSKiyoung Kim for i, f := range c.flat { 384*2810ac1bSKiyoung Kim if nn := 4 * uint(i); nn+4 > n { 385*2810ac1bSKiyoung Kim if u := f[Effective] | f[Permitted] | f[Inheritable]; u != 0 { 386*2810ac1bSKiyoung Kim n = nn 387*2810ac1bSKiyoung Kim for ; u != 0; u >>= 8 { 388*2810ac1bSKiyoung Kim n++ 389*2810ac1bSKiyoung Kim } 390*2810ac1bSKiyoung Kim } 391*2810ac1bSKiyoung Kim } 392*2810ac1bSKiyoung Kim } 393*2810ac1bSKiyoung Kim if n < MinExtFlagSize { 394*2810ac1bSKiyoung Kim n = MinExtFlagSize 395*2810ac1bSKiyoung Kim } 396*2810ac1bSKiyoung Kim b.Write([]byte{byte(n)}) 397*2810ac1bSKiyoung Kim for _, f := range c.flat { 398*2810ac1bSKiyoung Kim if n == 0 { 399*2810ac1bSKiyoung Kim break 400*2810ac1bSKiyoung Kim } 401*2810ac1bSKiyoung Kim eff, per, inh := f[Effective], f[Permitted], f[Inheritable] 402*2810ac1bSKiyoung Kim for i := 0; n > 0 && i < 4; i++ { 403*2810ac1bSKiyoung Kim n-- 404*2810ac1bSKiyoung Kim b.Write([]byte{ 405*2810ac1bSKiyoung Kim byte(eff & 0xff), 406*2810ac1bSKiyoung Kim byte(per & 0xff), 407*2810ac1bSKiyoung Kim byte(inh & 0xff), 408*2810ac1bSKiyoung Kim }) 409*2810ac1bSKiyoung Kim eff >>= 8 410*2810ac1bSKiyoung Kim per >>= 8 411*2810ac1bSKiyoung Kim inh >>= 8 412*2810ac1bSKiyoung Kim } 413*2810ac1bSKiyoung Kim } 414*2810ac1bSKiyoung Kim for n > 0 { 415*2810ac1bSKiyoung Kim n-- 416*2810ac1bSKiyoung Kim b.Write([]byte{0, 0, 0}) 417*2810ac1bSKiyoung Kim } 418*2810ac1bSKiyoung Kim return b.Bytes(), nil 419*2810ac1bSKiyoung Kim} 420