Ensure rootless containers without a passwd can start

We want to modify /etc/passwd to add an entry for the user in
question, but at the same time we don't want to require the
container provide a /etc/passwd (a container with a single,
statically linked binary and nothing else is perfectly fine and
should be allowed, for example). We could create the passwd file
if it does not exist, but if the container doesn't provide one,
it's probably better not to make one at all. Gate changes to
/etc/passwd behind a stat() of the file in the container
returning cleanly.

Fixes #7515

Signed-off-by: Matthew Heon <mheon@redhat.com>
This commit is contained in:
Matthew Heon 2020-08-31 14:06:49 -04:00
parent 0c076dbce5
commit 3875040f13
2 changed files with 24 additions and 0 deletions

View file

@ -1584,6 +1584,17 @@ func (c *Container) generatePasswd() (string, error) {
if _, err := os.Stat(passwdPath); err == nil {
return passwdPath, nil
}
// Check if container has a /etc/passwd - if it doesn't do nothing.
passwdPath, err := securejoin.SecureJoin(c.state.Mountpoint, "/etc/passwd")
if err != nil {
return "", errors.Wrapf(err, "error creating path to container %s /etc/passwd", c.ID())
}
if _, err := os.Stat(passwdPath); err != nil {
if os.IsNotExist(err) {
return "", nil
}
return "", errors.Wrapf(err, "unable to access container %s /etc/passwd", c.ID())
}
pwd := ""
if c.config.User != "" {
entry, err := c.generateUserPasswdEntry()

View file

@ -58,4 +58,17 @@ var _ = Describe("Podman run passwd", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.LineInOutputContains("passwd")).To(BeTrue())
})
It("podman can run container without /etc/passwd", func() {
SkipIfRemote()
dockerfile := `FROM alpine
RUN rm -f /etc/passwd /etc/shadow /etc/group
USER 1000`
imgName := "testimg"
podmanTest.BuildImage(dockerfile, imgName, "false")
session := podmanTest.Podman([]string{"run", "--rm", imgName, "ls", "/etc/"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Not(ContainSubstring("passwd")))
})
})