Skip to content

Commit

Permalink
Arbitrary File Read
Browse files Browse the repository at this point in the history
Fixes redhat-developer/vscode-xml#671

Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
angelozerr committed Mar 27, 2022
1 parent acbc29b commit da8c2bf
Show file tree
Hide file tree
Showing 54 changed files with 1,516 additions and 603 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -330,8 +331,8 @@ public Collection<DOMDocument> getAllDocuments() {
}

@Override
public void validate(DOMDocument document) {
xmlTextDocumentService.validate(document);
public void validate(DOMDocument document, Map<String, Object> validationArgs) {
xmlTextDocumentService.validate(document, validationArgs);
}

public XMLCapabilityManager getCapabilityManager() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -615,13 +616,34 @@ private void triggerValidationFor(TextDocument document, TriggeredBy triggeredBy
});
}

/**
* Validate and publish diagnostics for the given DOM document.
*
* @param xmlDocument the DOM document.
*
* @throws CancellationException when the DOM document content changed and
* diagnostics must be stopped.
*/
void validate(DOMDocument xmlDocument) throws CancellationException {
validate(xmlDocument, Collections.emptyMap());
}

/**
* Validate and publish diagnostics for the given DOM document.
*
* @param xmlDocument the DOM document.
* @param validationArgs the validation arguments.
*
* @throws CancellationException when the DOM document content changed and
* diagnostics must be stopped.
*/
void validate(DOMDocument xmlDocument, Map<String, Object> validationArgs) throws CancellationException {
CancelChecker cancelChecker = xmlDocument.getCancelChecker();
cancelChecker.checkCanceled();
getXMLLanguageService().publishDiagnostics(xmlDocument,
params -> xmlLanguageServer.getLanguageClient().publishDiagnostics(params),
(doc) -> triggerValidationFor(doc, TriggeredBy.Other), sharedSettings.getValidationSettings(),
cancelChecker);
validationArgs, cancelChecker);
}

private XMLLanguageService getXMLLanguageService() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ public DTDEntityDecl(int start, int end) {
setDeclType(start + 2, start + 8);
}

/**
* Returns the '%' and null otherwise.
*
* <p>
* <!ENTITY |% ...
* </p>
*
* @return the '%' and null otherwise.
*/
public String getPercent() {
return percent != null ? percent.getParameter() : null;
}
Expand All @@ -66,6 +75,28 @@ public void setPercent(int start, int end) {
percent = addNewParameter(start, end);
}

/**
* Returns the entity value node and null otherwise.
*
* <p>
* <!ENTITY % entity-name |"entity-value" ...
* </p>
*
* @return the entity value node and null otherwise.
*/
public DTDDeclParameter getValueNode() {
return value;
}

/**
* Returns the entity value content and null otherwise.
*
* <p>
* <!ENTITY % entity-name |"entity-value" ...
* </p>
*
* @return the entity value content and null otherwise.
*/
public String getValue() {
return value != null ? value.getParameterWithoutFirstAndLastChar() : null;
}
Expand All @@ -74,6 +105,15 @@ public void setValue(int start, int end) {
value = addNewParameter(start, end);
}

/**
* Returns the entity kind (PUBLIC, SYSTEM) and null otherwise.
*
* <p>
* <!ENTITY % entity-name |PUBLIC
* </p>
*
* @return the entity kind (PUBLIC, SYSTEM) and null otherwise.
*/
public String getKind() {
return kind != null ? kind.getParameter() : null;
}
Expand Down Expand Up @@ -132,9 +172,9 @@ public String getSystemId() {
}

/**
* Returns the system if node and null otherwise.
* Returns the system id node and null otherwise.
*
* @return the system if node and null otherwise.
* @return the system id node and null otherwise.
*/
public DTDDeclParameter getSystemIdNode() {
return systemId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ private void updateSettings(ContentModelSettings settings, ISaveContext context)
if (useCache != null) {
contentModelManager.setUseCache(useCache);
}

// Download external resources
XMLDownloadExternalResourcesSettings downloadExternalResources = settings.getDownloadExternalResources();
boolean downloadExternalResourcesEnabled = downloadExternalResources == null
Expand All @@ -167,6 +168,9 @@ private void updateSettings(ContentModelSettings settings, ISaveContext context)
if (oldValidationSettings != null && !Objects.equals(oldValidationSettings, currentValidationSettings)) {
context.collectDocumentToValidate(d -> true);
}
if (currentValidationSettings != null) {
contentModelManager.setResolveExternalEntities(currentValidationSettings.isResolveExternalEntities());
}
}

private void validateAllOpenedDocument(ISaveContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,31 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.contentmodel.commands;

import java.util.Map;

import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager;
import org.eclipse.lemminx.services.IXMLDocumentProvider;
import org.eclipse.lemminx.services.IXMLValidationService;
import org.eclipse.lemminx.services.extensions.commands.AbstractDOMDocumentCommandHandler;
import org.eclipse.lemminx.settings.SharedSettings;
import org.eclipse.lemminx.utils.JSONUtility;
import org.eclipse.lsp4j.ExecuteCommandParams;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;

import com.google.gson.JsonObject;

/**
* XML Command "xml.validation.current.file" to revalidate a give XML file which
* means:
*
*
* <ul>
* <li>remove the referenced grammar in the XML file from the Xerces grammar
* pool (used by the Xerces validation) and the content model documents cache
* (used by the XML completion/hover based on the grammar)</li>
* <li>trigger the validation for the given XML file</li>
* </ul>
*
*
* @author Angelo ZERR
*
*/
Expand All @@ -52,12 +57,16 @@ public XMLValidationFileCommand(ContentModelManager contentModelManager, IXMLDoc
@Override
protected Object executeCommand(DOMDocument document, ExecuteCommandParams params, SharedSettings sharedSettings,
CancelChecker cancelChecker) throws Exception {
// Validation args can contains the external resource ('url' as key map) to
// force do download.
JsonObject validationArgs = params.getArguments().size() > 1 ? (JsonObject) params.getArguments().get(1) : null;
// 1. remove the referenced grammar in the XML file from the Xerces grammar pool
// (used by the Xerces validation) and the content model documents cache (used
// by the XML completion/hover based on the grammar)
contentModelManager.evictCacheFor(document);
// 2. trigger the validation for the given XML file
validationService.validate(document);
Map map = JSONUtility.toModel(validationArgs, Map.class);
validationService.validate(document, map);
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.Map;
import java.util.Set;

import org.apache.xerces.xni.grammars.XMLGrammarPool;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelProvider.Identifier;
Expand Down Expand Up @@ -57,6 +56,8 @@ public class ContentModelManager {
private final XMLFileAssociationResolverExtension fileAssociationResolver;
private final LSPXMLGrammarPool grammarPool;

private boolean resolveExternalEntities;

public ContentModelManager(URIResolverExtensionManager resolverManager) {
this.resolverManager = resolverManager;
modelProviders = new ArrayList<>();
Expand Down Expand Up @@ -132,7 +133,8 @@ public Collection<CMDocument> findCMDocument(DOMDocument xmlDocument, String nam
for (ContentModelProvider modelProvider : modelProviders) {
// internal grammar
if (withInternal) {
CMDocument internalCMDocument = modelProvider.createInternalCMDocument(xmlDocument);
CMDocument internalCMDocument = modelProvider.createInternalCMDocument(xmlDocument,
isResolveExternalEntities());
if (internalCMDocument != null) {
documents.add(internalCMDocument);
}
Expand Down Expand Up @@ -312,17 +314,17 @@ private CMDocument findCMDocument(String uri, String publicId, String systemId,
try {
Path file = cacheResolverExtension.getCachedResource(resolvedUri);
if (file != null) {
cmDocument = modelProvider.createCMDocument(file.toUri().toString());
cmDocument = modelProvider.createCMDocument(file.toUri().toString(), isResolveExternalEntities());
}
} catch (CacheResourceDownloadingException e) {
// the DTD/XML Schema is downloading
return null;
} catch (Exception e) {
// other error like network which is not available
cmDocument = modelProvider.createCMDocument(resolvedUri);
cmDocument = modelProvider.createCMDocument(resolvedUri, isResolveExternalEntities());
}
} else {
cmDocument = modelProvider.createCMDocument(resolvedUri);
cmDocument = modelProvider.createCMDocument(resolvedUri, isResolveExternalEntities());
}
// Cache the document
if (cmDocument != null) {
Expand Down Expand Up @@ -404,11 +406,21 @@ public void setUseCache(boolean useCache) {
grammarPool.clear();
}
}


/**
* Returns true if the external resources can be downloaded and false otherwise.
*
* @return true if the external resources can be downloaded and false otherwise.
*/
public boolean isDownloadExternalResources() {
return cacheResolverExtension.isDownloadExternalResources();
}

/**
* Set true if the external resources can be downloaded and false otherwise.
*
* @param downloadExternalResources the external resources
*/
public void setDownloadExternalResources(boolean downloadExternalResources) {
cacheResolverExtension.setDownloadExternalResources(downloadExternalResources);
}
Expand Down Expand Up @@ -482,4 +494,31 @@ public LSPXMLGrammarPool getGrammarPool() {
return cacheResolverExtension.isUseCache() ? grammarPool : null;
}

/**
* Returns true if external entities must be resolved and false otherwise.
*
* @return true if external entities must be resolved and false otherwise.
*/
public boolean isResolveExternalEntities() {
return resolveExternalEntities;
}

/**
* Set true if external entities must be resolved and false otherwise.
*
* @param resolveExternalEntities resolve external entities
*/
public void setResolveExternalEntities(boolean resolveExternalEntities) {
this.resolveExternalEntities = resolveExternalEntities;
}

/**
* Force the given <code>url</code> to download.
*
* @param url the url to download.!
*/
public void forceDownloadExternalResource(String url) {
cacheResolverExtension.forceDownloadExternalResource(url);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public String getKind() {

Collection<Identifier> getIdentifiers(DOMDocument xmlDocument, String namespaceURI);

CMDocument createCMDocument(String key);
CMDocument createCMDocument(String key, boolean resolveExternalEntities);

CMDocument createInternalCMDocument(DOMDocument xmlDocument);
CMDocument createInternalCMDocument(DOMDocument xmlDocument, boolean resolveExternalEntities);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Map;

import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.DownloadResourceDisabledCodeAction;
import org.eclipse.lemminx.extensions.xsd.participants.XSDErrorCode;
import org.eclipse.lemminx.services.extensions.ICodeActionParticipant;
import org.eclipse.lemminx.services.extensions.IComponentProvider;
Expand Down Expand Up @@ -65,6 +66,7 @@ private void registerCodeActionsIfNeeded(SharedSettings sharedSettings) {
DTDErrorCode.registerCodeActionParticipants(codeActionParticipants, sharedSettings);
XMLSchemaErrorCode.registerCodeActionParticipants(codeActionParticipants, sharedSettings);
XSDErrorCode.registerCodeActionParticipants(codeActionParticipants);
ExternalResourceErrorCode.registerCodeActionParticipants(codeActionParticipants);
}
}
}
Expand Down
Loading

0 comments on commit da8c2bf

Please sign in to comment.