fix(tools-image): guarantee localhost resolution for images with empty /etc/hosts - #55
fix(tools-image): guarantee localhost resolution for images with empty /etc/hosts#55JoyboyBrian wants to merge 6 commits into
/etc/hosts#55Conversation
…y /etc/hosts The pivot-init fallback only created /etc/hosts when the file was absent, so OCI images that ship an empty placeholder (ubuntu:22.04/24.04 among them) booted with no localhost mapping and files-source name resolution failed inside the guest. Replace the inline fallback with /agentenv/ensure-localhost-hosts: it preserves image-provided content and idempotently appends only the missing 127.0.0.1/::1 localhost mappings, handling empty files, a missing /etc directory, trailing-newline repair, aliases, comments, and symlinks, and degrading to a boot-time WARN on unwritable paths. Add a regression suite that the tools-image Docker build runs against the exact BusyBox binary shipped in the drive, and strengthen the e2e Python SDK probe to query the files NSS source explicitly so upstream resolvers that answer 'localhost' cannot mask a broken hosts file.
|
🔍 OpenCodeReview found 1 issue(s) in this PR.
|
d4fa05f to
8eef2ac
Compare
|
Thanks for your contribution! However, I think a 400+ line addition is overkill for resolving this issue. A few line changes should be enough to handle the empty /etc/hosts case. |
|
Hi @yingdi-shan, thanks for the feedback! Agreed, the hardening had grown well beyond the actual bug, so I've slimmed it down to a ~15-line inline block in pivot-init plus a small e2e assertion, and dropped the separate helper script and its test harness. One note on why it's slightly more than the previous |
| if [ -s /etc/hosts ] && [ -n "$($BB tail -c 1 /etc/hosts)" ]; then | ||
| echo >> /etc/hosts | ||
| fi | ||
| if ! $BB grep -qsE '^127\.0\.0\.1[[:space:]]+localhost([[:space:]]|$)' /etc/hosts; then | ||
| echo "127.0.0.1 localhost" >> /etc/hosts | ||
| fi |
There was a problem hiding this comment.
[bug · medium]
These redirections follow symlinks. An image can legitimately ship /etc/hosts as a symlink to a runtime-generated path (which may now be dangling because /run was remounted), and an untrusted image could point it at an unrelated file such as /etc/passwd. In the former case localhost is still not installed; in the latter this root bootstrap corrupts the symlink target. Handle -L /etc/hosts explicitly and replace it with a concrete hosts file (preserving readable existing content where appropriate) before appending, similar to the symlink handling used for resolv.conf above.
There was a problem hiding this comment.
I believe this can be accepted as is.
On the security half: there is no privilege boundary here. pivot-init runs as PID 1 on the image's own rootfs, and the image author already controls every byte of that filesystem, including /etc/passwd. Redirecting this append through a symlink grants them nothing they did not already have. The resolv.conf handling above replaces its symlink for a functional reason, not a security one, so it is not a precedent that applies here.
On the dangling-symlink half: container images do not ship /etc/hosts as a symlink into /run in practice, since runtimes bind-mount /etc/hosts over whatever the image provides. Even if one did, the shell append follows and creates the link target, so localhost still resolves. The only remaining corner (a link into a directory that no longer exists) fails open with a warning on stderr, matching the pre-existing fallback this PR replaces, so it is not a regression introduced here.
Happy to add a small dangling-symlink guard if the reviewers consider it necessary.
|
Thanks! One last question: how should we approach upgrading the tool-images? Simply upgrading them could break the snapshot, since it may disrupt the mapping between page caching and disk. Until we have a safe way to upgrade tool-images, I think we need to be more cautious about how we update them. A proper fix is likely complex and will take time, since we may need to support multiple versions of tool-images simultaneously. In the meantime, a simpler workaround would be to update the template build process so that a warm start is guaranteed to be correct. |
|
Thanks @yingdi-shan! I re-checked the current implementation, and it turns out most of the multi-version mechanism is already in place on
Therefore, I do not think this fix requires invalidating existing snapshots. This PR only changes the tools-image source plus an e2e assertion; normal startup still consumes the prebuilt image pinned in That said, your caution is justified by two real gaps:
My recommendation is to keep this PR focused on the source fix, publish |
|
Hi @yingdi-shan, just following up. I’ve updated the PR description to match the simplified diff and clarify the rollout. AgentENV |
|
Thanks! I think we can merge this PR once we've prepared for the image upgrade. |
Summary
Fix guest
localhostresolution when an OCI image ships/etc/hostsas an empty placeholder or without canonical loopback mappings.This PR:
/etc/hostsfallback inpivot-initwith a small content-based check;127.0.0.1 localhostor::1 localhostmappings;Problem
pivot-initcurrently initializes/etc/hostsonly when the file does not exist:Many OCI images—including
ubuntu:22.04andubuntu:24.04—ship a zero-byte/etc/hostsbecause container runtimes normally replace it at startup. AgentENV boots the image as a VM and does not perform that container-runtime mount, so these guests can start without a usablelocalhostmapping.For example:
exits with status 2 in an affected guest. A plain
getent hosts localhostis not a reliable probe because an upstream DNS resolver may answer forlocalhost.Change
At boot,
pivot-initnow:/etcif necessary;The check is idempotent across repeated boots and pause/resume cycles. Existing
/etc/hostscontent is retained.The implementation intentionally remains a small inline bootstrap block. It does not introduce a separate helper, locking, or special symlink replacement policy;
pivot-inithas a single caller before user init.Validation
scripts/tests/e2e/e2b_python_sdk_compat.pythat verifies the sandbox created from the built template contains a loopback-to-localhostmapping.ubuntu:24.04:getent -s files hosts localhostexits 2;localhostresolution succeeds;Tools-drive rollout
This PR changes tools-image source only. It does not publish a tools drive or bump
[tools].version.The published AgentENV
v0.1.1release still pins and bundles tools drive0.1.0, so it does not contain this fix. Rolling the change out requires publishing a new immutable tools-drive version and updatingconfig/deps_manifest.toml.Existing snapshots remain pinned to the
tools_drive_versionrecorded when they were created and are not modified or invalidated by that future manifest bump. Nodes that may restore historical snapshots must retain the corresponding historical tools-drive versions.Changing snapshot-based template rebuilds to cold-boot with a newer tools drive, or automatically provisioning missing historical versions, is outside the scope of this focused fix.