@@ -20,6 +20,7 @@ import (
2020 buildahdocker "github.com/containers/buildah/docker"
2121 "github.com/containers/buildah/internal"
2222 "github.com/containers/buildah/internal/metadata"
23+ "github.com/containers/buildah/internal/sanitize"
2324 "github.com/containers/buildah/internal/tmpdir"
2425 internalUtil "github.com/containers/buildah/internal/util"
2526 "github.com/containers/buildah/pkg/parse"
@@ -453,7 +454,7 @@ func (s *stageExecutor) performCopy(excludes []string, copies ...imagebuilder.Co
453454 copy .Src = copySources
454455 }
455456
456- if len ( copy .From ) > 0 && len (copy .Files ) == 0 {
457+ if copy .From != "" && len (copy .Files ) == 0 {
457458 // If from has an argument within it, resolve it to its
458459 // value. Otherwise just return the value found.
459460 from , fromErr := imagebuilder .ProcessWord (copy .From , s .stage .Builder .Arguments ())
@@ -535,7 +536,8 @@ func (s *stageExecutor) performCopy(excludes []string, copies ...imagebuilder.Co
535536 }
536537 contextDir = mountPoint
537538 }
538- // Original behaviour of buildah still stays true for COPY irrespective of additional context.
539+ // With --from set, the content being copied isn't coming from the default
540+ // build context directory, so we're not expected to force everything to 0:0
539541 preserveOwnership = true
540542 copyExcludes = excludes
541543 } else {
@@ -618,9 +620,14 @@ func (s *stageExecutor) performCopy(excludes []string, copies ...imagebuilder.Co
618620}
619621
620622// Returns a map of StageName/ImageName:internal.StageMountDetails for the
621- // items in the passed-in mounts list which include a "from=" value.
623+ // items in the passed-in mounts list which include a "from=" value. The ""
624+ // key in the returned map corresponds to the default build context.
622625func (s * stageExecutor ) runStageMountPoints (mountList []string ) (map [string ]internal.StageMountDetails , error ) {
623626 stageMountPoints := make (map [string ]internal.StageMountDetails )
627+ stageMountPoints ["" ] = internal.StageMountDetails {
628+ MountPoint : s .executor .contextDir ,
629+ IsWritesDiscardedOverlay : s .executor .contextDirWritesAreDiscarded ,
630+ }
624631 for _ , flag := range mountList {
625632 if strings .Contains (flag , "from" ) {
626633 tokens := strings .Split (flag , "," )
@@ -650,7 +657,7 @@ func (s *stageExecutor) runStageMountPoints(mountList []string) (map[string]inte
650657 if additionalBuildContext .IsImage {
651658 mountPoint , err := s .getImageRootfs (s .ctx , additionalBuildContext .Value )
652659 if err != nil {
653- return nil , fmt .Errorf ("%s from=%s: image found with that name" , flag , from )
660+ return nil , fmt .Errorf ("%s from=%s: image not found with that name" , flag , from )
654661 }
655662 // The `from` in stageMountPoints should point
656663 // to `mountPoint` replaced from additional
@@ -932,6 +939,29 @@ func (s *stageExecutor) UnrecognizedInstruction(step *imagebuilder.Step) error {
932939 return errors .New (err )
933940}
934941
942+ // sanitizeFrom limits which image names (with or without transport prefixes)
943+ // we'll accept. For those it accepts which refer to filesystem objects, where
944+ // relative path names are evaluated relative to "contextDir", it will create a
945+ // copy of the original image, under "tmpdir", which contains no symbolic
946+ // links, and return either the original image reference or a reference to a
947+ // sanitized copy which should be used instead.
948+ func (s * stageExecutor ) sanitizeFrom (from , tmpdir string ) (newFrom string , err error ) {
949+ transportName , restOfImageName , maybeHasTransportName := strings .Cut (from , ":" )
950+ if ! maybeHasTransportName || transports .Get (transportName ) == nil {
951+ if _ , err = reference .ParseNormalizedNamed (from ); err == nil {
952+ // this is a normal-looking image-in-a-registry-or-named-in-storage name
953+ return from , nil
954+ }
955+ if img , err := s .executor .store .Image (from ); img != nil && err == nil {
956+ // this is an image ID
957+ return from , nil
958+ }
959+ return "" , fmt .Errorf ("parsing image name %q: %w" , from , err )
960+ }
961+ // TODO: drop this part and just return an error... someday
962+ return sanitize .ImageName (transportName , restOfImageName , s .executor .contextDir , tmpdir )
963+ }
964+
935965// prepare creates a working container based on the specified image, or if one
936966// isn't specified, the first argument passed to the first FROM instruction we
937967// can find in the stage's parsed tree.
@@ -948,6 +978,10 @@ func (s *stageExecutor) prepare(ctx context.Context, from string, initializeIBCo
948978 }
949979 from = base
950980 }
981+ sanitizedFrom , err := s .sanitizeFrom (from , tmpdir .GetTempDir ())
982+ if err != nil {
983+ return nil , fmt .Errorf ("invalid base image specification %q: %w" , from , err )
984+ }
951985 displayFrom := from
952986 if ib .Platform != "" {
953987 displayFrom = "--platform=" + ib .Platform + " " + displayFrom
@@ -987,7 +1021,7 @@ func (s *stageExecutor) prepare(ctx context.Context, from string, initializeIBCo
9871021
9881022 builderOptions := buildah.BuilderOptions {
9891023 Args : ib .Args ,
990- FromImage : from ,
1024+ FromImage : sanitizedFrom ,
9911025 GroupAdd : s .executor .groupAdd ,
9921026 PullPolicy : pullPolicy ,
9931027 ContainerSuffix : s .executor .containerSuffix ,
@@ -1025,16 +1059,6 @@ func (s *stageExecutor) prepare(ctx context.Context, from string, initializeIBCo
10251059 return nil , fmt .Errorf ("creating build container: %w" , err )
10261060 }
10271061
1028- // If executor's ProcessLabel and MountLabel is empty means this is the first stage
1029- // Make sure we share first stage's ProcessLabel and MountLabel with all other subsequent stages
1030- // Doing this will ensure and one stage in same build can mount another stage even if `selinux`
1031- // is enabled.
1032-
1033- if s .executor .mountLabel == "" && s .executor .processLabel == "" {
1034- s .executor .mountLabel = builder .MountLabel
1035- s .executor .processLabel = builder .ProcessLabel
1036- }
1037-
10381062 if initializeIBConfig {
10391063 volumes := map [string ]struct {}{}
10401064 for _ , v := range builder .Volumes () {
0 commit comments