From 44071ee558f17c8c90b6e8f5451798ee1dcf74ac Mon Sep 17 00:00:00 2001 From: David Graff Date: Fri, 31 May 2024 13:18:28 -0400 Subject: [PATCH] fix: correct creation of container /etc/hostname file As noted in #22729: As per debian's hostname (5) man page: > The file should contain a single newline-terminated hostname string. Comments (lines starting with a "#") are ignored. The hostname should be composed of up to 64 7-bit ASCII lower-case alphanumeric characters or hyphens forming a valid DNS domain name. It is recommended that this name contains only a single label, i.e. without any dots. Invalid characters will be filtered out in an attempt to make the name valid, but obviously it is recommended to use a valid name and not rely on this filtering. I have made the change noted in the issue and provided a unit test to ensure that the value written is correct. Signed-off-by: David Graff --- libpod/container_internal_linux.go | 2 +- libpod/container_internal_linux_test.go | 52 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 5385d95705..81349084a0 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -664,7 +664,7 @@ func (c *Container) makePlatformBindMounts() error { // Make /etc/hostname // This should never change, so no need to recreate if it exists if _, ok := c.state.BindMounts["/etc/hostname"]; !ok { - hostnamePath, err := c.writeStringToRundir("hostname", c.Hostname()) + hostnamePath, err := c.writeStringToRundir("hostname", fmt.Sprintf("%s\n", c.Hostname())) if err != nil { return fmt.Errorf("creating hostname file for container %s: %w", c.ID(), err) } diff --git a/libpod/container_internal_linux_test.go b/libpod/container_internal_linux_test.go index 4deb513b8a..4db8c27ca5 100644 --- a/libpod/container_internal_linux_test.go +++ b/libpod/container_internal_linux_test.go @@ -3,10 +3,16 @@ package libpod import ( + "fmt" + "os" "testing" + "unicode/utf8" + "github.com/containers/storage/pkg/idtools" + "github.com/containers/storage/types" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGenerateUserPasswdEntry(t *testing.T) { @@ -60,3 +66,49 @@ func TestGenerateUserGroupEntry(t *testing.T) { } assert.Equal(t, group, "567890:x:567890:567890\n") } + +func TestMakePlatformBindMounts(t *testing.T) { + runDir, err := os.MkdirTemp(os.TempDir(), "rundir") + require.NoError(t, err, "Unable to create temp directory") + defer os.RemoveAll(runDir) + testHostname := "test-hostname" + c := Container{ + config: &ContainerConfig{ + Spec: &spec.Spec{ + Hostname: testHostname, + }, + IDMappings: types.IDMappingOptions{ + UIDMap: []idtools.IDMap{ + { + ContainerID: 0, + HostID: os.Getuid(), + }, + }, + GIDMap: []idtools.IDMap{ + { + ContainerID: 0, + HostID: os.Getgid(), + }, + }, + }, + }, + state: &ContainerState{ + RunDir: runDir, + BindMounts: make(map[string]string), + }, + } + err = c.makePlatformBindMounts() + require.NoError(t, err) + + bindMountEtcHostname, ok := c.state.BindMounts["/etc/hostname"] + require.True(t, ok, "Unable to locate container /etc/hostname") + require.Greater(t, len(bindMountEtcHostname), 0, "hostname file not configured") + + contents, err := os.ReadFile(bindMountEtcHostname) + require.NoError(t, err, "error reading container /etc/hostname") + require.Greater(t, len(contents), 0, "container /etc/hostname was empty") + + strContents := string(contents) + require.True(t, utf8.ValidString(strContents), "hostname does not contain valid utf-8 string") + require.Equal(t, fmt.Sprintf("%s\n", testHostname), strContents) +}