diff --git a/pkg/archive/tar_unix.go b/pkg/archive/tar_unix.go index 684ea5783d950..59ee39ecb1490 100644 --- a/pkg/archive/tar_unix.go +++ b/pkg/archive/tar_unix.go @@ -22,6 +22,7 @@ import ( "archive/tar" "errors" "fmt" + "math" "os" "runtime" "strings" @@ -121,6 +122,16 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error { mode |= unix.S_IFIFO } + // Devmajor and Devminor come straight from the (untrusted) tar header as + // int64, but Mkdev only takes uint32. Casting a value that does not fit + // silently truncates it, so the node created on disk would carry a + // different major/minor than the header declares. Reject those instead of + // creating a mismatched device. + if hdr.Devmajor < 0 || hdr.Devmajor > math.MaxUint32 || + hdr.Devminor < 0 || hdr.Devminor > math.MaxUint32 { + return fmt.Errorf("device number %d:%d for %q out of range: %w", hdr.Devmajor, hdr.Devminor, hdr.Name, errInvalidArchive) + } + return mknod(path, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor))) } diff --git a/pkg/archive/tar_unix_test.go b/pkg/archive/tar_unix_test.go new file mode 100644 index 0000000000000..682543cd5ffea --- /dev/null +++ b/pkg/archive/tar_unix_test.go @@ -0,0 +1,52 @@ +//go:build !windows + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package archive + +import ( + "archive/tar" + "errors" + "math" + "path/filepath" + "testing" +) + +func TestHandleTarTypeBlockCharFifoDeviceRange(t *testing.T) { + for _, tc := range []struct { + name string + devmajor int64 + devminor int64 + }{ + {"major above uint32", math.MaxUint32 + 1, 0}, + {"minor above uint32", 0, math.MaxUint32 + 1}, + {"negative major", -1, 0}, + {"negative minor", 0, -1}, + } { + t.Run(tc.name, func(t *testing.T) { + hdr := &tar.Header{ + Typeflag: tar.TypeBlock, + Devmajor: tc.devmajor, + Devminor: tc.devminor, + } + err := handleTarTypeBlockCharFifo(hdr, filepath.Join(t.TempDir(), "dev")) + if !errors.Is(err, errInvalidArchive) { + t.Fatalf("expected errInvalidArchive for %d:%d, got %v", tc.devmajor, tc.devminor, err) + } + }) + } +} diff --git a/plugins/diff/windows/cimfs.go b/plugins/diff/windows/cimfs.go index 321273a70f194..0274a32ca8850 100644 --- a/plugins/diff/windows/cimfs.go +++ b/plugins/diff/windows/cimfs.go @@ -72,8 +72,8 @@ func init() { plugins.MetadataPlugin, }, InitFn: func(ic *plugin.InitContext) (any, error) { - if !cimfs.IsBlockCimSupported() { - return nil, fmt.Errorf("host OS version doesn't support block CIMs: %w", plugin.ErrSkipPlugin) + if !cimfs.IsBlockCimWriteSupported() { + return nil, fmt.Errorf("host OS doesn't support writable block CIMs: %w", plugin.ErrSkipPlugin) } md, err := ic.GetSingle(plugins.MetadataPlugin) diff --git a/plugins/snapshots/windows/block_cimfs.go b/plugins/snapshots/windows/block_cimfs.go index c249642fb4f26..69d3ad1647b3b 100644 --- a/plugins/snapshots/windows/block_cimfs.go +++ b/plugins/snapshots/windows/block_cimfs.go @@ -96,8 +96,8 @@ func init() { } func NewBlockCIMSnapshotter(root string, config *BlockCIMSnapshotterConfig) (snapshots.Snapshotter, error) { - if !cimfs.IsBlockCimSupported() { - return nil, fmt.Errorf("host windows version doesn't support block CIMs: %w", plugin.ErrSkipPlugin) + if !cimfs.IsBlockCimWriteSupported() { + return nil, fmt.Errorf("host OS doesn't support writable block CIMs: %w", plugin.ErrSkipPlugin) } baseSn, err := newBaseSnapshotter(root) diff --git a/plugins/snapshots/windows/cimfs.go b/plugins/snapshots/windows/cimfs.go index 436048eff71ab..222d9d95df076 100644 --- a/plugins/snapshots/windows/cimfs.go +++ b/plugins/snapshots/windows/cimfs.go @@ -83,7 +83,7 @@ func WithSize(size uint64) scratchCreationOpt { // defaultScratchCreationOptions returns the default options for scratch VHD creation func defaultScratchCreationOptions() *scratchCreationOptions { return &scratchCreationOptions{ - ntfsFormat: true, + ntfsFormat: false, sizeInBytes: defaultScratchVHDSizeInBytes, } } @@ -420,7 +420,7 @@ func createDifferencingScratchVHDs(ctx context.Context, path string) (err error) }() if !baseVHDExists { - if err = createScratchVHD(ctx, baseVHDPath); err != nil { + if err = createScratchVHD(ctx, baseVHDPath, WithNTFSFormat()); err != nil { return fmt.Errorf("failed to create base vhd: %w", err) } }