From 75d53c469ea6115db0386155262565a8aa15556d Mon Sep 17 00:00:00 2001 From: jingrui Date: Thu, 3 Jan 2019 16:04:37 +0800 Subject: [PATCH 044/111] plugin: Fix plugin security bug caused by unchecked plugin name reason: cherry-pick commits to docker-18.09 cherry-pick from 48c9622f82 | * plugin,bugfix: Fix plugin security bug caused by unchecked plugin name Docker may activate plugins outside plugin directory if plugin name contains string like "../../". This patch fix this bug by checking the combined plugin path before use it. fix issue docker/docker#268 Change-Id: Icff8b24e50fc92721149267bc8c29a8652046d8a Signed-off-by: majiuyue Signed-off-by: jingrui --- components/engine/pkg/plugins/discovery.go | 27 ++++++++++++++++------ components/engine/pkg/plugins/plugins.go | 2 +- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/components/engine/pkg/plugins/discovery.go b/components/engine/pkg/plugins/discovery.go index 4b79bd29ad..51f1d8ebea 100644 --- a/components/engine/pkg/plugins/discovery.go +++ b/components/engine/pkg/plugins/discovery.go @@ -14,6 +14,8 @@ import ( ) var ( + // ErrForbidden plugin sock/spec outside allowed location + ErrForbidden = errors.New("plugin outside allowed location") // ErrNotFound plugin not found ErrNotFound = errors.New("plugin not found") socketsPath = "/run/docker/plugins" @@ -82,7 +84,10 @@ func Scan() ([]string, error) { // Plugin returns the plugin registered with the given name (or returns an error). func (l *localRegistry) Plugin(name string) (*Plugin, error) { - socketpaths := pluginPaths(socketsPath, name, ".sock") + socketpaths, err := pluginPaths(socketsPath, name, ".sock") + if err != nil { + return nil, ErrForbidden + } for _, p := range socketpaths { if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 { @@ -92,8 +97,10 @@ func (l *localRegistry) Plugin(name string) (*Plugin, error) { var txtspecpaths []string for _, p := range specsPaths { - txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".spec")...) - txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".json")...) + for _, ext := range []string{".spec", ".json"} { + paths, _ := pluginPaths(p, name, ext) + txtspecpaths = append(txtspecpaths, paths...) + } } for _, p := range txtspecpaths { @@ -146,9 +153,15 @@ func readPluginJSONInfo(name, path string) (*Plugin, error) { return &p, nil } -func pluginPaths(base, name, ext string) []string { - return []string{ - filepath.Join(base, name+ext), - filepath.Join(base, name, name+ext), +func pluginPaths(base, name, ext string) ([]string, error) { + paths := []string{ + filepath.Clean(filepath.Join(base, name+ext)), + filepath.Clean(filepath.Join(base, name, name+ext)), + } + for _, p := range paths { + if !strings.HasPrefix(p, base) { + return nil, ErrForbidden + } } + return paths, nil } diff --git a/components/engine/pkg/plugins/plugins.go b/components/engine/pkg/plugins/plugins.go index 6962079df9..8a6fbeda29 100644 --- a/components/engine/pkg/plugins/plugins.go +++ b/components/engine/pkg/plugins/plugins.go @@ -208,7 +208,7 @@ func loadWithRetry(name string, retry bool) (*Plugin, error) { for { pl, err := registry.Plugin(name) if err != nil { - if !retry { + if !retry || err == ErrForbidden { return nil, err } -- 2.17.1