2017-04-11 22:27:05 +08:00
|
|
|
package buildah
|
|
|
|
|
|
|
|
import (
|
2022-07-06 17:14:06 +08:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2018-03-17 05:19:29 +08:00
|
|
|
"io"
|
2018-04-24 03:55:46 +08:00
|
|
|
"os"
|
2019-05-30 12:22:53 +08:00
|
|
|
"path/filepath"
|
2019-07-25 22:10:03 +08:00
|
|
|
"sync"
|
2018-04-24 03:55:46 +08:00
|
|
|
|
2019-07-25 22:10:03 +08:00
|
|
|
"github.com/containers/buildah/copier"
|
2019-10-26 05:19:30 +08:00
|
|
|
"github.com/containers/image/v5/docker/reference"
|
|
|
|
"github.com/containers/image/v5/pkg/sysregistriesv2"
|
|
|
|
"github.com/containers/image/v5/types"
|
2018-09-27 10:23:37 +08:00
|
|
|
"github.com/containers/storage"
|
2018-03-08 07:11:43 +08:00
|
|
|
"github.com/containers/storage/pkg/idtools"
|
2017-04-11 22:27:05 +08:00
|
|
|
"github.com/containers/storage/pkg/reexec"
|
2019-07-18 16:42:09 +08:00
|
|
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
2018-03-08 07:11:43 +08:00
|
|
|
rspec "github.com/opencontainers/runtime-spec/specs-go"
|
2025-03-24 20:32:00 +08:00
|
|
|
"github.com/opencontainers/selinux/go-selinux"
|
2018-10-03 02:48:11 +08:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-04-11 22:27:05 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// InitReexec is a wrapper for reexec.Init(). It should be called at
|
|
|
|
// the start of main(), and if it returns true, main() should return
|
|
|
|
// immediately.
|
|
|
|
func InitReexec() bool {
|
|
|
|
return reexec.Init()
|
|
|
|
}
|
Maintain multiple working container configs
Maintain the container configuration in multiple formats in the Buildah
object, initializing one based on the other, depending on which format
the source image used for its configuration.
Replace directly manipulated fields in the Buildah object (Annotations,
CreatedBy, OS, Architecture, Maintainer, User, Workdir, Env, Cmd,
Entrypoint, Expose, Labels, and Volumes) with accessor functions which
update both configurations and which read from whichever one we consider
to be authoritative. Drop Args because we weren't using them.
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
Closes: #102
Approved by: rhatdan
2017-05-16 23:08:52 +08:00
|
|
|
|
2019-01-19 04:39:58 +08:00
|
|
|
func copyHistory(history []v1.History) []v1.History {
|
|
|
|
if len(history) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
h := make([]v1.History, 0, len(history))
|
|
|
|
for _, entry := range history {
|
|
|
|
created := entry.Created
|
|
|
|
if created != nil {
|
|
|
|
timestamp := *created
|
|
|
|
created = ×tamp
|
|
|
|
}
|
|
|
|
h = append(h, v1.History{
|
|
|
|
Created: created,
|
|
|
|
CreatedBy: entry.CreatedBy,
|
|
|
|
Author: entry.Author,
|
|
|
|
Comment: entry.Comment,
|
|
|
|
EmptyLayer: entry.EmptyLayer,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
2018-03-08 07:11:43 +08:00
|
|
|
func convertStorageIDMaps(UIDMap, GIDMap []idtools.IDMap) ([]rspec.LinuxIDMapping, []rspec.LinuxIDMapping) {
|
|
|
|
uidmap := make([]rspec.LinuxIDMapping, 0, len(UIDMap))
|
|
|
|
gidmap := make([]rspec.LinuxIDMapping, 0, len(GIDMap))
|
|
|
|
for _, m := range UIDMap {
|
|
|
|
uidmap = append(uidmap, rspec.LinuxIDMapping{
|
|
|
|
HostID: uint32(m.HostID),
|
|
|
|
ContainerID: uint32(m.ContainerID),
|
|
|
|
Size: uint32(m.Size),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, m := range GIDMap {
|
|
|
|
gidmap = append(gidmap, rspec.LinuxIDMapping{
|
|
|
|
HostID: uint32(m.HostID),
|
|
|
|
ContainerID: uint32(m.ContainerID),
|
|
|
|
Size: uint32(m.Size),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return uidmap, gidmap
|
|
|
|
}
|
2018-04-24 03:55:46 +08:00
|
|
|
|
2018-03-13 01:53:12 +08:00
|
|
|
func convertRuntimeIDMaps(UIDMap, GIDMap []rspec.LinuxIDMapping) ([]idtools.IDMap, []idtools.IDMap) {
|
|
|
|
uidmap := make([]idtools.IDMap, 0, len(UIDMap))
|
|
|
|
gidmap := make([]idtools.IDMap, 0, len(GIDMap))
|
|
|
|
for _, m := range UIDMap {
|
|
|
|
uidmap = append(uidmap, idtools.IDMap{
|
|
|
|
HostID: int(m.HostID),
|
|
|
|
ContainerID: int(m.ContainerID),
|
|
|
|
Size: int(m.Size),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, m := range GIDMap {
|
|
|
|
gidmap = append(gidmap, idtools.IDMap{
|
|
|
|
HostID: int(m.HostID),
|
|
|
|
ContainerID: int(m.ContainerID),
|
|
|
|
Size: int(m.Size),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return uidmap, gidmap
|
|
|
|
}
|
|
|
|
|
2018-10-03 01:48:45 +08:00
|
|
|
// isRegistryBlocked checks if the named registry is marked as blocked
|
|
|
|
func isRegistryBlocked(registry string, sc *types.SystemContext) (bool, error) {
|
2018-12-04 02:02:47 +08:00
|
|
|
reginfo, err := sysregistriesv2.FindRegistry(sc, registry)
|
2018-10-03 01:48:45 +08:00
|
|
|
if err != nil {
|
2022-07-06 17:14:06 +08:00
|
|
|
return false, fmt.Errorf("unable to parse the registries configuration (%s): %w", sysregistriesv2.ConfigPath(sc), err)
|
2018-10-03 01:48:45 +08:00
|
|
|
}
|
2018-12-04 02:02:47 +08:00
|
|
|
if reginfo != nil {
|
2018-10-03 02:48:11 +08:00
|
|
|
if reginfo.Blocked {
|
2019-08-02 17:30:22 +08:00
|
|
|
logrus.Debugf("registry %q is marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigPath(sc))
|
2018-10-03 02:48:11 +08:00
|
|
|
} else {
|
2019-08-02 17:30:22 +08:00
|
|
|
logrus.Debugf("registry %q is not marked as blocked in registries configuration %q", registry, sysregistriesv2.ConfigPath(sc))
|
2018-10-03 02:48:11 +08:00
|
|
|
}
|
2018-10-03 01:48:45 +08:00
|
|
|
return reginfo.Blocked, nil
|
|
|
|
}
|
2019-08-02 17:30:22 +08:00
|
|
|
logrus.Debugf("registry %q is not listed in registries configuration %q, assuming it's not blocked", registry, sysregistriesv2.ConfigPath(sc))
|
2018-10-03 01:48:45 +08:00
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// isReferenceSomething checks if the registry part of a reference is insecure or blocked
|
|
|
|
func isReferenceSomething(ref types.ImageReference, sc *types.SystemContext, what func(string, *types.SystemContext) (bool, error)) (bool, error) {
|
2022-01-18 10:24:23 +08:00
|
|
|
if ref != nil {
|
|
|
|
if named := ref.DockerReference(); named != nil {
|
2018-10-03 01:48:45 +08:00
|
|
|
if domain := reference.Domain(named); domain != "" {
|
|
|
|
return what(domain, sc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// isReferenceBlocked checks if the registry part of a reference is blocked
|
|
|
|
func isReferenceBlocked(ref types.ImageReference, sc *types.SystemContext) (bool, error) {
|
|
|
|
if ref != nil && ref.Transport() != nil {
|
|
|
|
switch ref.Transport().Name() {
|
|
|
|
case "docker":
|
|
|
|
return isReferenceSomething(ref, sc, isRegistryBlocked)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
2019-07-25 22:10:03 +08:00
|
|
|
// ReserveSELinuxLabels reads containers storage and reserves SELinux contexts
|
|
|
|
// which are already being used by buildah containers.
|
2018-09-27 10:23:37 +08:00
|
|
|
func ReserveSELinuxLabels(store storage.Store, id string) error {
|
2019-07-25 22:10:03 +08:00
|
|
|
if selinuxGetEnabled() {
|
2018-09-27 10:23:37 +08:00
|
|
|
containers, err := store.Containers()
|
|
|
|
if err != nil {
|
2022-09-18 18:36:08 +08:00
|
|
|
return fmt.Errorf("getting list of containers: %w", err)
|
2018-09-27 10:23:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range containers {
|
|
|
|
if id == c.ID {
|
|
|
|
continue
|
2024-08-07 03:07:45 +08:00
|
|
|
}
|
|
|
|
b, err := OpenBuilder(store, c.ID)
|
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
|
|
// Ignore not exist errors since containers probably created by other tool
|
|
|
|
// TODO, we need to read other containers json data to reserve their SELinux labels
|
|
|
|
continue
|
2018-09-27 10:23:37 +08:00
|
|
|
}
|
2024-08-07 03:07:45 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Prevent different containers from using same MCS label
|
2025-03-24 20:32:00 +08:00
|
|
|
selinux.ReserveLabel(b.ProcessLabel)
|
2018-09-27 10:23:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-11 20:21:22 +08:00
|
|
|
|
|
|
|
// IsContainer identifies if the specified container id is a buildah container
|
|
|
|
// in the specified store.
|
|
|
|
func IsContainer(id string, store storage.Store) (bool, error) {
|
|
|
|
cdir, err := store.ContainerDirectory(id)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
// Assuming that if the stateFile exists, that this is a Buildah
|
|
|
|
// container.
|
|
|
|
if _, err = os.Stat(filepath.Join(cdir, stateFile)); err != nil {
|
2022-07-27 03:27:30 +08:00
|
|
|
if errors.Is(err, os.ErrNotExist) {
|
2020-08-11 20:21:22 +08:00
|
|
|
return false, nil
|
|
|
|
}
|
2020-10-15 17:16:50 +08:00
|
|
|
return false, err
|
2020-08-11 20:21:22 +08:00
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
2019-07-25 22:10:03 +08:00
|
|
|
|
|
|
|
// Copy content from the directory "src" to the directory "dest", ensuring that
|
|
|
|
// content from outside of "root" (which is a parent of "src" or "src" itself)
|
|
|
|
// isn't read.
|
|
|
|
func extractWithTar(root, src, dest string) error {
|
|
|
|
var getErr, putErr error
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
pipeReader, pipeWriter := io.Pipe()
|
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
getErr = copier.Get(root, src, copier.GetOptions{}, []string{"."}, pipeWriter)
|
|
|
|
pipeWriter.Close()
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
putErr = copier.Put(dest, dest, copier.PutOptions{}, pipeReader)
|
|
|
|
pipeReader.Close()
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
if getErr != nil {
|
2022-09-18 18:36:08 +08:00
|
|
|
return fmt.Errorf("reading %q: %w", src, getErr)
|
2019-07-25 22:10:03 +08:00
|
|
|
}
|
|
|
|
if putErr != nil {
|
2022-09-18 18:36:08 +08:00
|
|
|
return fmt.Errorf("copying contents of %q to %q: %w", src, dest, putErr)
|
2019-07-25 22:10:03 +08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|