Skip to content
This repository has been archived by the owner on Aug 14, 2020. It is now read-only.

Commit

Permalink
Merge pull request #204 from lucab/to-upstream/cve-fixes
Browse files Browse the repository at this point in the history
Additional validation on malformed images
  • Loading branch information
jonboulle committed Oct 14, 2016
2 parents 8a4173c + 500caa9 commit 2ab8826
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 12 deletions.
15 changes: 15 additions & 0 deletions lib/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
package common

import (
"fmt"
"regexp"

"github.com/appc/docker2aci/lib/internal/docker"
"github.com/appc/docker2aci/lib/internal/types"
)
Expand All @@ -27,6 +30,10 @@ const (
GzipCompression
)

var (
validId = regexp.MustCompile(`^(\w+:)?([A-Fa-f0-9]+)$`)
)

type ParsedDockerURL types.ParsedDockerURL

const (
Expand Down Expand Up @@ -60,3 +67,11 @@ func ParseDockerURL(arg string) (*ParsedDockerURL, error) {
p, err := docker.ParseDockerURL(arg)
return (*ParsedDockerURL)(p), err
}

// ValidateLayerId validates a layer ID
func ValidateLayerId(id string) error {
if ok := validId.MatchString(id); !ok {
return fmt.Errorf("invalid layer ID %q", id)
}
return nil
}
14 changes: 14 additions & 0 deletions lib/internal/backend/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ func (lb *FileBackend) BuildACI(layerIDs []string, dockerURL *types.ParsedDocker
var aciManifests []*schema.ImageManifest
var curPwl []string
for i := len(layerIDs) - 1; i >= 0; i-- {
if err := common.ValidateLayerId(layerIDs[i]); err != nil {
return nil, nil, err
}
tmpDir, err := ioutil.TempDir(tmpBaseDir, "docker2aci-")
if err != nil {
return nil, nil, fmt.Errorf("error creating dir: %v", err)
Expand Down Expand Up @@ -279,14 +282,24 @@ func extractEmbeddedLayer(file *os.File, layerID string, outputPath string) (*os
return layerFile, nil
}

// getAncestry computes an image ancestry, returning an ordered list
// of dependencies starting from the topmost image to the base.
// It checks for dependency loops via duplicate detection in the image
// chain and errors out in such cases.
func getAncestry(file *os.File, imgID string) ([]string, error) {
var ancestry []string
deps := make(map[string]bool)

curImgID := imgID

var err error
for curImgID != "" {
if deps[curImgID] {
return nil, fmt.Errorf("dependency loop detected at image %q", curImgID)
}
deps[curImgID] = true
ancestry = append(ancestry, curImgID)
log.Debug(fmt.Sprintf("Getting ancestry for layer %q", curImgID))
curImgID, err = getParent(file, curImgID)
if err != nil {
return nil, err
Expand Down Expand Up @@ -328,5 +341,6 @@ func getParent(file *os.File, imgID string) (string, error) {
return "", err
}

log.Debug(fmt.Sprintf("Layer %q depends on layer %q", imgID, parent))
return parent, nil
}
3 changes: 3 additions & 0 deletions lib/internal/backend/repository/repository1.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ func (rb *RepositoryBackend) buildACIV1(layerIDs []string, dockerURL *types.Pars

var doneChannels []chan error
for i, layerID := range layerIDs {
if err := common.ValidateLayerId(layerID); err != nil {
return nil, nil, err
}
doneChan := make(chan error)
doneChannels = append(doneChannels, doneChan)
// https://github.com/golang/go/wiki/CommonMistakes
Expand Down
18 changes: 7 additions & 11 deletions lib/internal/backend/repository/repository2.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"net/http"
"os"
"path"
"regexp"
"strconv"
"strings"
"sync"
Expand All @@ -43,8 +42,6 @@ const (
defaultIndexURL = "registry-1.docker.io"
)

var validHex = regexp.MustCompile(`^([a-f0-9]{64})$`)

// A manifest conforming to the docker v2.1 spec
type v2Manifest struct {
Name string `json:"name"`
Expand Down Expand Up @@ -91,6 +88,9 @@ func (rb *RepositoryBackend) buildACIV21(layerIDs []string, dockerURL *types.Par
closers := make([]io.ReadCloser, len(layerIDs))
var wg sync.WaitGroup
for i, layerID := range layerIDs {
if err := common.ValidateLayerId(layerID); err != nil {
return nil, nil, err
}
wg.Add(1)
errChan := make(chan error, 1)
errChannels = append(errChannels, errChan)
Expand Down Expand Up @@ -195,6 +195,9 @@ func (rb *RepositoryBackend) buildACIV22(layerIDs []string, dockerURL *types.Par

resultChan := make(chan layer, len(layerIDs))
for i, layerID := range layerIDs {
if err := common.ValidateLayerId(layerID); err != nil {
return nil, nil, err
}
// https://github.com/golang/go/wiki/CommonMistakes
i := i // golang--
layerID := layerID
Expand Down Expand Up @@ -436,7 +439,7 @@ func fixManifestLayers(manifest *v2Manifest) error {
}

imgs[i] = img
if err := validateV1ID(img.ID); err != nil {
if err := common.ValidateLayerId(img.ID); err != nil {
return err
}
}
Expand Down Expand Up @@ -471,13 +474,6 @@ func fixManifestLayers(manifest *v2Manifest) error {
return nil
}

func validateV1ID(id string) error {
if ok := validHex.MatchString(id); !ok {
return fmt.Errorf("image ID %q is invalid", id)
}
return nil
}

func (rb *RepositoryBackend) getLayerV2(layerID string, dockerURL *types.ParsedDockerURL, tmpDir string, copier *progressutil.CopyProgressPrinter) (*os.File, io.ReadCloser, error) {
var (
err error
Expand Down
15 changes: 15 additions & 0 deletions tests/fixture-test-depsloop/check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh

DOCKER2ACI=../bin/docker2aci
TESTDIR=$1
TESTNAME=$2

timeout 10s ${DOCKER2ACI} "${TESTDIR}/${TESTNAME}/${TESTNAME}.docker"
if [ $? -eq 1 ]; then
echo "### Test case ${TESTNAME}: SUCCESS"
exit 0
else
echo "### Test case ${TESTNAME}: FAIL"
exit 1
fi

Binary file not shown.
15 changes: 15 additions & 0 deletions tests/fixture-test-invalidlayerid/check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh

DOCKER2ACI=../bin/docker2aci
TESTDIR=$1
TESTNAME=$2

sudo ${DOCKER2ACI} "${TESTDIR}/${TESTNAME}/${TESTNAME}.docker"
if [ $? -eq 1 ]; then
echo "### Test case ${TESTNAME}: SUCCESS"
exit 0
else
echo "### Test case ${TESTNAME}: FAIL"
exit 1
fi

Binary file not shown.
7 changes: 6 additions & 1 deletion tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ RKT=$(which rkt)

DOCKER_STORAGE_BACKEND=$(sudo docker info|grep '^Storage Driver:'|sed 's/Storage Driver: //')

for i in $(find . -maxdepth 1 -type d -name 'fixture-test*') ; do
TESTNAME=$(basename $i)
echo "### Test case ${TESTNAME}..."
$TESTDIR/${TESTNAME}/check.sh "${TESTDIR}" "${TESTNAME}"
done

for i in $(find . -maxdepth 1 -type d -name 'test-*') ; do
TESTNAME=$(basename $i)
echo "### Test case ${TESTNAME}: build..."
Expand Down Expand Up @@ -81,4 +87,3 @@ for i in $(find . -maxdepth 1 -type d -name 'test-*') ; do

sudo docker rmi $PREFIX/${TESTNAME}
done

0 comments on commit 2ab8826

Please sign in to comment.