Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion features.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ var featuresCommand = cli.Command{
Enabled: &t,
},
IntelRdt: &features.IntelRdt{
Enabled: &t,
Enabled: &t,
Monitoring: &t,
},
MountExtensions: &features.MountExtensions{
IDMap: &features.IDMap{
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/moby/sys/userns v0.1.0
github.com/mrunalp/fileutils v0.5.1
github.com/opencontainers/cgroups v0.0.4
github.com/opencontainers/runtime-spec v1.2.2-0.20250401095657-e935f995dd67
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0
github.com/opencontainers/selinux v1.12.0
github.com/seccomp/libseccomp-golang v0.11.1
github.com/sirupsen/logrus v1.9.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ github.com/mrunalp/fileutils v0.5.1 h1:F+S7ZlNKnrwHfSwdlgNSkKo67ReVf8o9fel6C3dkm
github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/opencontainers/cgroups v0.0.4 h1:XVj8P/IHVms/j+7eh8ggdkTLAxjz84ZzuFyGoE28DR4=
github.com/opencontainers/cgroups v0.0.4/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs=
github.com/opencontainers/runtime-spec v1.2.2-0.20250401095657-e935f995dd67 h1:Q+KewUGTMamIe6Q39xCD/T1NC1POmaTlWnhjikCrZHA=
github.com/opencontainers/runtime-spec v1.2.2-0.20250401095657-e935f995dd67/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0 h1:RLn0YfUWkiqPGtgUANvJrcjIkCHGRl3jcz/c557M28M=
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8=
github.com/opencontainers/selinux v1.12.0/go.mod h1:BTPX+bjVbWGXw7ZZWUbdENt8w0htPSrlgOOysQaU62U=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down
3 changes: 3 additions & 0 deletions libcontainer/configs/intelrdt.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ type IntelRdt struct {
// The unit of memory bandwidth is specified in "percentages" by
// default, and in "MBps" if MBA Software Controller is enabled.
MemBwSchema string `json:"memBwSchema,omitempty"`

// Create a monitoring group for the container.
EnableMonitoring bool `json:"enableMonitoring,omitempty"`
}
17 changes: 4 additions & 13 deletions libcontainer/configs/validate/intelrdt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,24 @@ func TestValidateIntelRdt(t *testing.T) {
isErr bool
}{
{
name: "rdt not supported, no config",
rdtEnabled: false,
config: nil,
isErr: false,
name: "rdt not supported, no config",
},
{
name: "rdt not supported, with config",
rdtEnabled: false,
config: &configs.IntelRdt{},
isErr: true,
name: "rdt not supported, with config",
config: &configs.IntelRdt{},
isErr: true,
},
{
name: "empty config",
rdtEnabled: true,
config: &configs.IntelRdt{},
isErr: false,
},
{
name: "root clos",
rdtEnabled: true,
config: &configs.IntelRdt{
ClosID: "/",
},
isErr: false,
},
{
name: "invalid ClosID (.)",
Expand Down Expand Up @@ -71,7 +65,6 @@ func TestValidateIntelRdt(t *testing.T) {
{
name: "cat not supported",
rdtEnabled: true,
catEnabled: false,
config: &configs.IntelRdt{
L3CacheSchema: "0=ff",
},
Expand All @@ -80,7 +73,6 @@ func TestValidateIntelRdt(t *testing.T) {
{
name: "mba not supported",
rdtEnabled: true,
mbaEnabled: false,
config: &configs.IntelRdt{
MemBwSchema: "0=100",
},
Expand All @@ -96,7 +88,6 @@ func TestValidateIntelRdt(t *testing.T) {
L3CacheSchema: "0=ff",
MemBwSchema: "0=100",
},
isErr: false,
},
}
for _, tc := range testCases {
Expand Down
8 changes: 8 additions & 0 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ type State struct {

// Intel RDT "resource control" filesystem path.
IntelRdtPath string `json:"intel_rdt_path,omitempty"`

// Path of the container specific monitoring group in resctrl filesystem.
// Empty if the container does not have aindividual dedicated monitoring
// group.
IntelRdtMonPath string `json:"intel_rdt_mon_path,omitempty"`
}

// ID returns the container's unique ID
Expand Down Expand Up @@ -942,8 +947,10 @@ func (c *Container) currentState() *State {
}

intelRdtPath := ""
intelRdtMonPath := ""
if c.intelRdtManager != nil {
intelRdtPath = c.intelRdtManager.GetPath()
intelRdtMonPath = c.intelRdtManager.GetMonPath()
}
state := &State{
BaseState: BaseState{
Expand All @@ -956,6 +963,7 @@ func (c *Container) currentState() *State {
Rootless: c.config.RootlessEUID && c.config.RootlessCgroups,
CgroupPaths: c.cgroupManager.GetPaths(),
IntelRdtPath: intelRdtPath,
IntelRdtMonPath: intelRdtMonPath,
NamespacePaths: make(map[configs.NamespaceType]string),
ExternalDescriptors: externalDescriptors,
}
Expand Down
47 changes: 45 additions & 2 deletions libcontainer/intelrdt/intelrdt.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,22 +478,41 @@ func (m *Manager) Apply(pid int) (err error) {
return newLastCmdError(err)
}

// Create MON group
if monPath := m.GetMonPath(); monPath != "" {
if err := os.Mkdir(monPath, 0o755); err != nil && !os.IsExist(err) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who has control of this path? In runc this is trusted, okay, but is it exposed in k8s or containerd or some other to the user?

Not sure with the https://github.com/intel/k8s-rdt-controller what is exposed to an end user

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's runc, it's in this very same file (and patch):

func (m *Manager) GetMonPath() string {
	if closPath := m.GetPath(); closPath != "" && m.config.IntelRdt.EnableMonitoring {
		path, err := securejoin.SecureJoin(filepath.Join(closPath, "mon_groups"), m.id)

So it's basically <clos-dir>/mon_groups/<container-id>

Copy link
Member

@rata rata Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, and that comes from intelRdtRoot. But where does that come from? Is there any way an unprivileged user (or just anyone that is not the sysadmin or so) can control any path component (or the intelRDT root)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That, in turn, comes from parsing the output of statfs syscall (unix.Statfs()). Note that in the case of runc update the closPath is taken from the config.json of the container.

In any case I cannot see any way that an unprivileged user can control the path

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So statfs will have some string value and we will mkdir it on the host, outside of the container rootfs?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversation was broken out of this thread, it continued in the main PR discussion. The final answer I found for this is posted here: #4832 (comment)

Basically, the fs will be mounted somewhere on the host by the admin and we might create/delete some dirs inside that. None of that is accessible to the container process.

@marquiz correct me if I'm getting something wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kolyshkin PTAL, I'd like someone else to look at this part too, just in case I'm missing something :)

return newLastCmdError(err)
}
if err := WriteIntelRdtTasks(monPath, pid); err != nil {
return newLastCmdError(err)
}
}

m.path = path
return nil
}

// Destroy destroys the Intel RDT container-specific container_id group.
func (m *Manager) Destroy() error {
if m.config.IntelRdt == nil {
return nil
}
// Don't remove resctrl group if closid has been explicitly specified. The
// group is likely externally managed, i.e. by some other entity than us.
// There are probably other containers/tasks sharing the same group.
if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID == "" {
if m.config.IntelRdt.ClosID == "" {
m.mu.Lock()
defer m.mu.Unlock()
if err := os.Remove(m.GetPath()); err != nil && !os.IsNotExist(err) {
return err
}
m.path = ""
} else if monPath := m.GetMonPath(); monPath != "" {
// If ClosID is not specified the possible monintoring group was
// removed with the CLOS above.
if err := os.Remove(monPath); err != nil && !os.IsNotExist(err) {
return err
}
}
return nil
}
Expand All @@ -504,6 +523,21 @@ func (m *Manager) GetPath() string {
return m.path
}

// GetMonPath returns path of the monitoring group of the container. Returns an
// empty string if the container does not have a individual dedicated
// monitoring group.
func (m *Manager) GetMonPath() string {
if !m.config.IntelRdt.EnableMonitoring {
return ""
}
closPath := m.GetPath()
if closPath == "" {
return ""
}

return filepath.Join(closPath, "mon_groups", m.id)
}

// GetStats returns statistics for Intel RDT.
func (m *Manager) GetStats() (*Stats, error) {
// If intelRdt is not specified in config
Expand Down Expand Up @@ -581,7 +615,16 @@ func (m *Manager) GetStats() (*Stats, error) {
}

if IsMBMEnabled() || IsCMTEnabled() {
err = getMonitoringStats(containerPath, stats)
monPath := m.GetMonPath()
if monPath == "" {
// NOTE: If per-container monitoring is not enabled, the monitoring
// data we get here might have little to do with this container as
// there might be anything from this single container to the half
// of the system assigned in the group. Should consider not
// exposing stats in this case(?)
monPath = containerPath
}
err = getMonitoringStats(monPath, stats)
if err != nil {
return nil, err
}
Expand Down
Loading