aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
blob: 3d2bf6927f3701cf2fed11708ee3c1d2cff04f0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package capability

import (
	"syscall"
	"unsafe"
)

type capHeader struct {
	version uint32
	pid     int32
}

type capData struct {
	effective   uint32
	permitted   uint32
	inheritable uint32
}

func capget(hdr *capHeader, data *capData) (err error) {
	_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
	if e1 != 0 {
		err = e1
	}
	return
}

func capset(hdr *capHeader, data *capData) (err error) {
	_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
	if e1 != 0 {
		err = e1
	}
	return
}

// not yet in syscall
const (
	pr_CAP_AMBIENT           = 47
	pr_CAP_AMBIENT_IS_SET    = uintptr(1)
	pr_CAP_AMBIENT_RAISE     = uintptr(2)
	pr_CAP_AMBIENT_LOWER     = uintptr(3)
	pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
)

func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
	_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
	if e1 != 0 {
		err = e1
	}
	return
}

const (
	vfsXattrName = "security.capability"

	vfsCapVerMask = 0xff000000
	vfsCapVer1    = 0x01000000
	vfsCapVer2    = 0x02000000

	vfsCapFlagMask      = ^vfsCapVerMask
	vfsCapFlageffective = 0x000001

	vfscapDataSizeV1 = 4 * (1 + 2*1)
	vfscapDataSizeV2 = 4 * (1 + 2*2)
)

type vfscapData struct {
	magic uint32
	data  [2]struct {
		permitted   uint32
		inheritable uint32
	}
	effective [2]uint32
	version   int8
}

var (
	_vfsXattrName *byte
)

func init() {
	_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
}

func getVfsCap(path string, dest *vfscapData) (err error) {
	var _p0 *byte
	_p0, err = syscall.BytePtrFromString(path)
	if err != nil {
		return
	}
	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
	if e1 != 0 {
		if e1 == syscall.ENODATA {
			dest.version = 2
			return
		}
		err = e1
	}
	switch dest.magic & vfsCapVerMask {
	case vfsCapVer1:
		dest.version = 1
		if r0 != vfscapDataSizeV1 {
			return syscall.EINVAL
		}
		dest.data[1].permitted = 0
		dest.data[1].inheritable = 0
	case vfsCapVer2:
		dest.version = 2
		if r0 != vfscapDataSizeV2 {
			return syscall.EINVAL
		}
	default:
		return syscall.EINVAL
	}
	if dest.magic&vfsCapFlageffective != 0 {
		dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable
		dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable
	} else {
		dest.effective[0] = 0
		dest.effective[1] = 0
	}
	return
}

func setVfsCap(path string, data *vfscapData) (err error) {
	var _p0 *byte
	_p0, err = syscall.BytePtrFromString(path)
	if err != nil {
		return
	}
	var size uintptr
	if data.version == 1 {
		data.magic = vfsCapVer1
		size = vfscapDataSizeV1
	} else if data.version == 2 {
		data.magic = vfsCapVer2
		if data.effective[0] != 0 || data.effective[1] != 0 {
			data.magic |= vfsCapFlageffective
		}
		size = vfscapDataSizeV2
	} else {
		return syscall.EINVAL
	}
	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
	if e1 != 0 {
		err = e1
	}
	return
}