Skip to content

Commit a4f3123

Browse files
committed
Fix thread safety of SelinuxEnabled and getSelinuxMountPoint
Both suffered from different race conditions. SelinuxEnabled assigned selinuxEnabledChecked before selinuxEnabled. Thus racing callers could see the wrong selinuxEnabled. getSelinuxMountPoint assigned selinuxfs to "" before it know the right value. Thus racing could see "" improperly. The gate selinuxfs, enabled, and mclist all on the same lock
1 parent 5974b4c commit a4f3123

File tree

1 file changed

+73
-33
lines changed

1 file changed

+73
-33
lines changed

libcontainer/selinux/selinux.go

Lines changed: 73 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,33 +32,73 @@ const (
3232
stRdOnly = 0x01
3333
)
3434

35+
type selinuxState struct {
36+
enabledSet bool
37+
enabled bool
38+
selinuxfsSet bool
39+
selinuxfs string
40+
mcsList map[string]bool
41+
sync.Mutex
42+
}
43+
3544
var (
36-
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
37-
mcsList = make(map[string]bool)
38-
mcsLock sync.Mutex
39-
selinuxfs = "unknown"
40-
selinuxEnabled = false // Stores whether selinux is currently enabled
41-
selinuxEnabledChecked = false // Stores whether selinux enablement has been checked or established yet
45+
assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
46+
state = selinuxState{
47+
mcsList: make(map[string]bool),
48+
}
4249
)
4350

4451
type SELinuxContext map[string]string
4552

53+
func (s *selinuxState) setEnable(enabled bool) bool {
54+
s.Lock()
55+
defer s.Unlock()
56+
s.enabledSet = true
57+
s.enabled = enabled
58+
return s.enabled
59+
}
60+
61+
func (s *selinuxState) getEnabled() bool {
62+
s.Lock()
63+
enabled := s.enabled
64+
enabledSet := s.enabledSet
65+
s.Unlock()
66+
if enabledSet {
67+
return enabled
68+
}
69+
70+
enabled = false
71+
if fs := getSelinuxMountPoint(); fs != "" {
72+
if con, _ := Getcon(); con != "kernel" {
73+
enabled = true
74+
}
75+
}
76+
return s.setEnable(enabled)
77+
}
78+
4679
// SetDisabled disables selinux support for the package
4780
func SetDisabled() {
48-
selinuxEnabled, selinuxEnabledChecked = false, true
81+
state.setEnable(false)
4982
}
5083

51-
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
52-
// filesystem or an empty string if no mountpoint is found. Selinuxfs is
53-
// a proc-like pseudo-filesystem that exposes the selinux policy API to
54-
// processes. The existence of an selinuxfs mount is used to determine
55-
// whether selinux is currently enabled or not.
56-
func getSelinuxMountPoint() string {
57-
if selinuxfs != "unknown" {
84+
func (s *selinuxState) setSELinuxfs(selinuxfs string) string {
85+
s.Lock()
86+
defer s.Unlock()
87+
s.selinuxfsSet = true
88+
s.selinuxfs = selinuxfs
89+
return s.selinuxfs
90+
}
91+
92+
func (s *selinuxState) getSELinuxfs() string {
93+
s.Lock()
94+
selinuxfs := s.selinuxfs
95+
selinuxfsSet := s.selinuxfsSet
96+
s.Unlock()
97+
if selinuxfsSet {
5898
return selinuxfs
5999
}
60-
selinuxfs = ""
61100

101+
selinuxfs = ""
62102
f, err := os.Open("/proc/self/mountinfo")
63103
if err != nil {
64104
return selinuxfs
@@ -91,21 +131,21 @@ func getSelinuxMountPoint() string {
91131
selinuxfs = ""
92132
}
93133
}
94-
return selinuxfs
134+
return s.setSELinuxfs(selinuxfs)
135+
}
136+
137+
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
138+
// filesystem or an empty string if no mountpoint is found. Selinuxfs is
139+
// a proc-like pseudo-filesystem that exposes the selinux policy API to
140+
// processes. The existence of an selinuxfs mount is used to determine
141+
// whether selinux is currently enabled or not.
142+
func getSelinuxMountPoint() string {
143+
return state.getSELinuxfs()
95144
}
96145

97146
// SelinuxEnabled returns whether selinux is currently enabled.
98147
func SelinuxEnabled() bool {
99-
if selinuxEnabledChecked {
100-
return selinuxEnabled
101-
}
102-
selinuxEnabledChecked = true
103-
if fs := getSelinuxMountPoint(); fs != "" {
104-
if con, _ := Getcon(); con != "kernel" {
105-
selinuxEnabled = true
106-
}
107-
}
108-
return selinuxEnabled
148+
return state.getEnabled()
109149
}
110150

111151
func readConfig(target string) (value string) {
@@ -283,19 +323,19 @@ func SelinuxGetEnforceMode() int {
283323
}
284324

285325
func mcsAdd(mcs string) error {
286-
mcsLock.Lock()
287-
defer mcsLock.Unlock()
288-
if mcsList[mcs] {
326+
state.Lock()
327+
defer state.Unlock()
328+
if state.mcsList[mcs] {
289329
return fmt.Errorf("MCS Label already exists")
290330
}
291-
mcsList[mcs] = true
331+
state.mcsList[mcs] = true
292332
return nil
293333
}
294334

295335
func mcsDelete(mcs string) {
296-
mcsLock.Lock()
297-
mcsList[mcs] = false
298-
mcsLock.Unlock()
336+
state.Lock()
337+
defer state.Unlock()
338+
state.mcsList[mcs] = false
299339
}
300340

301341
func IntToMcs(id int, catRange uint32) string {

0 commit comments

Comments
 (0)