Skip to content

fix failure to start container with networking enabled#162

Open
ndeloof wants to merge 1 commit intocontainerd:mainfrom
ndeloof:fix
Open

fix failure to start container with networking enabled#162
ndeloof wants to merge 1 commit intocontainerd:mainfrom
ndeloof:fix

Conversation

@ndeloof
Copy link
Copy Markdown

@ndeloof ndeloof commented Apr 14, 2026

Following README to run a container with networking (using gvproxy) failed on MacOS.
Claude-assisted diagnostic eventually went to this fix

Copilot AI review requested due to automatic review settings April 14, 2026 15:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Resolves a container startup failure when networking is enabled by ensuring bind-mount sources don’t include symlinks that libkrun rejects under O_NOFOLLOW (notably on macOS).

Changes:

  • Resolve host bind-mount source paths via filepath.EvalSymlinks before passing them to libkrun.
  • Return an explicit error if symlink resolution fails.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/shim/task/mount.go Outdated
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
Copilot AI review requested due to automatic review settings April 14, 2026 16:38
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +190 to +194
} else {
// Try giving the VM a copy of the host's resolv.conf.
// This is always attempted (not only as a fallback) because on some
// platforms (e.g., macOS) the host path /etc/resolv.conf may contain
// symlinks that prevent it from being shared via virtiofs.
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

fallbackToHostRC no longer gates whether host /etc/resolv.conf is used (behavior changed from else if fallbackToHostRC to unconditional else). This makes the parameter’s meaning inconsistent and may unintentionally opt-in to host-DNS copying even when callers pass false. Either restore the condition (while still addressing the macOS symlink problem via symlink resolution / file copy), or remove/rename the parameter and update call sites to reflect the new always-try behavior.

Suggested change
} else {
// Try giving the VM a copy of the host's resolv.conf.
// This is always attempted (not only as a fallback) because on some
// platforms (e.g., macOS) the host path /etc/resolv.conf may contain
// symlinks that prevent it from being shared via virtiofs.
} else if fallbackToHostRC {
// Try giving the VM a copy of the host's resolv.conf when enabled.
// Copying the file contents (rather than sharing the host path) avoids
// issues on platforms where /etc/resolv.conf may be a symlink that
// cannot be shared via virtiofs.

Copilot uses AI. Check for mistakes.
Comment on lines +233 to +239
// Resolve symlinks in the source path because libkrun opens shared
// directories with O_NOFOLLOW, which rejects symlinks
// (e.g., /etc -> /private/etc and /etc/resolv.conf -> ../var/run/resolv.conf on macOS).
resolvedSource, err := filepath.EvalSymlinks(m.Source)
if err != nil {
return fmt.Errorf("failed to resolve symlinks for bind mount source %s: %w", m.Source, err)
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The error message should quote the path to avoid ambiguity (especially if it contains spaces) and to match common Go error formatting. Prefer %q for the path, e.g. ... source %q: %w.

Copilot uses AI. Check for mistakes.
Comment on lines +244 to 251
hostSrc := resolvedSource
specSrc := vmTarget
if !fi.IsDir() {
hostSrc = filepath.Dir(m.Source)
hostSrc = filepath.Dir(resolvedSource)
// Use path.Join (not filepath.Join) because this path is used
// inside the Linux VM where forward slashes are required.
specSrc = path.Join(vmTarget, filepath.Base(m.Source))
specSrc = path.Join(vmTarget, filepath.Base(resolvedSource))
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

After introducing resolvedSource, the directory/file decision still depends on fi.IsDir() obtained earlier. To keep the logic consistent and self-contained, consider deriving fi from resolvedSource (or add an inline comment clarifying that fi is already based on os.Stat(m.Source) which follows symlinks). This prevents subtle mismatches if the earlier stat ever changes to Lstat or otherwise diverges from the resolved path.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member

@akerouanton akerouanton left a comment

Choose a reason for hiding this comment

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

I think you're trying to invoke nerdbox through ctr. In that case, you should adapt your ctr invocation based on these findings.

// Resolve symlinks in the source path because libkrun opens shared
// directories with O_NOFOLLOW, which rejects symlinks
// (e.g., /etc -> /private/etc and /etc/resolv.conf -> ../var/run/resolv.conf on macOS).
resolvedSource, err := filepath.EvalSymlinks(m.Source)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm always wary of blindly following symlinks due to the security risks they pose. I think nerdbox users should evaluate any symlinks if and when that makes sense instead.

_, _ = rcBuf.WriteRune('\n')
}
rcBytes = rcBuf.Bytes()
} else if fallbackToHostRC {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IIRC all that code was added before nerdbox had proper support for bind-mounts.

I think the shim should be minimal and have less magic, i.e. we should remove this function and the io.containerd.nerdbox.ctr.dns annotation, and let higher-level runtimes inject their custom resolv.conf through standard bind-mounts.

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.

4 participants