Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,6 @@ func createContainer(container, image, release, authFile string, showCommandToEn
"--userns", usernsArg,
"--user", "root:root",
"--volume", "/:/run/host:rslave",
"--volume", "/dev:/dev:rslave",
"--volume", dbusSystemSocketMountArg,
"--volume", homeDirMountArg,
"--volume", toolboxPathMountArg,
Expand Down
84 changes: 76 additions & 8 deletions src/cmd/initContainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@ var (
{"/var/log/journal", "/run/host/var/log/journal", ""},
{"/var/mnt", "/run/host/var/mnt", "rslave"},
}

initContainerIgnoredHostDevices = map[string]struct{}{
"console": {},
"core": {},
"fd": {},
"full": {},
"kmsg": {},
"mqueue": {},
"null": {},
"ptmx": {},
"pts": {},
"random": {},
"shm": {},
"stderr": {},
"stdin": {},
"stdout": {},
"tty": {},
"urandom": {},
"zero": {},
}
)

var initContainerCmd = &cobra.Command{
Expand Down Expand Up @@ -263,6 +283,8 @@ func initContainer(cmd *cobra.Command, args []string) error {
}
}

projectHostDevices()

if utils.PathExists("/sys/fs/selinux") {
if err := mountBind("/sys/fs/selinux", "/usr/share/empty", ""); err != nil {
return err
Expand Down Expand Up @@ -1018,20 +1040,22 @@ func mountBind(containerPath, source, flags string) error {
if err := os.MkdirAll(containerPath, 0755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", containerPath, err)
}
} else if fileMode.IsRegular() || fileMode&os.ModeSocket != 0 {
logrus.Debugf("Creating regular file %s", containerPath)

} else {
containerPathDir := filepath.Dir(containerPath)
if err := os.MkdirAll(containerPathDir, 0755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", containerPathDir, err)
}

containerPathFile, err := os.Create(containerPath)
if err != nil && !os.IsExist(err) {
return fmt.Errorf("failed to create regular file %s: %w", containerPath, err)
}
if !utils.PathExists(containerPath) {
logrus.Debugf("Creating file mount point %s", containerPath)

containerPathFile, err := os.Create(containerPath)
if err != nil {
return fmt.Errorf("failed to create file mount point %s: %w", containerPath, err)
}

defer containerPathFile.Close()
defer containerPathFile.Close()
}
}

logrus.Debugf("Binding %s to %s", containerPath, source)
Expand All @@ -1053,6 +1077,50 @@ func mountBind(containerPath, source, flags string) error {
return nil
}

func projectHostDevices() {
const hostDevices = "/run/host/dev"
const logPrefix = "Projecting host devices into the container"

logrus.Debugf("%s", logPrefix)

entries, err := os.ReadDir(hostDevices)
if err != nil {
logrus.Debugf("%s: failed to read %s: %s", logPrefix, hostDevices, err)
logrus.Debugf("%s: skipping", logPrefix)
return
}

for _, entry := range entries {
name := entry.Name()
if _, ignored := initContainerIgnoredHostDevices[name]; ignored {
logrus.Debugf("%s: skipping runtime-managed path /dev/%s", logPrefix, name)
continue
}

source := filepath.Join(hostDevices, name)
fileInfo, err := os.Lstat(source)
if err != nil {
logrus.Debugf("%s: failed to lstat %s: %s", logPrefix, source, err)
continue
}
Comment on lines +1101 to +1105
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Calling os.Lstat here is redundant and inefficient because os.ReadDir already provides a DirEntry which contains the file type information. You can use entry.Type() and entry.IsDir() directly, or entry.Info() if you need the full FileInfo.

Suggested change
fileInfo, err := os.Lstat(source)
if err != nil {
logrus.Debugf("%s: failed to lstat %s: %s", logPrefix, source, err)
continue
}
fileInfo, err := entry.Info()
if err != nil {
logrus.Debugf("%s: failed to get info for %s: %s", logPrefix, source, err)
continue
}


if fileInfo.Mode()&os.ModeSymlink != 0 {
logrus.Debugf("%s: skipping symbolic link %s", logPrefix, source)
continue
}

flags := ""
if fileInfo.IsDir() {
flags = "rslave"
}

containerPath := filepath.Join("/dev", name)
if err := mountBind(containerPath, source, flags); err != nil {
logrus.Debugf("%s: failed to bind %s to %s: %s", logPrefix, containerPath, source, err)
}
Comment on lines +1118 to +1120
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Executing the mount command in a loop for every entry in /dev can be quite slow due to the overhead of process creation (fork/exec). Since init-container already imports golang.org/x/sys/unix, consider using the unix.Mount syscall directly for better performance, especially when dealing with a large number of device nodes.

}
}

// redirectPath serves for creating symbolic links for crucial system
// configuration files to their counterparts on the host's file system.
//
Expand Down
20 changes: 20 additions & 0 deletions test/system/101-create.bats
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ teardown() {
assert_output "true"
}

@test "create: The host /dev is not bind-mounted into the container" {
local default_container
default_container="$(get_system_id)-toolbox-$(get_system_version)"

pull_default_image

run --keep-empty-lines --separate-stderr "$TOOLBX" create

assert_success
assert [ ${#stderr_lines[@]} -eq 0 ]

run podman inspect \
--format '{{range .Mounts}}{{println .Destination}}{{end}}' \
--type container \
"$default_container"

assert_success
refute_line "/dev"
}

@test "create: Smoke test with SHELL unset" {
local default_container
default_container="$(get_system_id)-toolbox-$(get_system_version)"
Expand Down