Ver código fonte

Restrict checkpoint name to prevent directory traversal

This fix tries to address the issue raised in 28769 where
checkpoint name was not checked before passing to containerd.
As a result, it was possible to use a special checkpoint name
to get outside of the container's directory.

This fix add restriction `[a-zA-Z0-9][a-zA-Z0-9_.-]+` (`RestrictedNamePattern`).
This is the same as container name restriction.

This fix fixes 28769.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
Yong Tang 8 anos atrás
pai
commit
c90ec05175
4 arquivos alterados com 14 adições e 6 exclusões
  1. 10 0
      daemon/checkpoint.go
  2. 2 1
      daemon/names.go
  3. 1 4
      utils/names.go
  4. 1 1
      volume/local/local.go

+ 10 - 0
daemon/checkpoint.go

@@ -8,6 +8,12 @@ import (
 	"path/filepath"
 
 	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/utils"
+)
+
+var (
+	validCheckpointNameChars   = utils.RestrictedNameChars
+	validCheckpointNamePattern = utils.RestrictedNamePattern
 )
 
 // CheckpointCreate checkpoints the process running in a container with CRIU
@@ -28,6 +34,10 @@ func (daemon *Daemon) CheckpointCreate(name string, config types.CheckpointCreat
 		checkpointDir = container.CheckpointDir()
 	}
 
+	if !validCheckpointNamePattern.MatchString(config.CheckpointID) {
+		return fmt.Errorf("Invalid checkpoint ID (%s), only %s are allowed", config.CheckpointID, validCheckpointNameChars)
+	}
+
 	err = daemon.containerd.CreateCheckpoint(container.ID, config.CheckpointID, checkpointDir, config.Exit)
 	if err != nil {
 		return fmt.Errorf("Cannot checkpoint container %s: %s", name, err)

+ 2 - 1
daemon/names.go

@@ -2,6 +2,7 @@ package daemon
 
 import (
 	"fmt"
+	"strings"
 
 	"github.com/Sirupsen/logrus"
 	"github.com/docker/docker/container"
@@ -58,7 +59,7 @@ func (daemon *Daemon) generateIDAndName(name string) (string, string, error) {
 }
 
 func (daemon *Daemon) reserveName(id, name string) (string, error) {
-	if !validContainerNamePattern.MatchString(name) {
+	if !validContainerNamePattern.MatchString(strings.TrimPrefix(name, "/")) {
 		return "", fmt.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)
 	}
 	if name[0] != '/' {

+ 1 - 4
utils/names.go

@@ -6,7 +6,4 @@ import "regexp"
 const RestrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
 
 // RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters.
-var RestrictedNamePattern = regexp.MustCompile(`^/?` + RestrictedNameChars + `+$`)
-
-// RestrictedVolumeNamePattern is a regular expression to validate volume names against the collection of restricted characters.
-var RestrictedVolumeNamePattern = regexp.MustCompile(`^` + RestrictedNameChars + `+$`)
+var RestrictedNamePattern = regexp.MustCompile(`^` + RestrictedNameChars + `+$`)

+ 1 - 1
volume/local/local.go

@@ -36,7 +36,7 @@ var (
 	// volumeNameRegex ensures the name assigned for the volume is valid.
 	// This name is used to create the bind directory, so we need to avoid characters that
 	// would make the path to escape the root directory.
-	volumeNameRegex = utils.RestrictedVolumeNamePattern
+	volumeNameRegex = utils.RestrictedNamePattern
 )
 
 type validationError struct {