aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go
blob: 632bf6ac49cc30a4bb61e300e5344d16fa686b5c (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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package configs

import (
	"fmt"
	"os"
	"strconv"
)

const (
	Wildcard = -1
)

type Device struct {
	DeviceRule

	// Path to the device.
	Path string `json:"path"`

	// FileMode permission bits for the device.
	FileMode os.FileMode `json:"file_mode"`

	// Uid of the device.
	Uid uint32 `json:"uid"`

	// Gid of the device.
	Gid uint32 `json:"gid"`
}

// DevicePermissions is a cgroupv1-style string to represent device access. It
// has to be a string for backward compatibility reasons, hence why it has
// methods to do set operations.
type DevicePermissions string

const (
	deviceRead uint = (1 << iota)
	deviceWrite
	deviceMknod
)

func (p DevicePermissions) toSet() uint {
	var set uint
	for _, perm := range p {
		switch perm {
		case 'r':
			set |= deviceRead
		case 'w':
			set |= deviceWrite
		case 'm':
			set |= deviceMknod
		}
	}
	return set
}

func fromSet(set uint) DevicePermissions {
	var perm string
	if set&deviceRead == deviceRead {
		perm += "r"
	}
	if set&deviceWrite == deviceWrite {
		perm += "w"
	}
	if set&deviceMknod == deviceMknod {
		perm += "m"
	}
	return DevicePermissions(perm)
}

// Union returns the union of the two sets of DevicePermissions.
func (p DevicePermissions) Union(o DevicePermissions) DevicePermissions {
	lhs := p.toSet()
	rhs := o.toSet()
	return fromSet(lhs | rhs)
}

// Difference returns the set difference of the two sets of DevicePermissions.
// In set notation, A.Difference(B) gives you A\B.
func (p DevicePermissions) Difference(o DevicePermissions) DevicePermissions {
	lhs := p.toSet()
	rhs := o.toSet()
	return fromSet(lhs &^ rhs)
}

// Intersection computes the intersection of the two sets of DevicePermissions.
func (p DevicePermissions) Intersection(o DevicePermissions) DevicePermissions {
	lhs := p.toSet()
	rhs := o.toSet()
	return fromSet(lhs & rhs)
}

// IsEmpty returns whether the set of permissions in a DevicePermissions is
// empty.
func (p DevicePermissions) IsEmpty() bool {
	return p == DevicePermissions("")
}

// IsValid returns whether the set of permissions is a subset of valid
// permissions (namely, {r,w,m}).
func (p DevicePermissions) IsValid() bool {
	return p == fromSet(p.toSet())
}

type DeviceType rune

const (
	WildcardDevice DeviceType = 'a'
	BlockDevice    DeviceType = 'b'
	CharDevice     DeviceType = 'c' // or 'u'
	FifoDevice     DeviceType = 'p'
)

func (t DeviceType) IsValid() bool {
	switch t {
	case WildcardDevice, BlockDevice, CharDevice, FifoDevice:
		return true
	default:
		return false
	}
}

func (t DeviceType) CanMknod() bool {
	switch t {
	case BlockDevice, CharDevice, FifoDevice:
		return true
	default:
		return false
	}
}

func (t DeviceType) CanCgroup() bool {
	switch t {
	case WildcardDevice, BlockDevice, CharDevice:
		return true
	default:
		return false
	}
}

type DeviceRule struct {
	// Type of device ('c' for char, 'b' for block). If set to 'a', this rule
	// acts as a wildcard and all fields other than Allow are ignored.
	Type DeviceType `json:"type"`

	// Major is the device's major number.
	Major int64 `json:"major"`

	// Minor is the device's minor number.
	Minor int64 `json:"minor"`

	// Permissions is the set of permissions that this rule applies to (in the
	// cgroupv1 format -- any combination of "rwm").
	Permissions DevicePermissions `json:"permissions"`

	// Allow specifies whether this rule is allowed.
	Allow bool `json:"allow"`
}

func (d *DeviceRule) CgroupString() string {
	var (
		major = strconv.FormatInt(d.Major, 10)
		minor = strconv.FormatInt(d.Minor, 10)
	)
	if d.Major == Wildcard {
		major = "*"
	}
	if d.Minor == Wildcard {
		minor = "*"
	}
	return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions)
}