1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #20523 from cyli/vendor-notary-version-for-docker-1.10.2

Bump the notary version to one that fixes a bug with delegation path traversal
This commit is contained in:
Tibor Vass 2016-02-19 19:36:29 -05:00
commit 1bfaf317a9
9 changed files with 155 additions and 31 deletions

View file

@ -88,7 +88,7 @@ RUN cd /usr/local/lvm2 \
# Install Go
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# with a heads-up.
ENV GO_VERSION 1.5.3
RUN curl -fsSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" \
@ -168,7 +168,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_VERSION docker-v1.10-5
ENV NOTARY_VERSION docker-v1.10.2-1
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \

View file

@ -145,7 +145,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_VERSION docker-v1.10-5
ENV NOTARY_VERSION docker-v1.10.2-1
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \

View file

@ -116,7 +116,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
#ENV NOTARY_VERSION docker-v1.10-5
#ENV NOTARY_VERSION docker-v1.10.2-1
#RUN set -x \
# && export GOPATH="$(mktemp -d)" \
# && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \

View file

@ -116,7 +116,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_VERSION docker-v1.10-5
ENV NOTARY_VERSION docker-v1.10.2-1
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \

View file

@ -50,7 +50,7 @@ clone git github.com/docker/distribution 0f2d99b13ae0cfbcf118eff103e6e680b726b47
clone git github.com/vbatts/tar-split v0.9.11
# get desired notary commit, might also need to be updated in Dockerfile
clone git github.com/docker/notary docker-v1.10-5
clone git github.com/docker/notary docker-v1.10.2-1
clone git google.golang.org/grpc 174192fc93efcb188fc8f46ca447f0da606b6885 https://github.com/grpc/grpc-go.git
clone git github.com/miekg/pkcs11 80f102b5cac759de406949c47f0928b99bd64cdf

View file

@ -9,6 +9,7 @@ import (
"net/url"
"os"
"path/filepath"
"strings"
"time"
"github.com/Sirupsen/logrus"
@ -451,11 +452,48 @@ func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, erro
roles = []string{data.CanonicalTargetsRole}
}
targets := make(map[string]*TargetWithRole)
for _, role := range roles {
var foundRole *data.Role
walkRoles := []*data.Role{}
if role == data.CanonicalTargetsRole {
foundRole = &data.Role{
Name: data.CanonicalTargetsRole,
Paths: []string{""},
PathHashPrefixes: []string{""},
}
}
walkRoles = append(walkRoles, r.tufRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Roles...)
for len(walkRoles) > 0 && foundRole == nil {
currRole := walkRoles[0]
walkRoles = walkRoles[1:]
if currRole.Name == role {
foundRole = currRole
break
}
if strings.HasPrefix(role, currRole.Name+"/") {
targetMeta, ok := r.tufRepo.Targets[currRole.Name]
if !ok {
continue
}
for _, childRole := range targetMeta.Signed.Delegations.Roles {
restricted, err := data.Restrict(*currRole, *childRole)
if err == nil {
walkRoles = append(walkRoles, restricted)
}
}
}
}
if foundRole == nil {
continue
}
// we don't need to do anything special with removing role from
// roles because listSubtree always processes role and only excludes
// descendant delegations that appear in roles.
r.listSubtree(targets, role, roles...)
r.listSubtree(targets, foundRole, roles...)
}
var targetList []*TargetWithRole
@ -466,29 +504,32 @@ func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, erro
return targetList, nil
}
func (r *NotaryRepository) listSubtree(targets map[string]*TargetWithRole, role string, exclude ...string) {
func (r *NotaryRepository) listSubtree(targets map[string]*TargetWithRole, role *data.Role, exclude ...string) {
excl := make(map[string]bool)
for _, r := range exclude {
excl[r] = true
}
roles := []string{role}
roles := []*data.Role{role}
for len(roles) > 0 {
role = roles[0]
roles = roles[1:]
tgts, ok := r.tufRepo.Targets[role]
tgts, ok := r.tufRepo.Targets[role.Name]
if !ok {
// not every role has to exist
continue
}
for name, meta := range tgts.Signed.Targets {
if _, ok := targets[name]; !ok {
if _, ok := targets[name]; !ok && role.CheckPaths(name) {
targets[name] = &TargetWithRole{
Target: Target{Name: name, Hashes: meta.Hashes, Length: meta.Length}, Role: role}
Target: Target{Name: name, Hashes: meta.Hashes, Length: meta.Length}, Role: role.Name}
}
}
for _, d := range tgts.Signed.Delegations.Roles {
if !excl[d.Name] {
roles = append(roles, d.Name)
for _, child := range tgts.Signed.Delegations.Roles {
if !excl[child.Name] {
child, err := data.Restrict(*role, *child)
if err == nil {
roles = append(roles, child)
}
}
}
}
@ -511,10 +552,47 @@ func (r *NotaryRepository) GetTargetByName(name string, roles ...string) (*Targe
roles = append(roles, data.CanonicalTargetsRole)
}
for _, role := range roles {
meta, foundRole := c.TargetMeta(role, name, roles...)
var foundRole *data.Role
walkRoles := []*data.Role{}
if role == data.CanonicalTargetsRole {
foundRole = &data.Role{
Name: data.CanonicalTargetsRole,
Paths: []string{""},
PathHashPrefixes: []string{""},
}
}
walkRoles = append(walkRoles, r.tufRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Roles...)
for len(walkRoles) > 0 && foundRole == nil {
currRole := walkRoles[0]
walkRoles = walkRoles[1:]
if currRole.Name == role {
foundRole = currRole
break
}
if strings.HasPrefix(role, currRole.Name+"/") {
targetMeta, ok := r.tufRepo.Targets[currRole.Name]
if !ok {
continue
}
for _, childRole := range targetMeta.Signed.Delegations.Roles {
restricted, err := data.Restrict(*currRole, *childRole)
if err == nil && restricted.CheckPaths(name) {
walkRoles = append(walkRoles, restricted)
}
}
}
}
if foundRole == nil {
continue
}
meta, ownerName := c.TargetMeta(foundRole, name, roles...)
if meta != nil {
return &TargetWithRole{
Target: Target{Name: name, Hashes: meta.Hashes, Length: meta.Length}, Role: foundRole}, nil
Target: Target{Name: name, Hashes: meta.Hashes, Length: meta.Length}, Role: ownerName}, nil
}
}
return nil, fmt.Errorf("No trust data for %s", name)

View file

@ -526,39 +526,44 @@ func (c Client) RoleTargetsPath(role string, hashSha256 string, consistent bool)
// TargetMeta ensures the repo is up to date. It assumes downloadTargets
// has already downloaded all delegated roles
func (c Client) TargetMeta(role, path string, excludeRoles ...string) (*data.FileMeta, string) {
func (c Client) TargetMeta(role *data.Role, path string, excludeRoles ...string) (*data.FileMeta, string) {
excl := make(map[string]bool)
for _, r := range excludeRoles {
excl[r] = true
}
pathDigest := sha256.Sum256([]byte(path))
pathHex := hex.EncodeToString(pathDigest[:])
// FIFO list of targets delegations to inspect for target
roles := []string{role}
roles := []*data.Role{role}
var (
meta *data.FileMeta
curr string
curr *data.Role
)
for len(roles) > 0 {
// have to do these lines here because of order of execution in for statement
curr = roles[0]
roles = roles[1:]
meta = c.local.TargetMeta(curr, path)
meta = c.local.TargetMeta(curr.Name, path)
if meta != nil {
// we found the target!
return meta, curr
return meta, curr.Name
}
delegations := c.local.TargetDelegations(curr, path, pathHex)
for _, d := range delegations {
if !excl[d.Name] {
roles = append(roles, d.Name)
tgts, ok := c.local.Targets[curr.Name]
if !ok {
// not every role has to exist
continue
}
for _, child := range tgts.Signed.Delegations.Roles {
if !excl[child.Name] {
child, err := data.Restrict(*curr, *child)
if err == nil && child.CheckPaths(path) {
roles = append(roles, child)
}
}
}
}
return meta, ""
return nil, ""
}
// DownloadTarget downloads the target to dst from the remote

View file

@ -2,10 +2,11 @@ package data
import (
"fmt"
"github.com/Sirupsen/logrus"
"path"
"regexp"
"strings"
"github.com/Sirupsen/logrus"
)
// Canonical base role names
@ -244,3 +245,40 @@ func subtractStrSlices(orig, remove []string) []string {
}
return keep
}
// Restrict restricts the paths and path hash prefixes for the passed in delegation role,
// returning a copy of the role with validated paths as if it was a direct child
func Restrict(parent, child Role) (*Role, error) {
if path.Dir(child.Name) != parent.Name {
return nil, fmt.Errorf("%s is not a parent of %s", parent.Name, child.Name)
}
return &Role{
RootRole: child.RootRole,
Name: child.Name,
Paths: RestrictDelegationPathPrefixes(parent.Paths, child.Paths),
}, nil
}
// RestrictDelegationPathPrefixes returns the list of valid delegationPaths that are prefixed by parentPaths
func RestrictDelegationPathPrefixes(parentPaths, delegationPaths []string) []string {
validPaths := []string{}
if len(delegationPaths) == 0 {
return validPaths
}
// Validate each individual delegation path
for _, delgPath := range delegationPaths {
isPrefixed := false
for _, parentPath := range parentPaths {
if strings.HasPrefix(delgPath, parentPath) {
isPrefixed = true
break
}
}
// If the delegation path did not match prefix against any parent path, it is not valid
if isPrefixed {
validPaths = append(validPaths, delgPath)
}
}
return validPaths
}

View file

@ -459,6 +459,9 @@ func (tr *Repo) SetTargets(role string, s *data.SignedTargets) error {
tr.keysDB.AddKey(k)
}
for _, r := range s.Signed.Delegations.Roles {
if path.Dir(r.Name) != role || tr.keysDB.GetRole(r.Name) != nil {
continue
}
tr.keysDB.AddRole(r)
}
tr.Targets[role] = s