xref: /aosp_15_r20/external/libcap/cap/file.go (revision 2810ac1b38eead2603277920c78344c84ddf3aff)
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