aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runc/libcontainer/devices/device.go
blob: c2c2b3bb7c0b44859f78362778c280ab97572546 (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
171
172
173
174
package devices

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

const (
	Wildcard = -1
)

type Device struct {
	Rule

	// 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"`
}

// Permissions 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 Permissions string

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

func (p Permissions) 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) Permissions {
	var perm string
	if set&deviceRead == deviceRead {
		perm += "r"
	}
	if set&deviceWrite == deviceWrite {
		perm += "w"
	}
	if set&deviceMknod == deviceMknod {
		perm += "m"
	}
	return Permissions(perm)
}

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

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

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

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

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

type Type rune

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

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

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

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

type Rule 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 Type `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 Permissions `json:"permissions"`

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

func (d *Rule) 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)
}

func (d *Rule) Mkdev() (uint64, error) {
	return mkDev(d)
}