Skip to content

Commit 1fab11a

Browse files
fix: race-detection between parent and child processes (#106)
1 parent 60ba91d commit 1fab11a

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

app/child.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,66 @@
11
package app
22

33
import (
4+
"context"
45
"fmt"
56
"log"
67
"log/slog"
78
"os"
89
"os/exec"
10+
"syscall"
11+
"time"
912

13+
"github.com/cenkalti/backoff/v5"
1014
"github.com/coder/boundary/jail"
15+
"golang.org/x/sys/unix"
1116
)
1217

18+
// waitForInterface waits for a network interface to appear in the namespace.
19+
// It retries checking for the interface with exponential backoff up to the specified timeout.
20+
func waitForInterface(interfaceName string, timeout time.Duration) error {
21+
b := backoff.NewExponentialBackOff()
22+
b.InitialInterval = 50 * time.Millisecond
23+
b.MaxInterval = 500 * time.Millisecond
24+
b.Multiplier = 2.0
25+
26+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
27+
defer cancel()
28+
29+
operation := func() (bool, error) {
30+
cmd := exec.Command("ip", "link", "show", interfaceName)
31+
cmd.SysProcAttr = &syscall.SysProcAttr{
32+
AmbientCaps: []uintptr{uintptr(unix.CAP_NET_ADMIN)},
33+
}
34+
35+
err := cmd.Run()
36+
if err != nil {
37+
return false, fmt.Errorf("interface %s not found: %w", interfaceName, err)
38+
}
39+
// Interface exists
40+
return true, nil
41+
}
42+
43+
_, err := backoff.Retry(ctx, operation, backoff.WithBackOff(b))
44+
if err != nil {
45+
return fmt.Errorf("interface %s did not appear within %v: %w", interfaceName, timeout, err)
46+
}
47+
48+
return nil
49+
}
50+
1351
func RunChild(logger *slog.Logger, args []string) error {
1452
logger.Info("boundary CHILD process is started")
1553

1654
vethNetJail := os.Getenv("VETH_JAIL_NAME")
55+
if vethNetJail == "" {
56+
return fmt.Errorf("VETH_JAIL_NAME environment variable is not set")
57+
}
58+
59+
// Wait for the veth interface to be moved into the namespace by the parent process
60+
if err := waitForInterface(vethNetJail, 5*time.Second); err != nil {
61+
return fmt.Errorf("failed to wait for interface %s: %w", vethNetJail, err)
62+
}
63+
1764
err := jail.SetupChildNetworking(vethNetJail)
1865
if err != nil {
1966
return fmt.Errorf("failed to setup child networking: %v", err)

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/coder/boundary
33
go 1.24.0
44

55
require (
6+
github.com/cenkalti/backoff/v5 v5.0.3
67
github.com/coder/serpent v0.10.0
78
github.com/stretchr/testify v1.8.4
89
golang.org/x/sys v0.38.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tE
1010
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
1111
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
1212
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
13+
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
14+
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
1315
github.com/charmbracelet/lipgloss v0.8.0 h1:IS00fk4XAHcf8uZKc3eHeMUTCxUH6NkaTrdyCQk84RU=
1416
github.com/charmbracelet/lipgloss v0.8.0/go.mod h1:p4eYUZZJ/0oXTuCQKFF8mqyKCz0ja6y+7DniDDw5KKU=
1517
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs=

0 commit comments

Comments
 (0)