mirror of
https://github.com/containers/podman.git
synced 2025-08-06 19:44:14 +08:00
Preserve passwd on container restart
We added code to create a `/etc/passwd` file that we bind-mount into the container in some cases (most notably, `--userns=keep-id` containers). This, unfortunately, was not persistent, so user-added users would be dropped on container restart. Changing where we store the file should fix this. Further, we want to ensure that lookups of users in the container use the right /etc/passwd if we replaced it. There was already logic to do this, but it only worked for user-added mounts; it's easy enough to alter it to use our mounts as well. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
This commit is contained in:
@ -28,7 +28,6 @@ import (
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-tools/generate"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -1759,32 +1758,40 @@ func (c *Container) postDeleteHooks(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeStringToRundir copies the provided file to the runtimedir
|
||||
func (c *Container) writeStringToRundir(destFile, output string) (string, error) {
|
||||
// writeStringToRundir writes the given string to a file with the given name in
|
||||
// the container's temporary files directory. The file will be chown'd to the
|
||||
// container's root user and have an appropriate SELinux label set.
|
||||
// If a file with the same name already exists, it will be deleted and recreated
|
||||
// with the new contents.
|
||||
// Returns the full path to the new file.
|
||||
func (c *Container) writeStringToRundir(destFile, contents string) (string, error) {
|
||||
destFileName := filepath.Join(c.state.RunDir, destFile)
|
||||
|
||||
if err := os.Remove(destFileName); err != nil && !os.IsNotExist(err) {
|
||||
return "", errors.Wrapf(err, "error removing %s for container %s", destFile, c.ID())
|
||||
}
|
||||
|
||||
f, err := os.Create(destFileName)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "unable to create %s", destFileName)
|
||||
}
|
||||
defer f.Close()
|
||||
if err := f.Chown(c.RootUID(), c.RootGID()); err != nil {
|
||||
if err := writeStringToPath(destFileName, contents, c.config.MountLabel, c.RootUID(), c.RootGID()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, err := f.WriteString(output); err != nil {
|
||||
return "", errors.Wrapf(err, "unable to write %s", destFileName)
|
||||
return destFileName, nil
|
||||
}
|
||||
// Relabel runDirResolv for the container
|
||||
if err := label.Relabel(destFileName, c.config.MountLabel, false); err != nil {
|
||||
|
||||
// writeStringToStaticDir writes the given string to a file with the given name
|
||||
// in the container's permanent files directory. The file will be chown'd to the
|
||||
// container's root user and have an appropriate SELinux label set.
|
||||
// Unlike writeStringToRundir, will *not* delete and re-create if the file
|
||||
// already exists (will instead error).
|
||||
// Returns the full path to the new file.
|
||||
func (c *Container) writeStringToStaticDir(filename, contents string) (string, error) {
|
||||
destFileName := filepath.Join(c.config.StaticDir, filename)
|
||||
|
||||
if err := writeStringToPath(destFileName, contents, c.config.MountLabel, c.RootUID(), c.RootGID()); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Join(c.state.RunDir, destFile), nil
|
||||
return destFileName, nil
|
||||
}
|
||||
|
||||
// appendStringToRundir appends the provided string to the runtimedir file
|
||||
|
@ -214,6 +214,9 @@ func (c *Container) getUserOverrides() *lookup.Overrides {
|
||||
}
|
||||
}
|
||||
}
|
||||
if path, ok := c.state.BindMounts["/etc/passwd"]; ok {
|
||||
overrides.ContainerEtcPasswdPath = path
|
||||
}
|
||||
return &overrides
|
||||
}
|
||||
|
||||
@ -1513,6 +1516,14 @@ func (c *Container) generatePasswd() (string, error) {
|
||||
if !c.config.AddCurrentUserPasswdEntry && c.config.User == "" {
|
||||
return "", nil
|
||||
}
|
||||
if MountExists(c.config.Spec.Mounts, "/etc/passwd") {
|
||||
return "", nil
|
||||
}
|
||||
// Re-use passwd if possible
|
||||
passwdPath := filepath.Join(c.config.StaticDir, "passwd")
|
||||
if _, err := os.Stat(passwdPath); err == nil {
|
||||
return passwdPath, nil
|
||||
}
|
||||
pwd := ""
|
||||
if c.config.User != "" {
|
||||
entry, err := c.generateUserPasswdEntry()
|
||||
@ -1536,7 +1547,7 @@ func (c *Container) generatePasswd() (string, error) {
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return "", errors.Wrapf(err, "unable to read passwd file %s", originPasswdFile)
|
||||
}
|
||||
passwdFile, err := c.writeStringToRundir("passwd", string(orig)+pwd)
|
||||
passwdFile, err := c.writeStringToStaticDir("passwd", string(orig)+pwd)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to create temporary passwd file")
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@ -273,3 +274,28 @@ func makeInspectPortBindings(bindings []ocicni.PortMapping) map[string][]define.
|
||||
}
|
||||
return portBindings
|
||||
}
|
||||
|
||||
// Write a given string to a new file at a given path.
|
||||
// Will error if a file with the given name already exists.
|
||||
// Will be chown'd to the UID/GID provided and have the provided SELinux label
|
||||
// set.
|
||||
func writeStringToPath(path, contents, mountLabel string, uid, gid int) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "unable to create %s", path)
|
||||
}
|
||||
defer f.Close()
|
||||
if err := f.Chown(uid, gid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := f.WriteString(contents); err != nil {
|
||||
return errors.Wrapf(err, "unable to write %s", path)
|
||||
}
|
||||
// Relabel runDirResolv for the container
|
||||
if err := label.Relabel(path, mountLabel, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user