-
Notifications
You must be signed in to change notification settings - Fork 2.2k
update.go: fix nil pointer risk in Intel RDT initialization #4774
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
base: main
Are you sure you want to change the base?
update.go: fix nil pointer risk in Intel RDT initialization #4774
Conversation
53a77e5
to
314b79a
Compare
Hi! While working on this PR, I noticed that the CI fails due to Example: if l.Level != expectedLogs.Level { This triggers:
This can be safely resolved using: if l != nil && l.Level != expectedLogs.Level { There are similar occurrences in:
Let me know if you'd like me to submit a cleanup PR to address these 🙌 Thanks! |
@@ -363,6 +363,9 @@ other options are ignored. | |||
} | |||
config.IntelRdt = &configs.IntelRdt{} | |||
intelRdtManager := intelrdt.NewManager(&config, container.ID(), state.IntelRdtPath) | |||
if intelRdtManager == 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.
Thanks your contribution.
I think the only position of returning nil
is here:
runc/libcontainer/intelrdt/intelrdt.go
Lines 162 to 165 in 314b79a
if _, err := Root(); err != nil { | |
// Intel RDT is not available. | |
return nil | |
} |
But unfortunately, we didn't return the error to the caller, so I think we should add an error log in L163 to let the user know what's happened. WDYT?
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.
Good catch — you're right, NewManager() can return nil from intelrdt.go when Root() fails.
I've added a log message at that point in update.go to inform the user when RDT is unavailable.
Pushed the change, thanks again!
d12a3f2
to
94aaf27
Compare
update.go
Outdated
@@ -363,6 +363,10 @@ other options are ignored. | |||
} | |||
config.IntelRdt = &configs.IntelRdt{} | |||
intelRdtManager := intelrdt.NewManager(&config, container.ID(), state.IntelRdtPath) | |||
if intelRdtManager == nil { | |||
logrus.Errorf("Intel RDT is not available: resctrl filesystem not found or unsupported") |
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 think you misunderstood my comment, you should add the log in here:
runc/libcontainer/intelrdt/intelrdt.go
Lines 162 to 165 in 314b79a
if _, err := Root(); err != nil { | |
// Intel RDT is not available. | |
return nil | |
} |
Because no one knows what’s contents in this ‘err’.
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.
For example:
logrus.Errorf("Intel RDT is not available: %v", err)
94aaf27
to
290b43b
Compare
Static analysis revealed a possible nil dereference when applying Intel RDT configurations. The `NewManager()` function can return nil if Intel RDT is not supported by the kernel (e.g. no resctrl filesystem mounted), but the caller in `update.go` did not check for this condition. This patch adds an explicit nil check after NewManager() is called, with a descriptive log message to help users understand the failure. In addition, `NewManager()` itself now logs the underlying reason (using the error from `Root()`), improving observability. This issue was originally identified via static analysis: > update.go:367:9: undefined: log > and: Return value of function 'NewManager' will be overwritten Signed-off-by: AntonMoryakov <[email protected]>
290b43b
to
d3505b9
Compare
@@ -363,6 +363,10 @@ other options are ignored. | |||
} | |||
config.IntelRdt = &configs.IntelRdt{} | |||
intelRdtManager := intelrdt.NewManager(&config, container.ID(), state.IntelRdtPath) | |||
if intelRdtManager == nil { | |||
logrus.Errorf("Intel RDT manager creation failed: likely due to missing resctrl filesystem") |
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.
This line should be removed.
@@ -161,6 +162,7 @@ func NewManager(config *configs.Config, id string, path string) *Manager { | |||
} | |||
if _, err := Root(); err != nil { | |||
// Intel RDT is not available. | |||
logrus.Errorf("Intel RDT is not available: %v", err) |
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'm sorry to say that, I think we should remove this line now. Please see my comment as follows.
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.
If we want to keep this, we should return error in update.go
, for example:
if intelRdtManager == nil {
return fmt.Erroff("Intel RDT manager creation failed: likely due to missing resctrl filesystem")
}
@@ -363,6 +363,10 @@ other options are ignored. | |||
} | |||
config.IntelRdt = &configs.IntelRdt{} | |||
intelRdtManager := intelrdt.NewManager(&config, container.ID(), state.IntelRdtPath) | |||
if intelRdtManager == nil { | |||
logrus.Errorf("Intel RDT manager creation failed: likely due to missing resctrl filesystem") | |||
return 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.
We should not return nil here. I think the entire logic should be changed like this:
if intelRdtManager != nil && err := intelRdtManager.Apply(state.InitProcessPid); err != 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.
Like my comment in #4774 (comment)
I think that one is more reasonable, WDYT?
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.
NACK
A nil dereference is not possible here, because in update.go we call intelrdt.IsCATEnabled
and intelrdt.IsMBAEnabled
earlier, and if Root
returns nil, we'll error out here:
if l3CacheSchema != "" && !intelrdt.IsCATEnabled() {
return errors.New("Intel RDT/CAT: l3 cache schema is not enabled")
}
if memBwSchema != "" && !intelrdt.IsMBAEnabled() {
return errors.New("Intel RDT/MBA: memory bandwidth schema is not enabled")
}
Thanks for the feedback and the detailed explanation! You’re absolutely right — after reviewing the call chain and how intelrdt.IsCATEnabled() and intelrdt.IsMBAEnabled() rely on Root(), I agree that this is a false positive from the static analyzer. Can we close this PR then? Thanks again for the clarification! |
Which static analysis tool did you use? I use 'go vet ./...' to test, I can't see any static check errors. |
In practice, this nil check isn't strictly necessary. However, as a good coding practice, I think it's worthwhile to include a nil check here. It helps prevent potential errors when refactoring this code in the future. It's just my own opinion, please feel free to close it. |
static analyzers like SVACE |
Static analysis revealed potential nil dereference when applying RDT
configurations. The intelRdtManager instance from NewManager() could be
nil but was used without check in Apply() call.
Added explicit nil check that returns error to fail safely rather than
panic. This matches error handling patterns used elsewhere in the codebase.
Signed-off-by: Anton Moryakov [email protected]