Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

podman can not run a container with a symlinked /etc dir #12189

Closed
wuxxin opened this issue Nov 5, 2021 · 25 comments · Fixed by #12267
Closed

podman can not run a container with a symlinked /etc dir #12189

wuxxin opened this issue Nov 5, 2021 · 25 comments · Fixed by #12267
Labels
locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments.

Comments

@wuxxin
Copy link

wuxxin commented Nov 5, 2021

/kind bug
Description

while trying out https://github.com/remote-android/redroid-doc (a GPU accelerated AIC (Android In Container) solution) running on podman (rootful), podman throws an error:

Error: error creating mtab directory: mkdir /var/lib/containers/storage/overlay/e80f.../merged/etc: file exists

A look inside the container revealed that redroid uses symlinks for:

bin -> /system/bin
etc -> /system/etc
init -> /system/bin/init

and some android related symlinks in the root directory including the symlink of /etc to /system/etc.

while tracing the error message to the corresponding source code i found that it looks like this error message was introduced since #10270 which fixed #10263 .

the corresponding code creates the directory of /etc/mtab but somehow fails if /etc exists and is a symlink.

it is still in the current main branch (which includes the original modification and also the later added pull request #10765) , see: https://github.com/containers/podman/blob/main/libpod/container_internal.go#L1583

Steps to reproduce the issue:

  1. podman run --name=redroid --userns=auto --volume=redroid_data:/data docker.io/redroid/redroid:11.0.0-latest

Describe the results you received:
podman[3459841]: Error: error creating mtab directory: mkdir /var/lib/containter....

Describe the results you expected:
podman starts the container

Additional information you deem important (e.g. issue happens only occasionally):
this was probably working before #10270 introduced creation of /etc inside the container.

Output of podman version:

Version:      3.3.1
API Version:  3.3.1
Go Version:   go1.16.6
Built:        Thu Jan  1 01:00:00 1970
OS/Arch:      linux/amd64

Output of podman info --debug:

host:                                                                                                                                                                                              
  arch: amd64                                                                                                                                                                                      
  buildahVersion: 1.22.3                                                                                                                                                                           
  cgroupControllers:                                                                                                                                                                               
  - cpuset                                                                                                                                                                                         
  - cpu                                                                                                                                                                                            
  - io                                                                                                                                                                                             
  - memory                                                                                                                                                                                         
  - hugetlb                                                                                                                                                                                          - pids                                                                                                                                                                                             cgroupManager: systemd                                                                                                                                                                             cgroupVersion: v2                                            
  conmon:                                                                                                                                                                                              package: 'conmon: /usr/libexec/podman/conmon'                                                                                                                                                      path: /usr/libexec/podman/conmon                                                                                                                                                                   version: 'conmon version 2.0.30, commit: '                                                                                                                                                       cpus: 4                                                                                                                                                                                            distribution:                                                                                                                                                                                        distribution: ubuntu                                                    
    version: "20.04"                                                                                                                                                                                 eventLogger: journald                                                                                                                                                                              hostname: zap                                                                                                                                                                                      idMappings:                                                                                                                                                                                          gidmap: null                                                                                                                                                                                       uidmap: null                                               
  kernel: 5.11.0-38-generic                                                                                                                                                                          linkmode: dynamic                                                                                                                                                                                  memFree: 956403712                                                                                                                                                                                 memTotal: 16710602752                                                                                                                                                                              ociRuntime:                                                                                                                                                                                          name: crun                                                 
    package: 'crun: /usr/bin/crun'                                                                                                                                                                     path: /usr/bin/crun                                                                                                                                                                                version: |-                                                                                                                                                                                          crun version UNKNOWN                                                                                                                                                                               commit: ea1fe3938eefa14eb707f1d22adff4db670645d6                                                                                                                                                   spec: 1.0.0                                                                                                                                                                                        +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL                                                                                                                                    os: linux                                                                                                                                                                                          remoteSocket:                                                                                                                                                                                        path: /run/podman/podman.sock                                                                                                                                                                    security:                                                                                                                                                                                            apparmorEnabled: true              
    capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
    rootless: false
    seccompEnabled: true
    seccompProfilePath: /usr/share/containers/seccomp.json
    selinuxEnabled: false
 serviceIsRemote: false                                                                                                                                                                           
  slirp4netns:                                  
    executable: /usr/bin/slirp4netns                                                             
    package: 'slirp4netns: /usr/bin/slirp4netns'                                                 
    version: |-                                 
      slirp4netns version 1.1.8                                                                  
      commit: unknown                           
      libslirp: 4.3.1-git                       
      SLIRP_CONFIG_VERSION_MAX: 3                                                                
      libseccomp: 2.4.3                         
  swapFree: 9656070144                          
  swapTotal: 9661575168                         
  uptime: 100h 38m 24.05s (Approximately 4.17 days)                                              
registries:                                     
  search:                                       
  - docker.io                                   
  - quay.io                                     
store:                                          
  configFile: /etc/containers/storage.conf                                                       
  containerStore:                               
    number: 5                                   
    paused: 0                                   
    running: 4                                  
    stopped: 1                                  
  graphDriverName: overlay                      
  graphOptions:                                 
    overlay.mount_program:                      
      Executable: /usr/bin/fuse-overlayfs                                                        
      Package: 'fuse-overlayfs: /usr/bin/fuse-overlayfs'                                         
      Version: |-                               
        fusermount3 version: 3.9.0                                                               
        fuse-overlayfs: version 1.5                                                              
        FUSE library version 3.9.0                                                               
        using FUSE kernel interface version 7.31                                                 
    overlay.mountopt: nodev,metacopy=on                                                          
  graphRoot: /var/lib/containers/storage                                                         
  graphStatus:                                  
    Backing Filesystem: zfs                     
    Native Overlay Diff: "false"                                                                 
    Supports d_type: "true"                     
    Using metacopy: "false"                     
  imageStore:                                   
    number: 9                                   
  runRoot: /run/containers/storage                                                               
  volumePath: /var/lib/containers/storage/volumes                                                
version:                                        
  APIVersion: 3.3.1                             
  Built: 0                                      
  BuiltTime: Thu Jan  1 01:00:00 1970                                                            
  GitCommit: "" 
  GoVersion: go1.16.6
  OsArch: linux/amd64
  Version: 3.3.1

Package info (e.g. output of rpm -q podman or apt list podman):

podman/unknown,now 100:3.3.1-1 amd64 [installed]

Have you tested with the latest version of Podman and have you checked the Podman Troubleshooting Guide? (https://github.com/containers/podman/blob/master/troubleshooting.md)
No (as the github states 3.4.1 as latest and the ppa is only at 3.3.1)

@mheon
Copy link
Member

mheon commented Nov 8, 2021

Can you provide more details on the container you're running (ideally a command that reproduces)? Podman should not be dealing with /etc/mtab at all during container creation, so this doesn't look like something Podman is doing.

@wuxxin
Copy link
Author

wuxxin commented Nov 8, 2021

hey, thank you for your response, i am not sure what is needed from your side, but just try to run:

podman run --name=redroid --userns=auto --volume=redroid_data:/data docker.io/redroid/redroid:11.0.0-latest

the error message is coming from the sourcecode i referred to.

@rhatdan
Copy link
Member

rhatdan commented Nov 8, 2021

This is happening just because /etc->/system/etc. So easy to setup.

This most likely is an error happening in crun.

@giuseppe WDYT?

@rhatdan
Copy link
Member

rhatdan commented Nov 8, 2021

This issue, seems to be the hard links I think if you change the /etc->/system/etc to /etc->../system/etc, it would fix the problem.

@rhatdan rhatdan closed this as completed Nov 8, 2021
@rhatdan rhatdan reopened this Nov 8, 2021
@rhatdan
Copy link
Member

rhatdan commented Nov 8, 2021

@nalind Do we have anything to does a choot.Symlink?

@nalind
Copy link
Member

nalind commented Nov 8, 2021

Not directly, but since the link is already there in this case, github.com/containers/buildah/copier.Mkdir() should resolve it correctly when it's told to create it. Could get expensive if we have to do it for multiple locations, though.

As an aside, the image includes SELinux labels (i.e., "security.selinux" xattrs) for many of its contents, which I didn't think was recommended.

@wuxxin
Copy link
Author

wuxxin commented Nov 8, 2021

i tried to workaround by creating a symlink in /system/etc/mtab to /proc/mount, as an extra step from the original container, but that didnt help, mkdir /etc is still tried and container start aborts.

I am happy to have a workaround, for a container having /etc a symlink, but so far, i did not find a combination that worksaround /etc as a symlink

@mheon
Copy link
Member

mheon commented Nov 8, 2021

Again, are we sure this is actually Podman? We should not be doing anything with /etc/mtab - I don't see how /etc/ being or not being a symlink/hardlink affects that? I could potentially see issues with /etc/hosts or /etc/resolv.conf (we actually have had symlink issues with resolv.conf) but mtab makes no sense. There are similarly 0 mentions of mtab in the crun codebase.

@nalind
Copy link
Member

nalind commented Nov 8, 2021

The phrase "error creating mtab directory" suggests it's roughly around here.

@mheon
Copy link
Member

mheon commented Nov 8, 2021

That's only within the container's filesystem - I see no evidence this is related to /etc/mtab on the host. Still don't see a link here. Seems more likely to be an issue with the container itself as opposed to the host system?

@mheon
Copy link
Member

mheon commented Nov 8, 2021

Ahhh, nevermind, it's symlinked inside the container.

@rhatdan
Copy link
Member

rhatdan commented Nov 8, 2021

Yes the issue is inside of the container we have etc->/system/etc.
We have an serious issue that the os.Symlink actually could attempt to follow the link to the systems /system, if it existed.

This is why we should be doing this within a chroot.
chroot MOUNTDIR; ln -s /etc/mtab /proc/mountinfo

Would work.

@flouthoc
Copy link
Collaborator

flouthoc commented Nov 9, 2021

I think moby performs unlink before creating /etc/mtab https://github.com/moby/moby/blob/master/daemon/initlayer/setup_unix.go#L41

@wuxxin Could you please try following diff on latest main. I am not able to use image docker.io/redroid/redroid:11.0.0-latest due to its weird selinux labeling so I did not try running this with redriod. I'll wait for your confirmation.

diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index fbc2c1f38..0f2fac476 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -39,6 +39,7 @@ import (
        "github.com/opencontainers/selinux/go-selinux/label"
        "github.com/pkg/errors"
        "github.com/sirupsen/logrus"
+       "golang.org/x/sys/unix"
 )
 
 const (
@@ -1597,6 +1598,10 @@ func (c *Container) mountStorage() (_ string, deferredErr error) {
 
        // If /etc/mtab does not exist in container image, then we need to
        // create it, so that mount command within the container will work.
+
+       //try unlink any previous symlinks if they are present
+       unix.Unlink(filepath.Join(mountPoint, "/etc/mtab"))
+
        mtab := filepath.Join(mountPoint, "/etc/mtab")
        if err := idtools.MkdirAllAs(filepath.Dir(mtab), 0755, c.RootUID(), c.RootGID()); err != nil {
                return "", errors.Wrap(err, "error creating mtab directory")

@giuseppe
Copy link
Member

giuseppe commented Nov 9, 2021

+
+       //try unlink any previous symlinks if they are present
+       unix.Unlink(filepath.Join(mountPoint, "/etc/mtab"))
+

I'd play safe here and handle the error. If the Unlink fails for any reason, then we end up again with the same situation that the symlink exists and can point to the host.

@giuseppe
Copy link
Member

giuseppe commented Nov 9, 2021

This is why we should be doing this within a chroot.

another solution would be to use openat2, but it needs Linux 5.6+. c/storage/pkg/chunked has safeSymlink function that uses it.

@wuxxin
Copy link
Author

wuxxin commented Nov 9, 2021

@flouthoc happy to help, but i used podman from the ppa, i did not build it myself so far, (to attach the diff), but i can try in the next days, but its not a quick thing i can do.

@rhatdan
Copy link
Member

rhatdan commented Nov 9, 2021

@giuseppe Does RHEL8 has saveSymlink?
Is this available in Go?

Also I don't see how the unlink does anything. What would happen if etc->/etc inside of the container, does this image cause us to override the hosts /etc/mtab?

@giuseppe
Copy link
Member

giuseppe commented Nov 10, 2021

@giuseppe Does RHEL8 has saveSymlink?
Is this available in Go?

openat2 is available on RHEL8.

safeSymlink is defined here: https://github.com/containers/storage/blob/main/pkg/chunked/storage_linux.go#L819

@rhatdan
Copy link
Member

rhatdan commented Nov 10, 2021

Care to open a PR to fix this?

@flouthoc
Copy link
Collaborator

I tried following diff for running this container. Container runs successfully but qemu inside redriod panics without any logs. I am not sure why is redroid panicking without any logs.

diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index fbc2c1f38..0f2fac476 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -39,6 +39,7 @@ import (
        "github.com/opencontainers/selinux/go-selinux/label"
        "github.com/pkg/errors"
        "github.com/sirupsen/logrus"
+       "golang.org/x/sys/unix"
 )
 
 const (
@@ -1597,6 +1598,10 @@ func (c *Container) mountStorage() (_ string, deferredErr error) {
 
        // If /etc/mtab does not exist in container image, then we need to
        // create it, so that mount command within the container will work.
+
+       //try unlink any previous symlinks if they are present
+       unix.Unlink(filepath.Join(mountPoint, "/etc/mtab"))
+       unix.Unlink(filepath.Join(mountPoint, "/etc"))
+
        mtab := filepath.Join(mountPoint, "/etc/mtab")
        if err := idtools.MkdirAllAs(filepath.Dir(mtab), 0755, c.RootUID(), c.RootGID()); err != nil {
                return "", errors.Wrap(err, "error creating mtab directory")

@flouthoc
Copy link
Collaborator

I can see on redroid github issues similar crash reports for other platforms as well. But really hard to identify quickly now if its crashing because podman or because of my host configuration since its leaving no logs behind.

I get almost 0 logs.

@giuseppe
Copy link
Member

+       //try unlink any previous symlinks if they are present
+       unix.Unlink(filepath.Join(mountPoint, "/etc/mtab"))
+       unix.Unlink(filepath.Join(mountPoint, "/etc"))

this doesn't seem correct.

Why a container image cannot have a symlink for etc? We need to deal with it and resolve it inside the container

@flouthoc
Copy link
Collaborator

@giuseppe After unlinking /etc/mtab the call fails with Error: error creating mtab directory: mkdir <mountpoint>/merged/etc: file exists since there is a symlink for /etc as well. But i agree that should be handled.

@giuseppe
Copy link
Member

I'll open a PR to fix this issue

@giuseppe
Copy link
Member

PR: #12267

After the PR still requires that the target for the /etc symlink exists in the container, so if you have a etc -> /system/etc symlink, you need to make sure /system/etc exists. We could take care of it, but it is more expensive as we need to iterate each component

giuseppe added a commit to giuseppe/libpod that referenced this issue Nov 11, 2021
make sure the /etc/mtab symlink is created inside the rootfs when /etc
is a symlink.

Closes: containers#12189

[NO NEW TESTS NEEDED] there is already a test case

Signed-off-by: Giuseppe Scrivano <[email protected]>
mheon pushed a commit to mheon/libpod that referenced this issue Dec 6, 2021
make sure the /etc/mtab symlink is created inside the rootfs when /etc
is a symlink.

Closes: containers#12189

[NO NEW TESTS NEEDED] there is already a test case

Signed-off-by: Giuseppe Scrivano <[email protected]>
materkey added a commit to materkey/cri-o that referenced this issue Jan 24, 2022
@github-actions github-actions bot added the locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments. label Sep 21, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
locked - please file new issue/PR Assist humans wanting to comment on an old issue or PR with locked comments.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants