From 675d6905b2192a3a41ca58b921dddc97ddf88c2c Mon Sep 17 00:00:00 2001 From: Rajitha Date: Fri, 14 Aug 2020 12:10:44 -0400 Subject: [PATCH 1/2] dcm4che(issue #159) #164 Prevent read of tag beyond specified length. Toolkit detect child tags with length > the containing item length and stop trying to parse the sequence item. --- .../src/main/java/org/dcm4che3/io/DicomInputStream.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java b/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java index 3f9f380aba..6912a8368d 100644 --- a/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java +++ b/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java @@ -477,6 +477,12 @@ public void readAttributes(Attributes attrs, int len, int stopTag) break; throw e; } + // dcm4che3#159 - Skip child tags which exceed maximum specified len. + if (!undeflen && (pos + length) > endPos){ + LOG.warn("Tag {} with length of {} exceeds specified len of {}. Skipping.", TagUtils.toString(tag), length, len); + skip(endPos - pos); + break; + } if (hasStopTag && tag == stopTag) break; if (vr != null) { From de1dec922b878d6a9b31966d08407edebc1721ad Mon Sep 17 00:00:00 2001 From: Rajitha Date: Wed, 19 Aug 2020 17:13:41 -0400 Subject: [PATCH 2/2] dcm4che(issue #159) back port --- .../org/dcm4che3/io/DicomInputStream.java | 69 +++++++++++++++++-- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java b/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java index 6912a8368d..dbf27576d4 100644 --- a/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java +++ b/dcm4che-core/src/main/java/org/dcm4che3/io/DicomInputStream.java @@ -47,6 +47,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; +import java.io.PushbackInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -115,6 +116,7 @@ public enum IncludeBulkData { NO, YES, URI } protected long markPos; protected int tag; protected VR vr; + private int encodedVR; protected int length; protected DicomInputHandler handler = this; protected BulkDataDescriptor bulkDataDescriptor = BulkDataDescriptor.DEFAULT; @@ -387,6 +389,7 @@ public int readHeader() throws IOException { byte[] buf = buffer; tagPos = pos; readFully(buf, 0, 8); + encodedVR = 0; switch(tag = ByteUtils.bytesToTag(buf, 0, bigEndian)) { case Tag.Item: case Tag.ItemDelimitationItem: @@ -395,7 +398,7 @@ public int readHeader() throws IOException { break; default: if (explicitVR) { - vr = VR.valueOf(ByteUtils.bytesToVR(buf, 4)); + vr = VR.valueOf(encodedVR = ByteUtils.bytesToVR(buf, 4)); if (vr.headerLength() == 8) { length = ByteUtils.bytesToUShort(buf, 6, bigEndian); return tag; @@ -477,12 +480,6 @@ public void readAttributes(Attributes attrs, int len, int stopTag) break; throw e; } - // dcm4che3#159 - Skip child tags which exceed maximum specified len. - if (!undeflen && (pos + length) > endPos){ - LOG.warn("Tag {} with length of {} exceeds specified len of {}. Skipping.", TagUtils.toString(tag), length, len); - skip(endPos - pos); - break; - } if (hasStopTag && tag == stopTag) break; if (vr != null) { @@ -648,6 +645,13 @@ protected void readSequence(int len, Attributes attrs, int sqtag) String privateCreator = attrs.getPrivateCreator(sqtag); boolean undefLen = len == -1; long endPos = pos + (len & 0xffffffffL); + boolean explicitVR0 = explicitVR; + boolean bigEndian0 = bigEndian; + if (encodedVR == 0x554e // UN + && !probeExplicitVR()) { + explicitVR = false; + bigEndian = false; + } for (int i = 0; undefLen || pos < endPos; ++i) { readHeader(); if (tag == Tag.Item) { @@ -659,11 +663,62 @@ protected void readSequence(int len, Attributes attrs, int sqtag) } else skipAttribute(UNEXPECTED_ATTRIBUTE); } + explicitVR = explicitVR0; + bigEndian = bigEndian0; if (seq.isEmpty()) attrs.setNull(sqtag, VR.SQ); else seq.trimToSize(); } + + private boolean probeExplicitVR() throws IOException { + byte[] buf = new byte[14]; + if (in.markSupported()) { + in.mark(14); + in.read(buf); + in.reset(); + } else { + if (!(in instanceof PushbackInputStream)) + in = new PushbackInputStream(in, 14); + int len = in.read(buf); + ((PushbackInputStream) in).unread(buf, 0, len); + } + switch (ByteUtils.bytesToVR(buf, 12)) { + case 0x4145: // AE + case 0x4153: // AS + case 0x4154: // AT + case 0x4353: // CS + case 0x4441: // DA + case 0x4453: // DS + case 0x4454: // DT + case 0x4644: // FD + case 0x464c: // FL + case 0x4953: // IS + case 0x4c4f: // LO + case 0x4c54: // LT + case 0x4f42: // OB + case 0x4f44: // OD + case 0x4f46: // OF + case 0x4f4c: // OL + case 0x4f57: // OW + case 0x504e: // PN + case 0x5348: // SH + case 0x534c: // SL + case 0x5351: // SQ + case 0x5353: // SS + case 0x5354: // ST + case 0x544d: // TM + case 0x5543: // UC + case 0x5549: // UI + case 0x554c: // UL + case 0x554e: // UN + case 0x5552: // UR + case 0x5553: // US + case 0x5554: // UT + return true; + } + return false; + } public Attributes readItem() throws IOException { readHeader();