fix isolation startup cleanup and optional Linux mounts

This commit is contained in:
lxowalle 2026-04-08 17:03:01 +08:00
parent a009e76da2
commit d38ca161ec
2 changed files with 48 additions and 11 deletions

View file

@ -218,7 +218,7 @@ func DefaultExposePaths(root string) []config.ExposePath {
} }
func defaultLinuxSystemExposePaths() []config.ExposePath { func defaultLinuxSystemExposePaths() []config.ExposePath {
return []config.ExposePath{ return existingExposePaths([]config.ExposePath{
{Source: "/usr", Target: "/usr", Mode: "ro"}, {Source: "/usr", Target: "/usr", Mode: "ro"},
{Source: "/bin", Target: "/bin", Mode: "ro"}, {Source: "/bin", Target: "/bin", Mode: "ro"},
{Source: "/lib", Target: "/lib", Mode: "ro"}, {Source: "/lib", Target: "/lib", Mode: "ro"},
@ -236,7 +236,19 @@ func defaultLinuxSystemExposePaths() []config.ExposePath {
{Source: "/etc/alternatives", Target: "/etc/alternatives", Mode: "ro"}, {Source: "/etc/alternatives", Target: "/etc/alternatives", Mode: "ro"},
{Source: "/usr/share/zoneinfo", Target: "/usr/share/zoneinfo", Mode: "ro"}, {Source: "/usr/share/zoneinfo", Target: "/usr/share/zoneinfo", Mode: "ro"},
{Source: "/etc/localtime", Target: "/etc/localtime", Mode: "ro"}, {Source: "/etc/localtime", Target: "/etc/localtime", Mode: "ro"},
})
}
// existingExposePaths keeps only the builtin host paths that exist on the
// current machine so Linux isolation does not fail on distro-specific paths.
func existingExposePaths(items []config.ExposePath) []config.ExposePath {
filtered := make([]config.ExposePath, 0, len(items))
for _, item := range items {
if _, err := os.Stat(item.Source); err == nil {
filtered = append(filtered, item)
}
} }
return filtered
} }
// MergeExposePaths merges built-in rules with user overrides. Rules are keyed // MergeExposePaths merges built-in rules with user overrides. Rules are keyed
@ -363,12 +375,12 @@ func Start(cmd *exec.Cmd) error {
var err error var err error
root, err = ResolveInstanceRoot() root, err = ResolveInstanceRoot()
if err != nil { if err != nil {
_ = cmd.Process.Kill() terminateStartedCommand(cmd)
return err return err
} }
} }
if err := postStartPlatformIsolation(cmd, isolation, root); err != nil { if err := postStartPlatformIsolation(cmd, isolation, root); err != nil {
_ = cmd.Process.Kill() terminateStartedCommand(cmd)
return err return err
} }
return nil return nil
@ -390,17 +402,26 @@ func Run(cmd *exec.Cmd) error {
var err error var err error
root, err = ResolveInstanceRoot() root, err = ResolveInstanceRoot()
if err != nil { if err != nil {
_ = cmd.Process.Kill() terminateStartedCommand(cmd)
return err return err
} }
} }
if err := postStartPlatformIsolation(cmd, isolation, root); err != nil { if err := postStartPlatformIsolation(cmd, isolation, root); err != nil {
_ = cmd.Process.Kill() terminateStartedCommand(cmd)
return err return err
} }
return cmd.Wait() return cmd.Wait()
} }
func terminateStartedCommand(cmd *exec.Cmd) {
cleanupPendingPlatformResources(cmd)
if cmd == nil || cmd.Process == nil {
return
}
_ = cmd.Process.Kill()
_ = cmd.Wait()
}
// PrepareCommand mutates the command in-place so it inherits the configured // PrepareCommand mutates the command in-place so it inherits the configured
// isolated environment before being started by the caller. // isolated environment before being started by the caller.
func PrepareCommand(cmd *exec.Cmd) error { func PrepareCommand(cmd *exec.Cmd) error {

View file

@ -176,12 +176,11 @@ func TestValidateWindowsExposePaths(t *testing.T) {
func TestDefaultLinuxSystemExposePaths(t *testing.T) { func TestDefaultLinuxSystemExposePaths(t *testing.T) {
paths := defaultLinuxSystemExposePaths() paths := defaultLinuxSystemExposePaths()
needed := map[string]bool{ needed := map[string]bool{}
"/etc/hosts": false, for _, path := range []string{"/etc/hosts", "/etc/nsswitch.conf", "/etc/ssl", "/usr/share/zoneinfo", "/etc/localtime"} {
"/etc/nsswitch.conf": false, if _, err := os.Stat(path); err == nil {
"/etc/ssl": false, needed[path] = false
"/usr/share/zoneinfo": false, }
"/etc/localtime": false,
} }
for _, item := range paths { for _, item := range paths {
if _, ok := needed[item.Source]; ok { if _, ok := needed[item.Source]; ok {
@ -195,6 +194,23 @@ func TestDefaultLinuxSystemExposePaths(t *testing.T) {
} }
} }
func TestExistingExposePaths_SkipsMissingPaths(t *testing.T) {
existing := filepath.Join(t.TempDir(), "existing")
if err := os.MkdirAll(existing, 0o755); err != nil {
t.Fatalf("os.MkdirAll() error = %v", err)
}
filtered := existingExposePaths([]config.ExposePath{
{Source: existing, Target: existing, Mode: "ro"},
{Source: filepath.Join(t.TempDir(), "missing"), Target: "/missing", Mode: "ro"},
})
if len(filtered) != 1 {
t.Fatalf("existingExposePaths() len = %d, want 1", len(filtered))
}
if got := filtered[0]; got.Source != existing {
t.Fatalf("existingExposePaths()[0] = %+v, want source=%q", got, existing)
}
}
func TestPrepareCommand_AppliesUserEnv(t *testing.T) { func TestPrepareCommand_AppliesUserEnv(t *testing.T) {
t.Setenv(config.EnvHome, filepath.Join(t.TempDir(), "home")) t.Setenv(config.EnvHome, filepath.Join(t.TempDir(), "home"))
if runtime.GOOS == "linux" { if runtime.GOOS == "linux" {