Skip to content

Commit c3ca57f

Browse files
frostmarhdonnay
authored andcommitted
jar: skip corrupt jar file
Signed-off-by: Mark Frost <frostmar@uk.ibm.com> Signed-off-by: Hank Donnay <hdonnay@redhat.com>
1 parent bbeefdd commit c3ca57f

3 files changed

Lines changed: 116 additions & 6 deletions

File tree

java/jar/jar.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ func Parse(ctx context.Context, name string, z *zip.Reader) ([]Info, error) {
9090
goto Finish
9191
case errors.Is(err, errUnpopulated):
9292
case strings.HasPrefix(base, "javax") && errors.Is(err, ErrNotAJar):
93+
case errors.Is(err, ErrNotAJar):
94+
return nil, err
9395
default:
9496
return nil, mkErr(name, err)
9597
}
@@ -103,6 +105,8 @@ func Parse(ctx context.Context, name string, z *zip.Reader) ([]Info, error) {
103105
goto Finish
104106
case errors.Is(err, errUnpopulated) || errors.Is(err, errInsaneManifest):
105107
case strings.HasPrefix(base, "javax") && errors.Is(err, ErrNotAJar):
108+
case errors.Is(err, ErrNotAJar):
109+
return nil, err
106110
default:
107111
return nil, mkErr(name, err)
108112
}
@@ -146,7 +150,7 @@ func extractManifest(ctx context.Context, name string, z *zip.Reader) (Info, err
146150
mf, err := z.Open(manifestPath)
147151
switch {
148152
case errors.Is(err, nil):
149-
case errors.Is(err, fs.ErrNotExist):
153+
case errors.Is(err, fs.ErrNotExist), errors.Is(err, zip.ErrFormat):
150154
return Info{}, mkErr("manifest", notAJar(name, err))
151155
default:
152156
return Info{}, err
@@ -165,10 +169,13 @@ func extractManifest(ctx context.Context, name string, z *zip.Reader) (Info, err
165169
func extractProperties(ctx context.Context, name string, z *zip.Reader) ([]Info, error) {
166170
const filename = "pom.properties"
167171
mf, err := z.Open(`META-INF`)
168-
if err != nil {
169-
if errors.Is(err, fs.ErrNotExist) {
170-
return nil, mkErr("properties", notAJar(name, err))
171-
}
172+
switch {
173+
case errors.Is(err, nil):
174+
case errors.Is(err, fs.ErrNotExist),
175+
errors.Is(err, zip.ErrFormat),
176+
errors.Is(err, zip.ErrChecksum):
177+
return nil, mkErr("properties", notAJar(name, err))
178+
default:
172179
return nil, mkErr("properties", err)
173180
}
174181
mf.Close()
@@ -193,7 +200,11 @@ func extractProperties(ctx context.Context, name string, z *zip.Reader) ([]Info,
193200
ret := make([]Info, len(pf))
194201
for i, p := range pf {
195202
f, err := z.Open(p)
196-
if err != nil {
203+
switch {
204+
case errors.Is(err, nil):
205+
case errors.Is(err, zip.ErrFormat), errors.Is(err, zip.ErrChecksum):
206+
return nil, mkErr("properties", notAJar(name, err))
207+
default:
197208
return nil, err
198209
}
199210
err = ret[i].parseProperties(ctx, f)

java/jar/jar_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,100 @@ func TestJARBadManifest(t *testing.T) {
259259
}
260260
}
261261

262+
// TestMalformed creates a malformed zip, then makes sure the package handles it
263+
// gracefully.
264+
func TestMalformed(t *testing.T) {
265+
const (
266+
jarName = `malformed_zip.jar`
267+
manifest = `testdata/malformed_zip.MF`
268+
)
269+
t.Parallel()
270+
ctx := zlog.Test(context.Background(), t)
271+
dir := integration.PackageCacheDir(t)
272+
fn := filepath.Join(dir, jarName)
273+
Open:
274+
f, err := os.Open(fn)
275+
switch {
276+
case errors.Is(err, nil):
277+
case errors.Is(err, os.ErrNotExist):
278+
// Create the jar-like.
279+
mk, err := os.Create(fn)
280+
if err != nil {
281+
t.Fatal(err)
282+
}
283+
defer func() {
284+
if err := mk.Close(); err != nil {
285+
t.Logf("non-failing error: %v", err)
286+
}
287+
if t.Failed() {
288+
if err := os.Remove(fn); err != nil {
289+
t.Error(err)
290+
}
291+
}
292+
}()
293+
w := zip.NewWriter(mk)
294+
if _, err := w.Create(`META-INF/`); err != nil {
295+
t.Fatal(err)
296+
}
297+
fw, err := w.Create(`META-INF/MANIFEST.MF`)
298+
if err != nil {
299+
t.Fatal(err)
300+
}
301+
mf, err := os.ReadFile(manifest)
302+
if err != nil {
303+
t.Fatal(err)
304+
}
305+
if _, err := io.Copy(fw, bytes.NewReader(mf)); err != nil {
306+
t.Fatal(err)
307+
}
308+
if err := w.Close(); err != nil {
309+
t.Fatal(err)
310+
}
311+
312+
// Then, corrupt it.
313+
// Seek to the central directory footer:
314+
pos, err := mk.Seek(-0x16+0x10 /* sizeof(footer) + offset(dir_offset)*/, io.SeekEnd)
315+
if err != nil {
316+
t.Fatal(err)
317+
}
318+
b := make([]byte, 4)
319+
if _, err := io.ReadFull(mk, b); err != nil {
320+
t.Fatal(err)
321+
}
322+
// Offset everything so the reader slowly descends into madness.
323+
b[0] -= 7
324+
if _, err := mk.WriteAt(b, pos); err != nil {
325+
t.Fatal(err)
326+
}
327+
328+
if err := mk.Sync(); err != nil {
329+
t.Error(err)
330+
}
331+
goto Open
332+
default:
333+
t.Fatal(err)
334+
}
335+
defer f.Close()
336+
fi, err := f.Stat()
337+
if err != nil {
338+
t.Fatal(err)
339+
}
340+
z, err := zip.NewReader(f, fi.Size())
341+
if err != nil {
342+
t.Fatal(err)
343+
}
344+
infos, err := Parse(ctx, jarName, z)
345+
t.Logf("returned error: %v", err)
346+
switch {
347+
case errors.Is(err, ErrNotAJar):
348+
default:
349+
t.Fail()
350+
}
351+
if len(infos) != 0 {
352+
t.Errorf("returned infos: %#v", infos)
353+
}
354+
}
355+
262356
func TestManifestSectionReader(t *testing.T) {
263357
var ms []string
264358
d := os.DirFS("testdata")

java/jar/testdata/malformed_zip.MF

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Manifest-Version: 1.0
2+
Created-By: 666 (claircore testing)
3+
4+
Name: foo
5+
Other-Key: blah

0 commit comments

Comments
 (0)