Skip to content

Commit

Permalink
Additional zip-slip tests (#1162)
Browse files Browse the repository at this point in the history
* Additional zip-slip tests

* Fix windows path test
  • Loading branch information
dotasek committed Mar 9, 2023
1 parent f49eee6 commit 909f7e6
Show file tree
Hide file tree
Showing 34 changed files with 576 additions and 732 deletions.
Expand Up @@ -471,9 +471,13 @@ public void loadFromFile(String file, IContextResourceLoader loader) throws IOEx

private void loadFromStream(InputStream stream, IContextResourceLoader loader) throws IOException, FHIRException {
ZipInputStream zip = new ZipInputStream(stream);
ZipEntry ze;
while ((ze = zip.getNextEntry()) != null) {
loadDefinitionItem(ze.getName(), zip, loader, null, null);
ZipEntry zipEntry;
while ((zipEntry = zip.getNextEntry()) != null) {
String entryName = zipEntry.getName();
if (entryName.contains("..")) {
throw new RuntimeException("Entry with an illegal path: " + entryName);
}
loadDefinitionItem(entryName, zip, loader, null, null);
zip.closeEntry();
}
zip.close();
Expand Down
Expand Up @@ -37,6 +37,8 @@
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;

import javax.annotation.Nonnull;

public class QuestionnaireRenderer extends TerminologyRenderer {
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";

Expand Down Expand Up @@ -251,28 +253,28 @@ private boolean renderTreeItem(HierarchicalTableGenerator gen, List<Row> rows, Q
Cell flags = gen.new Cell();
r.getCells().add(flags);
if (i.getReadOnly()) {
flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, "Is Readonly").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-readonly.png"))));
flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, "Is Readonly").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-readonly.png"))));
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) {
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-isSubject.html"), null, "Can change the subject of the questionnaire").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-isSubject.html"), null, "Can change the subject of the questionnaire").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-subject.png"))));
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden")) {
flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-hidden.html"), null, "Is a hidden item").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png"))));
flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-hidden.html"), null, "Is a hidden item").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-hidden.png"))));
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay")) {
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-optionalDisplay.html"), null, "Is optional to display").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-optionalDisplay.html"), null, "Is optional to display").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-optional.png"))));
}
if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) {
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), null, "Is linked to an observation").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-observationLinkPeriod.html"), null, "Is linked to an observation").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-observation.png"))));
}
if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation")) {
String code = ToolingExtensions.readStringExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation");
flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-choiceorientation.html"), null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
flags.addPiece(gen.new Piece(getSpecLink("extension-questionnaire-choiceorientation.html"), null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-" + code + ".png"))));
}
if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory")) {
CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory").getValueCodeableConcept();
String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category");
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-displayCategory.html"), null, "Category: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"))));
flags.addPiece(gen.new Piece(getSDCLink("StructureDefinition-sdc-questionnaire-displayCategory.html"), null, "Category: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", getImgPath("icon-qi-" + code + ".png"))));
}
}
Cell defn = gen.new Cell();
Expand Down Expand Up @@ -687,26 +689,26 @@ private boolean renderFormItem(XhtmlNode x, Questionnaire q, QuestionnaireItemCo

if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) {
hasFlag = true;
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject"), "Can change the subject of the questionnaire").img(Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png"), "icon");
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject"), "Can change the subject of the questionnaire").img(getImgPath("icon-qi-subject.png"), "icon");
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden")) {
hasFlag = true;
flags.ah(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), "Is a hidden item").img(Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png"), "icon");
flags.ah(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), "Is a hidden item").img(getImgPath("icon-qi-hidden.png"), "icon");
d.style("background-color: #eeeeee");
}
if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay")) {
hasFlag = true;
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay"), "Is optional to display").img(Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png"), "icon");
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay"), "Is optional to display").img(getImgPath("icon-qi-optional.png"), "icon");
}
if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) {
hasFlag = true;
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod"), "Is linked to an observation").img(Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png"), "icon");
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod"), "Is linked to an observation").img(getImgPath("icon-qi-observation.png"), "icon");
}
if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory")) {
CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory").getValueCodeableConcept();
String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category");
hasFlag = true;
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory"), "Category: "+code).img(Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png"), "icon");
flags.ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory"), "Category: "+code).img(getImgPath("icon-qi-" + code + ".png"), "icon");
}

if (i.hasMaxLength()) {
Expand Down Expand Up @@ -788,6 +790,13 @@ private boolean renderFormItem(XhtmlNode x, Questionnaire q, QuestionnaireItemCo
return hasExt;
}

@Nonnull
private String getImgPath(String code) throws IOException {
return context.getLocalPrefix().length() > 0
? Utilities.path(context.getLocalPrefix(), code)
: Utilities.path(code);
}

private void item(XhtmlNode ul, String name, String value, String valueLink) {
if (!Utilities.noString(value)) {
ul.li().style("font-size: 10px").ah(valueLink).tx(name+": "+value);
Expand Down Expand Up @@ -862,7 +871,7 @@ private boolean renderRootDefinition(XhtmlNode tbl, Questionnaire q, List<Questi
boolean ext = false;
XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent");
td.an(q.getId());
td.img(Utilities.path(context.getLocalPrefix(), "icon_q_root.gif"), "icon");
td.img(getImgPath("icon_q_root.gif"), "icon");
td.tx(" Questionnaire ");
td.b().tx(q.getId());

Expand Down Expand Up @@ -915,10 +924,10 @@ private boolean renderDefinition(XhtmlNode tbl, Questionnaire q, QuestionnaireIt
XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent");
td.an("item."+qi.getLinkId());
for (QuestionnaireItemComponent p : parents) {
td.ah("#item."+p.getLinkId()).img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png"), "icon");
td.ah("#item."+p.getLinkId()).img(getImgPath("icon_q_item.png"), "icon");
td.tx(" > ");
}
td.img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png"), "icon");
td.img(getImgPath("icon_q_item.png"), "icon");
td.tx(" Item ");
td.b().tx(qi.getLinkId());

Expand Down Expand Up @@ -1103,4 +1112,4 @@ private void defn(XhtmlNode tbl, String name, boolean value, boolean ifFalse) {
}
}

}
}
Expand Up @@ -97,17 +97,17 @@ private void fillCache(String source) throws IOException {
public static void unzip(InputStream is, String targetDir) throws IOException {
try (ZipInputStream zipIn = new ZipInputStream(is)) {
for (ZipEntry ze; (ze = zipIn.getNextEntry()) != null; ) {
String path = Path.of(Utilities.path(targetDir, ze.getName())).normalize().toFile().getAbsolutePath();

if (!path.startsWith(targetDir)) {
Path path = Path.of(Utilities.path(targetDir, ze.getName())).normalize();
String pathString = path.toFile().getAbsolutePath();
if (!path.startsWith(Path.of(targetDir).normalize())) {
// see: https://snyk.io/research/zip-slip-vulnerability
throw new RuntimeException("Entry with an illegal path: " + ze.getName());
}
if (ze.isDirectory()) {
Utilities.createDirectory(path);
Utilities.createDirectory(pathString);
} else {
Utilities.createDirectory(Utilities.getDirectoryForFile(path));
TextFile.streamToFileNoClose(zipIn, path);
Utilities.createDirectory(Utilities.getDirectoryForFile(pathString));
TextFile.streamToFileNoClose(zipIn, pathString);
}
}
}
Expand Down
@@ -1,33 +1,33 @@
package org.hl7.fhir.r4b.test.utils;

/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/



Expand Down Expand Up @@ -146,61 +146,6 @@ private void generateSnapshots(String[] args) throws IOException, FHIRException
// }
}

private Map<String, byte[]> getDefinitions(String definitions) throws IOException, FHIRException {
Map<String, byte[]> results = new HashMap<String, byte[]>();
readDefinitions(results, loadDefinitions(definitions));
return results;
}

private void readDefinitions(Map<String, byte[]> map, byte[] defn) throws IOException {
ZipInputStream zip = new ZipInputStream(new ByteArrayInputStream(defn));
ZipEntry ze;
while ((ze = zip.getNextEntry()) != null) {
if (!ze.getName().endsWith(".zip") && !ze.getName().endsWith(".jar") ) { // skip saxon .zip
String name = ze.getName();
InputStream in = zip;
ByteArrayOutputStream b = new ByteArrayOutputStream();
int n;
byte[] buf = new byte[1024];
while ((n = in.read(buf, 0, 1024)) > -1) {
b.write(buf, 0, n);
}
map.put(name, b.toByteArray());
}
zip.closeEntry();
}
zip.close();
}

private byte[] loadDefinitions(String definitions) throws FHIRException, IOException {
byte[] defn;
// if (Utilities.noString(definitions)) {
// defn = loadFromUrl(MASTER_SOURCE);
// } else
if (definitions.startsWith("https:") || definitions.startsWith("http:")) {
defn = loadFromUrl(definitions);
} else if (new File(definitions).exists()) {
defn = loadFromFile(definitions);
} else
throw new FHIRException("Unable to find FHIR validation Pack (source = "+definitions+")");
return defn;
}

private byte[] loadFromUrl(String src) throws IOException {
URL url = new URL(src);
byte[] str = IOUtils.toByteArray(url.openStream());
return str;
}

private byte[] loadFromFile(String src) throws IOException {
FileInputStream in = new FileInputStream(src);
byte[] b = new byte[in.available()];
in.read(b);
in.close();
return b;
}


protected XmlPullParser loadXml(InputStream stream) throws XmlPullParserException, IOException {
BufferedInputStream input = new BufferedInputStream(stream);
XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
Expand Down Expand Up @@ -438,4 +383,4 @@ private void executeTest(String[] args) throws Throwable {
}


}
}

0 comments on commit 909f7e6

Please sign in to comment.