From 701d6bbe91b8859dd3a54a979fbdbe64238f7174 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Thu, 24 Oct 2024 15:35:45 -0400 Subject: [PATCH] Handle RUN --mount with relative targets and no configured workdir When the target location of a RUN --mount is specified as a relative path, we normally try to convert it to an absolute path by combining it with the currently-configured working directory. If there is no such value, though, the result is still not an absolute path. Work around this by using "/" when the configured working directory is "". Set this field in the `runMountInfo` struct on FreeBSD, as we already did on Linux. Signed-off-by: Nalin Dahyabhai --- internal/volumes/volumes.go | 13 +++++++++---- run_common.go | 6 +++--- run_freebsd.go | 7 +++++++ run_linux.go | 4 ++++ tests/bud.bats | 14 ++++++++++++++ 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/internal/volumes/volumes.go b/internal/volumes/volumes.go index 0c081c01a4d..fa9a8bb35e6 100644 --- a/internal/volumes/volumes.go +++ b/internal/volumes/volumes.go @@ -531,6 +531,7 @@ func GetVolumes(ctx *types.SystemContext, store storage.Store, volumes []string, // getMounts takes user-provided input from the --mount flag and creates OCI // spec mounts. // buildah run --mount type=bind,src=/etc/resolv.conf,target=/etc/resolv.conf ... +// buildah run --mount type=cache,target=/var/cache ... // buildah run --mount type=tmpfs,target=/dev/shm ... // // If this function succeeds, the caller must unlock the returned *lockfile.LockFile s if any (when??). @@ -590,7 +591,7 @@ func getMounts(ctx *types.SystemContext, store storage.Store, mounts []string, c } finalMounts[mount.Destination] = mount case TypeTmpfs: - mount, err := GetTmpfsMount(tokens) + mount, err := GetTmpfsMount(tokens, workDir) if err != nil { return nil, mountedImages, nil, err } @@ -608,7 +609,7 @@ func getMounts(ctx *types.SystemContext, store storage.Store, mounts []string, c } // GetTmpfsMount parses a single tmpfs mount entry from the --mount flag -func GetTmpfsMount(args []string) (specs.Mount, error) { +func GetTmpfsMount(args []string, workDir string) (specs.Mount, error) { newMount := specs.Mount{ Type: TypeTmpfs, Source: TypeTmpfs, @@ -646,10 +647,14 @@ func GetTmpfsMount(args []string) (specs.Mount, error) { if !hasArgValue { return newMount, fmt.Errorf("%v: %w", argName, errBadOptionArg) } - if err := parse.ValidateVolumeCtrDir(argValue); err != nil { + targetPath := argValue + if !path.IsAbs(targetPath) { + targetPath = filepath.Join(workDir, targetPath) + } + if err := parse.ValidateVolumeCtrDir(targetPath); err != nil { return newMount, err } - newMount.Destination = argValue + newMount.Destination = targetPath setDest = true default: return newMount, fmt.Errorf("%v: %w", argName, errBadMntOption) diff --git a/run_common.go b/run_common.go index 8aa07e547d9..8ea14bdfc34 100644 --- a/run_common.go +++ b/run_common.go @@ -1605,7 +1605,7 @@ func (b *Builder) runSetupRunMounts(mountPoint string, mounts []string, sources mountImages = append(mountImages, image) } case "tmpfs": - mountSpec, err = b.getTmpfsMount(tokens, idMaps) + mountSpec, err = b.getTmpfsMount(tokens, idMaps, sources.WorkDir) if err != nil { return nil, nil, err } @@ -1665,9 +1665,9 @@ func (b *Builder) getBindMount(tokens []string, context *imageTypes.SystemContex return &volumes[0], image, nil } -func (b *Builder) getTmpfsMount(tokens []string, idMaps IDMaps) (*specs.Mount, error) { +func (b *Builder) getTmpfsMount(tokens []string, idMaps IDMaps, workDir string) (*specs.Mount, error) { var optionMounts []specs.Mount - mount, err := volumes.GetTmpfsMount(tokens) + mount, err := volumes.GetTmpfsMount(tokens, workDir) if err != nil { return nil, err } diff --git a/run_freebsd.go b/run_freebsd.go index 4d7d593d449..79ea3a44d3d 100644 --- a/run_freebsd.go +++ b/run_freebsd.go @@ -124,10 +124,16 @@ func (b *Builder) Run(command []string, options RunOptions) error { return err } + workDir := b.WorkDir() if options.WorkingDir != "" { g.SetProcessCwd(options.WorkingDir) + workDir = options.WorkingDir } else if b.WorkDir() != "" { g.SetProcessCwd(b.WorkDir()) + workDir = b.WorkDir() + } + if workDir == "" { + workDir = string(os.PathSeparator) } mountPoint, err := b.Mount(b.MountLabel) if err != nil { @@ -249,6 +255,7 @@ func (b *Builder) Run(command []string, options RunOptions) error { } runMountInfo := runMountInfo{ + WorkDir: workDir, ContextDir: options.ContextDir, Secrets: options.Secrets, SSHSources: options.SSHSources, diff --git a/run_linux.go b/run_linux.go index 0018cb3346f..71d92323e5c 100644 --- a/run_linux.go +++ b/run_linux.go @@ -237,6 +237,10 @@ func (b *Builder) Run(command []string, options RunOptions) error { workDir = options.WorkingDir } else if b.WorkDir() != "" { g.SetProcessCwd(b.WorkDir()) + workDir = b.WorkDir() + } + if workDir == "" { + workDir = string(os.PathSeparator) } setupSelinux(g, b.ProcessLabel, b.MountLabel) mountPoint, err := b.Mount(b.MountLabel) diff --git a/tests/bud.bats b/tests/bud.bats index 7747aab685b..cab3042ba0e 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -7017,3 +7017,17 @@ EOF run_buildah 1 build --security-opt label=disable --build-context testbuild=${TEST_SCRATCH_DIR}/cve20249675/ --no-cache ${TEST_SCRATCH_DIR}/cve20249675/ expect_output --substring "cat: can't open '/var/tmp/file.txt': No such file or directory" } + +@test "build-mounts-implicit-workdir" { + base=busybox + _prefetch $base + run_buildah inspect --format '{{.Docker.Config.WorkingDir}}' --type=image $base + expect_output "" "test base image needs to not have a default working directory defined in its configuration" + # check that the target for a bind mount can be specified as a relative path even when there's no WorkingDir defined for it to be relative to + echo FROM $base > ${TEST_SCRATCH_DIR}/Containerfile + echo RUN --mount=type=bind,src=Containerfile,target=Containerfile test -s Containerfile >> ${TEST_SCRATCH_DIR}/Containerfile + echo RUN --mount=type=cache,id=cash,target=cachesubdir truncate -s 1024 cachesubdir/cachefile >> ${TEST_SCRATCH_DIR}/Containerfile + echo RUN --mount=type=cache,id=cash,target=cachesubdir2 test -s cachesubdir2/cachefile >> ${TEST_SCRATCH_DIR}/Containerfile + echo RUN --mount=type=tmpfs,target=tmpfssubdir test '`stat -f -c %i .`' '!=' '`stat -f -c %i tmpfssubdir`' >> ${TEST_SCRATCH_DIR}/Containerfile + run_buildah build --security-opt label=disable ${TEST_SCRATCH_DIR} +}