Browse code

Address feedback from Tonis

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2017/11/21 01:33:20
Showing 24 changed files
... ...
@@ -358,6 +358,9 @@ func addNodesForLabelOption(dockerfile *parser.Node, labels map[string]string) {
358 358
 //
359 359
 // TODO: Remove?
360 360
 func BuildFromConfig(config *container.Config, changes []string, os string) (*container.Config, error) {
361
+	if !system.IsOSSupported(os) {
362
+		return nil, errdefs.InvalidParameter(system.ErrNotSupportedOperatingSystem)
363
+	}
361 364
 	if len(changes) == 0 {
362 365
 		return config, nil
363 366
 	}
... ...
@@ -156,7 +156,9 @@ func initializeStage(d dispatchRequest, cmd *instructions.Stage) error {
156 156
 		return err
157 157
 	}
158 158
 	state := d.state
159
-	state.beginStage(cmd.Name, image)
159
+	if err := state.beginStage(cmd.Name, image); err != nil {
160
+		return err
161
+	}
160 162
 	if len(state.runConfig.OnBuild) > 0 {
161 163
 		triggers := state.runConfig.OnBuild
162 164
 		state.runConfig.OnBuild = nil
... ...
@@ -309,7 +311,9 @@ func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container
309 309
 // RUN [ "echo", "hi" ] # echo hi
310 310
 //
311 311
 func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
312
-
312
+	if !system.IsOSSupported(d.state.operatingSystem) {
313
+		return system.ErrNotSupportedOperatingSystem
314
+	}
313 315
 	stateRunConfig := d.state.runConfig
314 316
 	cmdFromArgs := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, d.state.operatingSystem)
315 317
 	buildArgs := d.state.buildArgs.FilterAllowed(stateRunConfig.Env)
... ...
@@ -21,6 +21,7 @@ package dockerfile
21 21
 
22 22
 import (
23 23
 	"reflect"
24
+	"runtime"
24 25
 	"strconv"
25 26
 	"strings"
26 27
 
... ...
@@ -211,10 +212,16 @@ func (s *dispatchState) hasFromImage() bool {
211 211
 	return s.imageID != "" || (s.baseImage != nil && s.baseImage.ImageID() == "")
212 212
 }
213 213
 
214
-func (s *dispatchState) beginStage(stageName string, image builder.Image) {
214
+func (s *dispatchState) beginStage(stageName string, image builder.Image) error {
215 215
 	s.stageName = stageName
216 216
 	s.imageID = image.ImageID()
217 217
 	s.operatingSystem = image.OperatingSystem()
218
+	if s.operatingSystem == "" { // In case it isn't set
219
+		s.operatingSystem = runtime.GOOS
220
+	}
221
+	if !system.IsOSSupported(s.operatingSystem) {
222
+		return system.ErrNotSupportedOperatingSystem
223
+	}
218 224
 
219 225
 	if image.RunConfig() != nil {
220 226
 		// copy avoids referencing the same instance when 2 stages have the same base
... ...
@@ -226,6 +233,7 @@ func (s *dispatchState) beginStage(stageName string, image builder.Image) {
226 226
 	s.setDefaultPath()
227 227
 	s.runConfig.OpenStdin = false
228 228
 	s.runConfig.StdinOnce = false
229
+	return nil
229 230
 }
230 231
 
231 232
 // Add the default PATH to runConfig.ENV if one exists for the operating system and there
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/docker/docker/pkg/containerfs"
13 13
 	"github.com/docker/docker/pkg/idtools"
14 14
 	"github.com/docker/docker/pkg/stringid"
15
+	"github.com/docker/docker/pkg/system"
15 16
 	"github.com/docker/docker/registry"
16 17
 	"github.com/pkg/errors"
17 18
 	"github.com/sirupsen/logrus"
... ...
@@ -70,7 +71,7 @@ func (rl *releaseableLayer) Commit() (builder.ReleaseableLayer, error) {
70 70
 	if err != nil {
71 71
 		return nil, err
72 72
 	}
73
-	// TODO: An optimization woudld be to handle empty layers before returning
73
+	// TODO: An optimization would be to handle empty layers before returning
74 74
 	return &releaseableLayer{layerStore: rl.layerStore, roLayer: newLayer}, nil
75 75
 }
76 76
 
... ...
@@ -171,6 +172,9 @@ func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfi
171 171
 // leaking of layers.
172 172
 func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ReleaseableLayer, error) {
173 173
 	if refOrID == "" {
174
+		if !system.IsOSSupported(opts.OS) {
175
+			return nil, nil, system.ErrNotSupportedOperatingSystem
176
+		}
174 177
 		layer, err := newReleasableLayerForImage(nil, daemon.layerStores[opts.OS])
175 178
 		return nil, layer, err
176 179
 	}
... ...
@@ -182,6 +186,9 @@ func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID st
182 182
 		}
183 183
 		// TODO: shouldn't we error out if error is different from "not found" ?
184 184
 		if image != nil {
185
+			if !system.IsOSSupported(image.OperatingSystem()) {
186
+				return nil, nil, system.ErrNotSupportedOperatingSystem
187
+			}
185 188
 			layer, err := newReleasableLayerForImage(image, daemon.layerStores[image.OperatingSystem()])
186 189
 			return image, layer, err
187 190
 		}
... ...
@@ -191,6 +198,9 @@ func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID st
191 191
 	if err != nil {
192 192
 		return nil, nil, err
193 193
 	}
194
+	if !system.IsOSSupported(image.OperatingSystem()) {
195
+		return nil, nil, system.ErrNotSupportedOperatingSystem
196
+	}
194 197
 	layer, err := newReleasableLayerForImage(image, daemon.layerStores[image.OperatingSystem()])
195 198
 	return image, layer, err
196 199
 }
... ...
@@ -17,6 +17,7 @@ import (
17 17
 	"github.com/docker/docker/image"
18 18
 	"github.com/docker/docker/layer"
19 19
 	"github.com/docker/docker/pkg/ioutils"
20
+	"github.com/docker/docker/pkg/system"
20 21
 	"github.com/pkg/errors"
21 22
 )
22 23
 
... ...
@@ -149,6 +150,9 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
149 149
 		daemon.containerPause(container)
150 150
 		defer daemon.containerUnpause(container)
151 151
 	}
152
+	if !system.IsOSSupported(container.OS) {
153
+		return "", system.ErrNotSupportedOperatingSystem
154
+	}
152 155
 
153 156
 	if c.MergeConfigs && c.Config == nil {
154 157
 		c.Config = container.Config
... ...
@@ -251,6 +255,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
251 251
 }
252 252
 
253 253
 func (daemon *Daemon) exportContainerRw(container *container.Container) (arch io.ReadCloser, err error) {
254
+	// Note: Indexing by OS is safe as only called from `Commit` which has already performed validation
254 255
 	rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
255 256
 	if err != nil {
256 257
 		return nil, err
... ...
@@ -270,6 +270,8 @@ func (daemon *Daemon) setRWLayer(container *container.Container) error {
270 270
 		StorageOpt: container.HostConfig.StorageOpt,
271 271
 	}
272 272
 
273
+	// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
274
+	// caller), and guaranteed non-nil
273 275
 	rwLayer, err := daemon.layerStores[container.OS].CreateRWLayer(container.ID, layerID, rwLayerOpts)
274 276
 	if err != nil {
275 277
 		return err
... ...
@@ -155,7 +155,10 @@ func (daemon *Daemon) restore() error {
155 155
 			logrus.Errorf("Failed to load container %v: %v", id, err)
156 156
 			continue
157 157
 		}
158
-
158
+		if !system.IsOSSupported(container.OS) {
159
+			logrus.Errorf("Failed to load container %v: %s (%q)", id, system.ErrNotSupportedOperatingSystem, container.OS)
160
+			continue
161
+		}
159 162
 		// Ignore the container if it does not support the current driver being used by the graph
160 163
 		currentDriverForContainerOS := daemon.graphDrivers[container.OS]
161 164
 		if (container.Driver == "" && currentDriverForContainerOS == "aufs") || container.Driver == currentDriverForContainerOS {
... ...
@@ -94,6 +94,9 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
94 94
 			return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err)
95 95
 		}
96 96
 	}
97
+	if !system.IsOSSupported(container.OS) {
98
+		return fmt.Errorf("cannot remove %s: %s ", container.ID, system.ErrNotSupportedOperatingSystem)
99
+	}
97 100
 
98 101
 	// stop collection of stats for the container regardless
99 102
 	// if stats are currently getting collected.
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"github.com/docker/docker/errdefs"
10 10
 	"github.com/docker/docker/pkg/archive"
11 11
 	"github.com/docker/docker/pkg/ioutils"
12
+	"github.com/docker/docker/pkg/system"
12 13
 )
13 14
 
14 15
 // ContainerExport writes the contents of the container to the given
... ...
@@ -47,6 +48,9 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
47 47
 }
48 48
 
49 49
 func (daemon *Daemon) containerExport(container *container.Container) (arch io.ReadCloser, err error) {
50
+	if !system.IsOSSupported(container.OS) {
51
+		return nil, fmt.Errorf("cannot export %s: %s ", container.ID, system.ErrNotSupportedOperatingSystem)
52
+	}
50 53
 	rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
51 54
 	if err != nil {
52 55
 		return nil, err
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	"github.com/docker/docker/errdefs"
12 12
 	"github.com/docker/docker/image"
13 13
 	"github.com/docker/docker/pkg/stringid"
14
+	"github.com/docker/docker/pkg/system"
14 15
 	"github.com/pkg/errors"
15 16
 )
16 17
 
... ...
@@ -66,10 +67,13 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
66 66
 	start := time.Now()
67 67
 	records := []types.ImageDeleteResponseItem{}
68 68
 
69
-	imgID, _, err := daemon.GetImageIDAndOS(imageRef)
69
+	imgID, operatingSystem, err := daemon.GetImageIDAndOS(imageRef)
70 70
 	if err != nil {
71 71
 		return nil, err
72 72
 	}
73
+	if !system.IsOSSupported(operatingSystem) {
74
+		return nil, errors.Errorf("unable to delete image: %q", system.ErrNotSupportedOperatingSystem)
75
+	}
73 76
 
74 77
 	repoRefs := daemon.referenceStore.References(imgID.Digest())
75 78
 
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"github.com/docker/distribution/reference"
7 7
 	"github.com/docker/docker/api/types"
8 8
 	"github.com/docker/docker/layer"
9
+	"github.com/docker/docker/pkg/system"
9 10
 	"github.com/pkg/errors"
10 11
 )
11 12
 
... ...
@@ -16,7 +17,9 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
16 16
 	if err != nil {
17 17
 		return nil, errors.Wrapf(err, "no such image: %s", name)
18 18
 	}
19
-
19
+	if !system.IsOSSupported(img.OperatingSystem()) {
20
+		return nil, system.ErrNotSupportedOperatingSystem
21
+	}
20 22
 	refs := daemon.referenceStore.References(img.ID().Digest())
21 23
 	repoTags := []string{}
22 24
 	repoDigests := []string{}
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/docker/docker/container"
15 15
 	"github.com/docker/docker/image"
16 16
 	"github.com/docker/docker/layer"
17
+	"github.com/docker/docker/pkg/system"
17 18
 )
18 19
 
19 20
 var acceptedImageFilterTags = map[string]bool{
... ...
@@ -113,6 +114,13 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
113 113
 			}
114 114
 		}
115 115
 
116
+		// Skip any images with an unsupported operating system to avoid a potential
117
+		// panic when indexing through the layerstore. Don't error as we want to list
118
+		// the other images. This should never happen, but here as a safety precaution.
119
+		if !system.IsOSSupported(img.OperatingSystem()) {
120
+			continue
121
+		}
122
+
116 123
 		layerID := img.RootFS.ChainID()
117 124
 		var size int64
118 125
 		if layerID != "" {
... ...
@@ -138,6 +138,9 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
138 138
 	max := len(img.RootFS.DiffIDs)
139 139
 	for i := 1; i <= max; i++ {
140 140
 		img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
141
+		if !system.IsOSSupported(img.OperatingSystem()) {
142
+			return nil, fmt.Errorf("cannot get layerpath for ImageID %s: %s ", img.RootFS.ChainID(), system.ErrNotSupportedOperatingSystem)
143
+		}
141 144
 		layerPath, err := layer.GetLayerPath(daemon.layerStores[img.OperatingSystem()], img.RootFS.ChainID())
142 145
 		if err != nil {
143 146
 			return nil, fmt.Errorf("failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStores[img.OperatingSystem()], img.RootFS.ChainID(), err)
... ...
@@ -158,6 +158,9 @@ func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, strin
158 158
 	if os == "" {
159 159
 		os = runtime.GOOS
160 160
 	}
161
+	if !system.IsOSSupported(os) {
162
+		return nil, "", system.ErrNotSupportedOperatingSystem
163
+	}
161 164
 	return unmarshalledConfig.RootFS, os, nil
162 165
 }
163 166
 
... ...
@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/docker/docker/pkg/ioutils"
15 15
 	"github.com/docker/docker/pkg/progress"
16 16
 	"github.com/docker/docker/pkg/stringid"
17
+	"github.com/docker/docker/pkg/system"
17 18
 	"github.com/docker/docker/registry"
18 19
 	"github.com/opencontainers/go-digest"
19 20
 	"github.com/sirupsen/logrus"
... ...
@@ -210,6 +211,9 @@ func (p *v1Pusher) imageListForTag(imgID image.ID, dependenciesSeen map[layer.Ch
210 210
 
211 211
 	topLayerID := img.RootFS.ChainID()
212 212
 
213
+	if !system.IsOSSupported(img.OperatingSystem()) {
214
+		return nil, system.ErrNotSupportedOperatingSystem
215
+	}
213 216
 	pl, err := p.config.LayerStores[img.OperatingSystem()].Get(topLayerID)
214 217
 	*referencedLayers = append(*referencedLayers, pl)
215 218
 	if err != nil {
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/docker/docker/pkg/archive"
14 14
 	"github.com/docker/docker/pkg/ioutils"
15 15
 	"github.com/docker/docker/pkg/progress"
16
+	"github.com/docker/docker/pkg/system"
16 17
 	"github.com/sirupsen/logrus"
17 18
 	"golang.org/x/net/context"
18 19
 )
... ...
@@ -105,10 +106,14 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
105 105
 		downloadsByKey = make(map[string]*downloadTransfer)
106 106
 	)
107 107
 
108
-	// Assume that the operating system is the host OS if blank
108
+	// Assume that the operating system is the host OS if blank, and validate it
109
+	// to ensure we don't cause a panic by an invalid index into the layerstores.
109 110
 	if os == "" {
110 111
 		os = runtime.GOOS
111 112
 	}
113
+	if !system.IsOSSupported(os) {
114
+		return image.RootFS{}, nil, system.ErrNotSupportedOperatingSystem
115
+	}
112 116
 
113 117
 	rootFS := initialRootFS
114 118
 	for _, descriptor := range layers {
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	"github.com/docker/distribution/digestset"
10 10
 	"github.com/docker/docker/layer"
11
+	"github.com/docker/docker/pkg/system"
11 12
 	"github.com/opencontainers/go-digest"
12 13
 	"github.com/pkg/errors"
13 14
 	"github.com/sirupsen/logrus"
... ...
@@ -73,6 +74,9 @@ func (is *store) restore() error {
73 73
 		}
74 74
 		var l layer.Layer
75 75
 		if chainID := img.RootFS.ChainID(); chainID != "" {
76
+			if !system.IsOSSupported(img.OperatingSystem()) {
77
+				return system.ErrNotSupportedOperatingSystem
78
+			}
76 79
 			l, err = is.lss[img.OperatingSystem()].Get(chainID)
77 80
 			if err != nil {
78 81
 				return err
... ...
@@ -148,6 +152,9 @@ func (is *store) Create(config []byte) (ID, error) {
148 148
 
149 149
 	var l layer.Layer
150 150
 	if layerID != "" {
151
+		if !system.IsOSSupported(img.OperatingSystem()) {
152
+			return "", system.ErrNotSupportedOperatingSystem
153
+		}
151 154
 		l, err = is.lss[img.OperatingSystem()].Get(layerID)
152 155
 		if err != nil {
153 156
 			return "", errors.Wrapf(err, "failed to get layer %s", layerID)
... ...
@@ -4,12 +4,12 @@ package layer
4 4
 
5 5
 import "runtime"
6 6
 
7
-// SetOS writes the "os" file to the layer filestore
8
-func (fm *fileMetadataTransaction) SetOS(os string) error {
7
+// setOS writes the "os" file to the layer filestore
8
+func (fm *fileMetadataTransaction) setOS(os string) error {
9 9
 	return nil
10 10
 }
11 11
 
12
-// GetOS reads the "os" file from the layer filestore
13
-func (fms *fileMetadataStore) GetOS(layer ChainID) (string, error) {
12
+// getOS reads the "os" file from the layer filestore
13
+func (fms *fileMetadataStore) getOS(layer ChainID) (string, error) {
14 14
 	return runtime.GOOS, nil
15 15
 }
... ...
@@ -7,16 +7,16 @@ import (
7 7
 	"strings"
8 8
 )
9 9
 
10
-// SetOS writes the "os" file to the layer filestore
11
-func (fm *fileMetadataTransaction) SetOS(os string) error {
10
+// setOS writes the "os" file to the layer filestore
11
+func (fm *fileMetadataTransaction) setOS(os string) error {
12 12
 	if os == "" {
13 13
 		return nil
14 14
 	}
15 15
 	return fm.ws.WriteFile("os", []byte(os), 0644)
16 16
 }
17 17
 
18
-// GetOS reads the "os" file from the layer filestore
19
-func (fms *fileMetadataStore) GetOS(layer ChainID) (string, error) {
18
+// getOS reads the "os" file from the layer filestore
19
+func (fms *fileMetadataStore) getOS(layer ChainID) (string, error) {
20 20
 	contentBytes, err := ioutil.ReadFile(fms.getLayerFilename(layer, "os"))
21 21
 	if err != nil {
22 22
 		// For backwards compatibility, the os file may not exist. Default to "windows" if missing.
... ...
@@ -216,7 +216,7 @@ type MetadataTransaction interface {
216 216
 	SetDiffID(DiffID) error
217 217
 	SetCacheID(string) error
218 218
 	SetDescriptor(distribution.Descriptor) error
219
-	SetOS(string) error
219
+	setOS(string) error
220 220
 	TarSplitWriter(compressInput bool) (io.WriteCloser, error)
221 221
 
222 222
 	Commit(ChainID) error
... ...
@@ -237,7 +237,7 @@ type MetadataStore interface {
237 237
 	GetDiffID(ChainID) (DiffID, error)
238 238
 	GetCacheID(ChainID) (string, error)
239 239
 	GetDescriptor(ChainID) (distribution.Descriptor, error)
240
-	GetOS(ChainID) (string, error)
240
+	getOS(ChainID) (string, error)
241 241
 	TarSplitReader(ChainID) (io.ReadCloser, error)
242 242
 
243 243
 	SetMountID(string, string) error
... ...
@@ -150,7 +150,7 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
150 150
 		return nil, fmt.Errorf("failed to get descriptor for %s: %s", layer, err)
151 151
 	}
152 152
 
153
-	os, err := ls.store.GetOS(layer)
153
+	os, err := ls.store.getOS(layer)
154 154
 	if err != nil {
155 155
 		return nil, fmt.Errorf("failed to get operating system for %s: %s", layer, err)
156 156
 	}
... ...
@@ -146,7 +146,7 @@ func storeLayer(tx MetadataTransaction, layer *roLayer) error {
146 146
 			return err
147 147
 		}
148 148
 	}
149
-	if err := tx.SetOS(layer.layerStore.os); err != nil {
149
+	if err := tx.setOS(layer.layerStore.os); err != nil {
150 150
 		return err
151 151
 	}
152 152
 
... ...
@@ -7,4 +7,7 @@ import (
7 7
 var (
8 8
 	// ErrNotSupportedPlatform means the platform is not supported.
9 9
 	ErrNotSupportedPlatform = errors.New("platform and architecture is not supported")
10
+
11
+	// ErrNotSupportedOperatingSystem means the operating system is not supported.
12
+	ErrNotSupportedOperatingSystem = errors.New("operating system is not supported")
10 13
 )
... ...
@@ -62,7 +62,7 @@ func IsOSSupported(os string) bool {
62 62
 	if runtime.GOOS == os {
63 63
 		return true
64 64
 	}
65
-	if LCOWSupported() && runtime.GOOS == "windows" && os == "linux" {
65
+	if LCOWSupported() && os == "linux" {
66 66
 		return true
67 67
 	}
68 68
 	return false