Skip to content

Commit 2dfc2fe

Browse files
authored
Merge pull request #4173 from lifubang/fix-syncPipeClose
never send procError to parent process after sent procReady
2 parents 313ec8b + 0bc4732 commit 2dfc2fe

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
lines changed

libcontainer/init_linux.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ func startInitialization() (retErr error) {
107107

108108
defer func() {
109109
// If this defer is ever called, this means initialization has failed.
110-
// Send the error back to the parent process in the form of an initError.
110+
// Send the error back to the parent process in the form of an initError
111+
// if the sync socket has not been closed.
112+
if syncPipe.isClosed() {
113+
return
114+
}
111115
ierr := initError{Message: retErr.Error()}
112116
if err := writeSyncArg(syncPipe, procError, ierr); err != nil {
113117
fmt.Fprintln(os.Stderr, err)

libcontainer/sync_unix.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"os"
7+
"sync/atomic"
78

89
"golang.org/x/sys/unix"
910
)
@@ -14,7 +15,8 @@ import (
1415
// which ends up making things like json.Decoder hang forever if the packet is
1516
// bigger than the internal read buffer.
1617
type syncSocket struct {
17-
f *os.File
18+
f *os.File
19+
closed atomic.Bool
1820
}
1921

2022
func newSyncSocket(f *os.File) *syncSocket {
@@ -26,9 +28,15 @@ func (s *syncSocket) File() *os.File {
2628
}
2729

2830
func (s *syncSocket) Close() error {
31+
// Even with errors from Close(), we have to assume the pipe was closed.
32+
s.closed.Store(true)
2933
return s.f.Close()
3034
}
3135

36+
func (s *syncSocket) isClosed() bool {
37+
return s.closed.Load()
38+
}
39+
3240
func (s *syncSocket) WritePacket(b []byte) (int, error) {
3341
return s.f.Write(b)
3442
}

tests/integration/exec.bats

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,21 @@ function check_exec_debug() {
322322
runc exec --cgroup second test_busybox grep -w second /proc/self/cgroup
323323
[ "$status" -eq 0 ]
324324
}
325+
326+
@test "RUNC_DMZ=legacy runc exec [execve error]" {
327+
cat <<EOF >rootfs/run.sh
328+
#!/mmnnttbb foo bar
329+
sh
330+
EOF
331+
chmod +x rootfs/run.sh
332+
RUNC_DMZ=legacy runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
333+
RUNC_DMZ=legacy runc exec -t test_busybox /run.sh
334+
[ "$status" -ne 0 ]
335+
336+
# After the sync socket closed, we should not send error to parent
337+
# process, or else we will get a unnecessary error log(#4171).
338+
# Although we never close the sync socket when doing exec,
339+
# but we need to keep this test to ensure this behavior is always right.
340+
[ ${#lines[@]} -eq 1 ]
341+
[[ ${lines[0]} = *"exec failed: unable to start container process: exec /run.sh: no such file or directory"* ]]
342+
}

tests/integration/run.bats

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,19 @@ EOF
247247
[ "$status" -ne 0 ]
248248
[[ "$output" = *"exec /run.sh: "* ]]
249249
}
250+
251+
@test "RUNC_DMZ=legacy runc run [execve error]" {
252+
cat <<EOF >rootfs/run.sh
253+
#!/mmnnttbb foo bar
254+
sh
255+
EOF
256+
chmod +x rootfs/run.sh
257+
update_config '.process.args = [ "/run.sh" ]'
258+
RUNC_DMZ=legacy runc run test_hello
259+
[ "$status" -ne 0 ]
260+
261+
# After the sync socket closed, we should not send error to parent
262+
# process, or else we will get a unnecessary error log(#4171).
263+
[ ${#lines[@]} -eq 1 ]
264+
[[ ${lines[0]} = "exec /run.sh: no such file or directory" ]]
265+
}

0 commit comments

Comments
 (0)