Skip to content

Commit 2abf0e6

Browse files
committed
EXECUTE ORDER #666
Aleksa Sarai (1): layer: reject empty whiteout name '.wh.' LGTMs: cyphar
2 parents 702d842 + 635306a commit 2abf0e6

File tree

3 files changed

+32
-17
lines changed

3 files changed

+32
-17
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2121
was a violation of the policy that user-configured data should always take
2222
priority. Umoci will now only add the auto-generated `HOME` environment
2323
variable if no such variable was configured in `Config.Env`. (#652)
24+
* When encountering an invalid whiteout (specifically, one with the name
25+
`.wh.`), `umoci unpack` will now return an error. Previously such whiteouts
26+
were incorrectly treated as though they were opaque whiteouts.
2427

2528
### Changed ###
2629
* `github.com/vbatts/go-mtree` has merged our patches to improve the strictness

oci/layer/tar_extract.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,8 @@ func (te *TarExtractor) mkdirAll(root, subpath string, mode os.FileMode) error {
552552
return nil
553553
}
554554

555+
var errInvalidWhiteout = errors.New("invalid whiteout")
556+
555557
// UnpackEntry extracts the given tar.Header to the provided root, ensuring
556558
// that the layer state is consistent with the layer state that produced the
557559
// tar archive being iterated over. This does handle whiteouts, so a tar.Header
@@ -681,7 +683,11 @@ func (te *TarExtractor) UnpackEntry(root string, hdr *tar.Header, r io.Reader) (
681683
// Typeflag, expecting that the path is the only thing that matters in a
682684
// whiteout entry.
683685
if woFile, isWhiteout := strings.CutPrefix(file, whPrefix); isWhiteout {
686+
if woFile == "" {
687+
return fmt.Errorf("%w with empty name: %s", errInvalidWhiteout, path)
688+
}
684689
if file == whOpaque {
690+
// special value to indicate opaque whiteout
685691
woFile = ""
686692
}
687693
switch onDiskFmt := te.onDiskFmt.(type) {

oci/layer/tar_extract_test.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -212,18 +212,21 @@ func TestUnpackEntryParentDir(t *testing.T) {
212212
// as well as ensuring that the metadata of the parent is maintained.
213213
func TestUnpackEntryWhiteout(t *testing.T) {
214214
for _, test := range []struct {
215-
name string
216-
path string
217-
dir bool // TODO: Switch to Typeflag
215+
name string
216+
path string
217+
dir bool // TODO: Switch to Typeflag
218+
expectedErr error
218219
}{
219-
{"FileInRoot", "rootpath", false},
220-
{"HiddenFileInRoot", ".hiddenroot", false},
221-
{"FileInSubdir", "some/path/file", false},
222-
{"HiddenFileInSubdir", "another/path/.hiddenfile", false},
223-
{"DirInRoot", "rootpath", true},
224-
{"HiddenDirInRoot", ".hiddenroot", true},
225-
{"DirInSubdir", "some/path/dir", true},
226-
{"HiddenDirInSubdir", "another/path/.hiddendir", true},
220+
{"EmptyWhiteoutName-Root", "", false, errInvalidWhiteout},
221+
{"EmptyWhiteoutName", "some/path/", false, errInvalidWhiteout},
222+
{"FileInRoot", "rootpath", false, nil},
223+
{"HiddenFileInRoot", ".hiddenroot", false, nil},
224+
{"FileInSubdir", "some/path/file", false, nil},
225+
{"HiddenFileInSubdir", "another/path/.hiddenfile", false, nil},
226+
{"DirInRoot", "rootpath", true, nil},
227+
{"HiddenDirInRoot", ".hiddenroot", true, nil},
228+
{"DirInSubdir", "some/path/dir", true, nil},
229+
{"HiddenDirInSubdir", "another/path/.hiddendir", true, nil},
227230
} {
228231
t.Run(test.name, func(t *testing.T) {
229232
testMtime := testhelpers.Unix(123, 456)
@@ -255,7 +258,7 @@ func TestUnpackEntryWhiteout(t *testing.T) {
255258

256259
err = os.WriteFile(filepath.Join(dir, test.path, ".subdir", "file3"), []byte("some value"), 0o644)
257260
require.NoError(t, err)
258-
} else {
261+
} else if rawFile != "" {
259262
err := os.WriteFile(filepath.Join(dir, test.path), []byte("some value"), 0o644)
260263
require.NoError(t, err)
261264
}
@@ -272,11 +275,14 @@ func TestUnpackEntryWhiteout(t *testing.T) {
272275

273276
te := NewTarExtractor(nil)
274277
err = te.UnpackEntry(dir, hdr, nil)
275-
require.NoErrorf(t, err, "UnpackEntry %s whiteout", hdr.Name)
276-
277-
// Make sure that the path is gone.
278-
_, err = os.Lstat(filepath.Join(dir, test.path))
279-
assert.ErrorIs(t, err, os.ErrNotExist, "whiteout should have removed path") //nolint:testifylint // assert.*Error* makes more sense
278+
if test.expectedErr != nil {
279+
assert.ErrorIsf(t, err, test.expectedErr, "UnpackEntry %q whiteout should fail with expected err", hdr.Name) //nolint:testifylint // assert.*Error* makes more sense
280+
} else {
281+
require.NoErrorf(t, err, "UnpackEntry %q whiteout", hdr.Name)
282+
// Make sure that the path is gone.
283+
_, err = os.Lstat(filepath.Join(dir, test.path))
284+
assert.ErrorIs(t, err, os.ErrNotExist, "whiteout should have removed path") //nolint:testifylint // assert.*Error* makes more sense
285+
}
280286

281287
// Make sure the parent directory wasn't modified.
282288
fi, err := os.Lstat(filepath.Join(dir, rawDir))

0 commit comments

Comments
 (0)