-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Don't deny all devices when update cgroup resource #2205
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
package fs | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/opencontainers/runc/libcontainer/cgroups" | ||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon" | ||
"github.com/opencontainers/runc/libcontainer/configs" | ||
|
@@ -12,6 +14,12 @@ import ( | |
type DevicesGroup struct { | ||
} | ||
|
||
type Empty struct{} | ||
|
||
var ( | ||
defaultDevice = &configs.Device{Type: 'a', Major: -1, Minor: -1, Permissions: "rwm"} | ||
) | ||
|
||
func (s *DevicesGroup) Name() string { | ||
return "devices" | ||
} | ||
|
@@ -32,29 +40,63 @@ func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { | |
} | ||
|
||
devices := cgroup.Resources.Devices | ||
oldAllowedDevices, err := readDevicesExceptDefault(path) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if len(devices) > 0 { | ||
for _, dev := range devices { | ||
file := "devices.deny" | ||
if dev.Allow { | ||
file = "devices.allow" | ||
} | ||
if err := fscommon.WriteFile(path, file, dev.CgroupString()); err != nil { | ||
return err | ||
|
||
// For the second time set, we don't deny all devices | ||
if dev.Type == defaultDevice.Type && len(oldAllowedDevices) != 0 { | ||
file = "" | ||
} | ||
|
||
if len(file) > 0 { | ||
if err := fscommon.WriteFile(path, file, dev.CgroupString()); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
if cgroup.Resources.AllowAllDevices != nil { | ||
if *cgroup.Resources.AllowAllDevices == false { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't directly related to this patch (and is something we should fix separately), but I've hit this wall while trying to review it. I've spent a while now trying to understand what the hell this whole In the context of this patch, I'm not even sure how to review whether the semantics of the below code are correct -- if I'm correct in my understanding that nothing uses the code, how do we know if the changes make sense... @crosbymichael Am I missing something? Will something really bad happen if we get rid of it? I remember the @AkihiroSuda WDYT? (Since you were the last person to touch it, and I think @crosbymichael and I last looked at this code in 2016.) |
||
if err := fscommon.WriteFile(path, "devices.deny", "a"); err != nil { | ||
return err | ||
// For the first time set, we deny all devices to initialize the cgroup | ||
if len(oldAllowedDevices) == 0 { | ||
if err := fscommon.WriteFile(path, "devices.deny", "a"); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
for _, dev := range cgroup.Resources.AllowedDevices { | ||
if err := fscommon.WriteFile(path, "devices.allow", dev.CgroupString()); err != nil { | ||
return err | ||
newAllowedDevices := make(map[string]Empty) | ||
for _, dev := range cgroup.AllowedDevices { | ||
newAllowedDevices[dev.CgroupString()] = Empty{} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should loop over |
||
|
||
// Deny no longer allowed devices | ||
for cgroupString := range oldAllowedDevices { | ||
if _, found := newAllowedDevices[cgroupString]; !found { | ||
if err := fscommon.WriteFile(path, "devices.deny", cgroupString); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
|
||
// Allow new devices | ||
for cgroupString := range newAllowedDevices { | ||
if _, found := oldAllowedDevices[cgroupString]; !found { | ||
if err := fscommon.WriteFile(path, "devices.allow", cgroupString); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
|
@@ -79,3 +121,22 @@ func (s *DevicesGroup) Remove(d *cgroupData) error { | |
func (s *DevicesGroup) GetStats(path string, stats *cgroups.Stats) error { | ||
return nil | ||
} | ||
|
||
func readDevicesExceptDefault(path string) (allowed map[string]Empty, err error) { | ||
cgroupData, err := fscommon.ReadFile(path, "devices.list") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
allowedDevices := make(map[string]Empty) | ||
defaultDeviceString := defaultDevice.CgroupString() | ||
for _, data := range strings.Split(cgroupData, "\n") { | ||
// skip allow all devices | ||
if len(data) == 0 || data == defaultDeviceString { | ||
continue | ||
} | ||
allowedDevices[data] = Empty{} | ||
} | ||
|
||
return allowedDevices, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't like this, and after looking at it for a bit I think I'm convinced it isn't right.
This code will ignore any update that containsBut even if this check wasa
-- but there are valid use-cases fora
other than "deny everything" (you can allow both character and block devices for a particular major number, for instance).dev == defaultDevice
it'd still be wrong since you can also allow all devices (though you shouldn't) -- and that would be ignored.I think the issue is that the caller shouldn't be specifying a default deny rule in the list which we then need to filter out -- that should be done as part of this module. So we figure out what rules we need to specify.
EDIT: My comment about
a
was wrong, I forgot thata
always means everything, and that you can't specify both block and character devices.