Skip to content

util_linux: add connection close in setupIO #4780

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

mi4r
Copy link

@mi4r mi4r commented Jun 9, 2025

If an error occurs while creating a file descriptor using socket, err := uc.File(), this error is returned to the calling runner.run function. The runner.run function also simply returns this error, and, as a result, the connection created in the line conn, err := net.Dial("unix", sockpath) remains open.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

If an error occurs while creating a file descriptor using
socket, err := uc.File(), this error is returned to the calling
runner.run function. The runner.run function also simply returns
this error, and, as a result, the connection created in the line
conn, err := net.Dial("unix", sockpath) remains open.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Tigran Sogomonian <[email protected]>
utils_linux.go Outdated
@@ -123,11 +123,13 @@ func setupIO(process *libcontainer.Process, container *libcontainer.Container, c
}
uc, ok := conn.(*net.UnixConn)
if !ok {
conn.Close()
Copy link
Member

Choose a reason for hiding this comment

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

Thank you for your contribution.

In practice, omitting these close operations doesn't cause any harm, since runc will exit anyway if an error occurs during the setupIO call.

However, from a code style and best practices perspective, I think we should always close the socket connection once an error is encountered after the connection has been established.

Considering both aspects, LGTM.

Copy link
Member

@rata rata left a comment

Choose a reason for hiding this comment

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

Thanks for the PR. Let's do some small changes before we merge :)

utils_linux.go Outdated
@@ -123,11 +123,13 @@ func setupIO(process *libcontainer.Process, container *libcontainer.Container, c
}
uc, ok := conn.(*net.UnixConn)
if !ok {
conn.Close()
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand, if the result is not ok can the connection still be open. Are you sure?

utils_linux.go Outdated
return nil, errors.New("casting to UnixConn failed")
}
t.postStart = append(t.postStart, uc)
socket, err := uc.File()
if err != nil {
conn.Close()
Copy link
Member

Choose a reason for hiding this comment

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

Let's avoid having to do this on every exit path. Please create a defer after the connection is established, that is an inline function and does a conn.Close only if we are returning an error.

Copy link
Author

Choose a reason for hiding this comment

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

And if we put defer, won't we close the connection in any case (success and error) when exiting the function? Or do you mean that a simple defer is not needed?

Copy link
Member

Choose a reason for hiding this comment

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

We can do a defer that checks if we are returning with error. See for example here:

runc/tty.go

Lines 123 to 127 in c3d127f

defer func() {
if Err != nil {
_ = epollConsole.Close()
}
}()

You defer a function, and you have a named return. Then, in that function you check if the error we are returning is not nil, then you do the close. I think we can use the same here, can't we?

Copy link
Author

Choose a reason for hiding this comment

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

I do it like that but have failed in CI. What's wrong?

Copy link
Member

Choose a reason for hiding this comment

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

I guess you figured it out?

Make connection close using defer.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Tigran Sogomonian <[email protected]>
utils_linux.go Outdated
conn, err := net.Dial("unix", sockpath)
if err != nil {
return nil, err
conn, Err := net.Dial("unix", sockpath)
Copy link
Member

Choose a reason for hiding this comment

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

You can keep the original err variable here — there's no need to change it to Err.

Since the function uses a named return value, assigning err will automatically set the return value correctly.

utils_linux.go Outdated
socket, err := uc.File()
if err != nil {
return nil, err
socket, Err := uc.File()
Copy link
Member

Choose a reason for hiding this comment

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

And the same here, you don't need to modify err to Err.

Fix Err to err

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Signed-off-by: Tigran Sogomonian <[email protected]>
Comment on lines +124 to +128
defer func() {
if Err != nil {
conn.Close()
}
}()
Copy link
Member

Choose a reason for hiding this comment

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

The uc.File() call below is also missing a close.

Not sure when we can close it, though. Maybe it's handled by the caller, can you check?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants