summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Holzinger <pholzing@redhat.com>2021-12-06 17:50:54 +0100
committerPaul Holzinger <pholzing@redhat.com>2021-12-06 18:34:14 +0100
commit3753347d62469902ef1667d9253574f2a7e5efef (patch)
tree038bbd37961042e1b233f4e91fbdd01a795f988f
parent188f1989faa7de371558cb5466132edcfe62eda3 (diff)
downloadpodman-3753347d62469902ef1667d9253574f2a7e5efef.tar.gz
podman-3753347d62469902ef1667d9253574f2a7e5efef.tar.bz2
podman-3753347d62469902ef1667d9253574f2a7e5efef.zip
rootless netns: resolve all path components for resolv.conf
We need to follow all symlinks in the /etc/resolv.conf path. Currently we would only check the last file but it is possible that any directory before that is also a link. Unfortunately this code is very hard to maintain and not well tested. I will try to come up with a unit test when I have more time. I think we could utilize some for of chroot for this. For now we are stucked with the default setup in the fedora/ubunutu test VMs. [NO NEW TESTS NEEDED] Fixes #12461 Signed-off-by: Paul Holzinger <pholzing@redhat.com>
-rw-r--r--libpod/networking_linux.go47
1 files changed, 40 insertions, 7 deletions
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index b734b9c95..5fb97dd73 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -222,29 +222,62 @@ func (r *RootlessNetNS) Do(toRun func() error) error {
// the link target will be available in the mount ns.
// see: https://github.com/containers/podman/issues/10855
resolvePath := "/etc/resolv.conf"
- for i := 0; i < 255; i++ {
+ linkCount := 0
+ for i := 1; i < len(resolvePath); i++ {
// Do not use filepath.EvalSymlinks, we only want the first symlink under /run.
// If /etc/resolv.conf has more than one symlink under /run, e.g.
// -> /run/systemd/resolve/stub-resolv.conf -> /run/systemd/resolve/resolv.conf
// we would put the netns resolv.conf file to the last path. However this will
// break dns because the second link does not exists in the mount ns.
// see https://github.com/containers/podman/issues/11222
- link, err := os.Readlink(resolvePath)
+ //
+ // We also need to resolve all path components not just the last file.
+ // see https://github.com/containers/podman/issues/12461
+
+ if resolvePath[i] != '/' {
+ // if we are at the last char we need to inc i by one because there is no final slash
+ if i == len(resolvePath)-1 {
+ i++
+ } else {
+ // not the end of path, keep going
+ continue
+ }
+ }
+ path := resolvePath[:i]
+
+ fi, err := os.Lstat(path)
if err != nil {
- // if there is no symlink exit
- break
+ return errors.Wrap(err, "failed to stat resolv.conf path")
}
+
+ // no link, just continue
+ if fi.Mode()&os.ModeSymlink == 0 {
+ continue
+ }
+
+ link, err := os.Readlink(path)
+ if err != nil {
+ return errors.Wrap(err, "failed to read resolv.conf symlink")
+ }
+ linkCount++
if filepath.IsAbs(link) {
// link is as an absolute path
- resolvePath = link
+ resolvePath = filepath.Join(link, resolvePath[i:])
} else {
// link is as a relative, join it with the previous path
- resolvePath = filepath.Join(filepath.Dir(resolvePath), link)
+ base := filepath.Dir(path)
+ resolvePath = filepath.Join(base, link, resolvePath[i:])
}
+ // set i back to zero since we now have a new base path
+ i = 0
+
+ // we have to stop at the first path under /run because we will have an empty /run and will create the path anyway
+ // if we would continue we would need to recreate all links under /run
if strings.HasPrefix(resolvePath, "/run/") {
break
}
- if i == 254 {
+ // make sure wo do not loop forever
+ if linkCount == 255 {
return errors.New("too many symlinks while resolving /etc/resolv.conf")
}
}