Files
Daniel J Walsh 57b0b89d0c Vendor in latest containers/storage opencontainers/selinux
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2018-10-23 10:32:32 -04:00

135 lines
4.0 KiB
Go

package graphdriver
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/reexec"
)
const (
chownByMapsCmd = "storage-chown-by-maps"
)
func init() {
reexec.Register(chownByMapsCmd, chownByMapsMain)
}
func chownByMapsMain() {
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "requires mapping configuration on stdin and directory path")
os.Exit(1)
}
// Read and decode our configuration.
discreteMaps := [4][]idtools.IDMap{}
config := bytes.Buffer{}
if _, err := config.ReadFrom(os.Stdin); err != nil {
fmt.Fprintf(os.Stderr, "error reading configuration: %v", err)
os.Exit(1)
}
if err := json.Unmarshal(config.Bytes(), &discreteMaps); err != nil {
fmt.Fprintf(os.Stderr, "error decoding configuration: %v", err)
os.Exit(1)
}
// Try to chroot. This may not be possible, and on some systems that
// means we just Chdir() to the directory, so from here on we should be
// using relative paths.
if err := chrootOrChdir(os.Args[1]); err != nil {
fmt.Fprintf(os.Stderr, "error chrooting to %q: %v", os.Args[1], err)
os.Exit(1)
}
// Build the mapping objects.
toContainer := idtools.NewIDMappingsFromMaps(discreteMaps[0], discreteMaps[1])
if len(toContainer.UIDs()) == 0 && len(toContainer.GIDs()) == 0 {
toContainer = nil
}
toHost := idtools.NewIDMappingsFromMaps(discreteMaps[2], discreteMaps[3])
if len(toHost.UIDs()) == 0 && len(toHost.GIDs()) == 0 {
toHost = nil
}
chown := func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error walking to %q: %v", path, err)
}
return platformLChown(path, info, toHost, toContainer)
}
if err := filepath.Walk(".", chown); err != nil {
fmt.Fprintf(os.Stderr, "error during chown: %v", err)
os.Exit(1)
}
os.Exit(0)
}
// ChownPathByMaps walks the filesystem tree, changing the ownership
// information using the toContainer and toHost mappings, using them to replace
// on-disk owner UIDs and GIDs which are "host" values in the first map with
// UIDs and GIDs for "host" values from the second map which correspond to the
// same "container" IDs.
func ChownPathByMaps(path string, toContainer, toHost *idtools.IDMappings) error {
if toContainer == nil {
toContainer = &idtools.IDMappings{}
}
if toHost == nil {
toHost = &idtools.IDMappings{}
}
config, err := json.Marshal([4][]idtools.IDMap{toContainer.UIDs(), toContainer.GIDs(), toHost.UIDs(), toHost.GIDs()})
if err != nil {
return err
}
cmd := reexec.Command(chownByMapsCmd, path)
cmd.Stdin = bytes.NewReader(config)
output, err := cmd.CombinedOutput()
if len(output) > 0 && err != nil {
return fmt.Errorf("%v: %s", err, string(output))
}
if err != nil {
return err
}
if len(output) > 0 {
return fmt.Errorf("%s", string(output))
}
return nil
}
type naiveLayerIDMapUpdater struct {
ProtoDriver
}
// NewNaiveLayerIDMapUpdater wraps the ProtoDriver in a LayerIDMapUpdater that
// uses ChownPathByMaps to update the ownerships in a layer's filesystem tree.
func NewNaiveLayerIDMapUpdater(driver ProtoDriver) LayerIDMapUpdater {
return &naiveLayerIDMapUpdater{ProtoDriver: driver}
}
// UpdateLayerIDMap walks the layer's filesystem tree, changing the ownership
// information using the toContainer and toHost mappings, using them to replace
// on-disk owner UIDs and GIDs which are "host" values in the first map with
// UIDs and GIDs for "host" values from the second map which correspond to the
// same "container" IDs.
func (n *naiveLayerIDMapUpdater) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMappings, mountLabel string) error {
driver := n.ProtoDriver
options := MountOpts{
MountLabel: mountLabel,
}
layerFs, err := driver.Get(id, options)
if err != nil {
return err
}
defer func() {
driver.Put(id)
}()
return ChownPathByMaps(layerFs, toContainer, toHost)
}
// SupportsShifting tells whether the driver support shifting of the UIDs/GIDs in an userNS
func (n *naiveLayerIDMapUpdater) SupportsShifting() bool {
return false
}