mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-10-06 04:59:23 +08:00
Merge remote-tracking branch 'origin/Ghidra_12.2'
This commit is contained in:
@@ -31,12 +31,14 @@ import org.jgrapht.traverse.TopologicalOrderIterator;
|
||||
import org.osgi.framework.*;
|
||||
import org.osgi.framework.launch.Framework;
|
||||
import org.osgi.framework.wiring.*;
|
||||
import org.osgi.service.url.URLStreamHandlerService;
|
||||
|
||||
import generic.io.NullPrintWriter;
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.options.SaveState;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.framework.protocol.ghidra.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -417,10 +419,6 @@ public class BundleHost {
|
||||
// setup the cache path
|
||||
config.setProperty(Constants.FRAMEWORK_STORAGE, makeCacheDir());
|
||||
|
||||
// prevent the use of Felix URL handlers which can interfere with URL.openConnection
|
||||
// exception handling
|
||||
config.put(FelixConstants.SERVICE_URLHANDLERS_PROP, "false");
|
||||
|
||||
config.put(FelixConstants.LOG_LEVEL_PROP, "1");
|
||||
if (STDERR_DEBUGGING) {
|
||||
config.put(FelixConstants.LOG_LEVEL_PROP, "999");
|
||||
@@ -481,6 +479,8 @@ public class BundleHost {
|
||||
throw new OSGiException("Felix OSGi framework has no bundle context");
|
||||
}
|
||||
|
||||
registerGhidraProtocolHandler(frameworkBundleContext);
|
||||
|
||||
addDebuggingListeners();
|
||||
|
||||
Bundle bundle = frameworkBundleContext.getBundle();
|
||||
@@ -521,6 +521,23 @@ public class BundleHost {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install Ghidra URL stream handler service to force standard use of {@code ghidra} protocol
|
||||
* {@link Handler}. This bypasses the improper IOException propagation caused by
|
||||
* {@code URLHandlersStreamHandlerProxy.openConnection(URL)} which forces itself to
|
||||
* act as a proxy for all normal protocol handlers.
|
||||
*
|
||||
* @param context OSGI Bundle context
|
||||
*/
|
||||
private void registerGhidraProtocolHandler(BundleContext context) {
|
||||
Hashtable<String, Object> properties = new Hashtable<>();
|
||||
properties.put("url.handler.protocol", new String[] { GhidraURL.PROTOCOL });
|
||||
context.registerService(
|
||||
URLStreamHandlerService.class.getName(),
|
||||
new GhidraOSGIStreamHandler(),
|
||||
properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the host framework.
|
||||
* @return the OSGi framework
|
||||
|
||||
@@ -3214,8 +3214,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
long loadSizeBytes = elfProgramHeader.getAdjustedLoadSize();
|
||||
long fullSizeBytes = elfProgramHeader.getAdjustedMemorySize();
|
||||
|
||||
boolean maintainExecuteBit = elf.getSectionHeaderCount() == 0;
|
||||
|
||||
if (fullSizeBytes <= 0) {
|
||||
if (!space.isLoadedMemorySpace() && loadSizeBytes > 0) {
|
||||
fullSizeBytes = loadSizeBytes;
|
||||
@@ -3239,16 +3237,12 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
|
||||
String comment = getSectionComment(addr, fullSizeBytes, space.getAddressableUnitSize(),
|
||||
elfProgramHeader.getDescription(), address.isLoadedMemoryAddress());
|
||||
if (!maintainExecuteBit && elfProgramHeader.isExecute()) {
|
||||
comment += " (disabled execute bit)";
|
||||
}
|
||||
|
||||
String blockName = getSegmentName(elfProgramHeader, segmentNumber);
|
||||
if (loadSizeBytes != 0) {
|
||||
addInitializedMemorySection(elfProgramHeader, elfProgramHeader.getOffset(),
|
||||
loadSizeBytes, address, blockName, elfProgramHeader.isRead(),
|
||||
elfProgramHeader.isWrite(),
|
||||
maintainExecuteBit ? elfProgramHeader.isExecute() : false, comment,
|
||||
elfProgramHeader.isWrite(), elfProgramHeader.isExecute(), comment,
|
||||
isFragmentationOK,
|
||||
elfProgramHeader.getType() == ElfProgramHeaderConstants.PT_LOAD);
|
||||
}
|
||||
@@ -3435,11 +3429,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
|
||||
Address address = null;
|
||||
ElfProgramHeader loadHeader = elf.getProgramLoadHeaderContaining(addr);
|
||||
|
||||
if (sectionByteLength == 0 &&
|
||||
elfSectionToLoad.getType() == ElfSectionHeaderConstants.SHT_PROGBITS) {
|
||||
// Check for and consume uninitialized portion of PT_LOAD segment if possible
|
||||
ElfProgramHeader loadHeader = elf.getProgramLoadHeaderContaining(addr);
|
||||
if (loadHeader != null) {
|
||||
// NOTE: should never apply to relocatable ELF
|
||||
Address segmentStart = getSegmentLoadAddress(loadHeader);
|
||||
@@ -3478,6 +3472,19 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
|
||||
final String blockName = elfSectionToLoad.getNameAsString();
|
||||
|
||||
boolean isExecute = elfSectionToLoad.isExecutable();
|
||||
boolean isWrite = elfSectionToLoad.isWritable();
|
||||
boolean isRead = true;
|
||||
|
||||
if (loadHeader != null) {
|
||||
// If PT_LOAD exists, defer to it for permissions
|
||||
// NOTE: This does not handle a section not fully contained within a program
|
||||
// header loaded region
|
||||
isExecute = loadHeader.isExecute();
|
||||
isWrite = loadHeader.isWrite();
|
||||
isRead = loadHeader.isRead();
|
||||
}
|
||||
|
||||
try {
|
||||
if (loadOffset == -1 ||
|
||||
elfSectionToLoad.getType() == ElfSectionHeaderConstants.SHT_NOBITS) {
|
||||
@@ -3489,7 +3496,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
getSectionComment(addr, sectionByteLength, space.getAddressableUnitSize(),
|
||||
elfSectionToLoad.getTypeAsString(), address.isLoadedMemoryAddress());
|
||||
addUninitializedMemorySection(elfSectionToLoad, sectionByteLength, address,
|
||||
blockName, true, elfSectionToLoad.isWritable(), elfSectionToLoad.isExecutable(),
|
||||
blockName, isRead, isWrite, isExecute,
|
||||
comment, false);
|
||||
}
|
||||
else {
|
||||
@@ -3497,8 +3504,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
getSectionComment(addr, sectionByteLength, space.getAddressableUnitSize(),
|
||||
elfSectionToLoad.getTypeAsString(), address.isLoadedMemoryAddress());
|
||||
addInitializedMemorySection(elfSectionToLoad, loadOffset, sectionByteLength,
|
||||
address, blockName, elfSectionToLoad.isAlloc(), elfSectionToLoad.isWritable(),
|
||||
elfSectionToLoad.isExecutable(), comment, false, elfSectionToLoad.isAlloc());
|
||||
address, blockName, isRead, isWrite,
|
||||
isExecute, comment, false, elfSectionToLoad.isAlloc());
|
||||
}
|
||||
}
|
||||
catch (AddressOverflowException e) {
|
||||
|
||||
+41
-27
@@ -111,41 +111,55 @@ public class URLAnnotatedStringHandler implements AnnotatedStringHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUnsupportedGhidraURL(URL url) {
|
||||
try {
|
||||
return GhidraURL.isGhidraURL(url) && GhidraURL.getProjectPathname(url) == null;
|
||||
}
|
||||
catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleMouseClick(String[] annotationParts, Navigatable navigatable,
|
||||
ServiceProvider serviceProvider) {
|
||||
|
||||
String urlString = annotationParts[1];
|
||||
URL url = getURLForString(urlString);
|
||||
if (url != null) {
|
||||
|
||||
String protocol = url.getProtocol();
|
||||
if (!allowedProtocols.contains(protocol)) {
|
||||
Msg.showError(this, null, "URL Access Not Allowed",
|
||||
"Unsupported URL annotation protocol - " + allowedProtocolsStr +
|
||||
" required:\n\n" +
|
||||
urlString);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ClientUtil.getAllowListProvider().isAllowed(url)) {
|
||||
Msg.showError(this, null, "URL Access Not Allowed",
|
||||
"Access denied by Server Allow List");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GhidraURL.PROTOCOL.equals(url.getProtocol())) {
|
||||
ProgramManager programManager = serviceProvider.getService(ProgramManager.class);
|
||||
return programManager.openProgram(url, ProgramManager.OPEN_CURRENT) != null;
|
||||
}
|
||||
|
||||
BrowserLoader.display(url, null, serviceProvider);
|
||||
return true;
|
||||
if (url == null) {
|
||||
Msg.showError(this, null, "Invalid URL",
|
||||
"Invalid URL annotation: " + urlString);
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg.showError(this, null, "Invalid URL",
|
||||
"Invalid URL annotation - not a valid URL: " + urlString);
|
||||
String protocol = url.getProtocol();
|
||||
if (!allowedProtocols.contains(protocol)) {
|
||||
Msg.showError(this, null, "URL Access Not Allowed",
|
||||
"Unsupported URL annotation protocol - " + allowedProtocolsStr +
|
||||
" required:\n" + urlString);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (isUnsupportedGhidraURL(url)) {
|
||||
Msg.showError(this, null, "Invalid Ghidra URL",
|
||||
"Unsupported Ghidra URL annotation:\n" + urlString);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GhidraURL.isLocalURL(url) && !ClientUtil.getAllowListProvider().isAllowed(url)) {
|
||||
Msg.showError(this, null, "URL Access Not Allowed",
|
||||
"Access denied by Server Allow List");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GhidraURL.isGhidraURL(url)) {
|
||||
|
||||
ProgramManager programManager = serviceProvider.getService(ProgramManager.class);
|
||||
return programManager.openProgram(url, ProgramManager.OPEN_CURRENT) != null;
|
||||
}
|
||||
|
||||
BrowserLoader.display(url, null, serviceProvider);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.framework.protocol.ghidra;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import org.osgi.service.url.AbstractURLStreamHandlerService;
|
||||
|
||||
/**
|
||||
* {@link GhidraOSGIStreamHandler} provides a Ghidra URL stream handler service for
|
||||
* Felix OSGI. This allows direct use of the standard {@code ghidra} protocol
|
||||
* {@link Handler} and bypasses the improper IOException propagation caused by
|
||||
* {@code URLHandlersStreamHandlerProxy.openConnection(URL)}.
|
||||
*/
|
||||
public class GhidraOSGIStreamHandler extends AbstractURLStreamHandlerService {
|
||||
|
||||
private static final Handler ghidraProtocolHandler = new Handler();
|
||||
|
||||
@Override
|
||||
public URLConnection openConnection(URL url) throws IOException {
|
||||
return ghidraProtocolHandler.openConnection(url);
|
||||
}
|
||||
}
|
||||
@@ -212,6 +212,9 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
logger.accept("\t%d external symbols resolved, %d remain unresolved"
|
||||
.formatted(getResolvedSymbolCount(), unresolvedExternalFunctionIds.size()));
|
||||
for (ExtLibInfo extLib : extLibs) {
|
||||
if (Library.UNKNOWN.equals(extLib.getName())) {
|
||||
continue;
|
||||
}
|
||||
String libPath = extLib.getAssociatedProgramPath();
|
||||
String loggedLibPath = libPath != null ? libPath : "missing";
|
||||
if (extLib.problem != null) {
|
||||
@@ -269,7 +272,9 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
try (Transaction tx = program.openTransaction("Resolve External Symbols")) {
|
||||
for (ExtLibInfo extLib : extLibs) {
|
||||
monitor.checkCancelled();
|
||||
resolveSymbolsToLibrary(extLib);
|
||||
if (extLib.libProgram != null) {
|
||||
resolveSymbolsToLibrary(extLib);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +297,7 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
Program libProg = libPath != null ? getLibraryProgram(libPath) : null;
|
||||
Throwable problem =
|
||||
libProg == null && libPath != null ? problemLibraries.get(libPath) : null;
|
||||
result.add(new ExtLibInfo(lib, problem));
|
||||
result.add(new ExtLibInfo(lib, libProg, problem));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -322,7 +327,7 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
ExternalLocation extLoc = externalManager.getExternalLocation(s);
|
||||
String extLocName =
|
||||
Objects.requireNonNullElse(extLoc.getOriginalImportedName(), extLoc.getLabel());
|
||||
if (isExportedSymbol(program, extLocName)) {
|
||||
if (isExportedSymbol(extLib.libProgram, extLocName)) {
|
||||
try {
|
||||
s.setNamespace(extLib.lib);
|
||||
idIterator.remove();
|
||||
@@ -360,6 +365,7 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
private class ExtLibInfo {
|
||||
|
||||
final Library lib;
|
||||
final Program libProgram; // may be null
|
||||
final List<String> resolvedSymbols = new ArrayList<>();
|
||||
final Throwable problem;
|
||||
|
||||
@@ -367,13 +373,15 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
* Define external Library dependency associated with {@link ProgramSymbolResolver}
|
||||
* instance.
|
||||
* @param lib external library dependency
|
||||
* @param problem exception which occured while accessing Library
|
||||
* @param libProgram imported or discovered program which corresponds to lib, or null if not found
|
||||
* @param problem exception which occurred while accessing Library
|
||||
*/
|
||||
ExtLibInfo(Library lib, Throwable problem) {
|
||||
ExtLibInfo(Library lib, Program libProgram, Throwable problem) {
|
||||
if (program != lib.getSymbol().getProgram()) {
|
||||
throw new AssertionError("Program mismatch");
|
||||
}
|
||||
this.lib = lib;
|
||||
this.libProgram = libProgram;
|
||||
this.problem = problem;
|
||||
}
|
||||
|
||||
@@ -416,7 +424,9 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
* @return true if program publishes a symbol the specified name
|
||||
*/
|
||||
private static boolean isExportedSymbol(Program program, String name) {
|
||||
|
||||
if (program == null) {
|
||||
return false;
|
||||
}
|
||||
for (Symbol s : program.getSymbolTable().getLabelOrFunctionSymbols(name, null)) {
|
||||
if (s.isExternalEntryPoint()) {
|
||||
return true;
|
||||
|
||||
+17
-8
@@ -59,18 +59,27 @@ public class GhidraGoPlugin extends Plugin implements ApplicationLevelOnlyPlugin
|
||||
|
||||
private void processUrl(URL url) {
|
||||
|
||||
URL projectUrl = GhidraURL.getProjectURL(url);
|
||||
Msg.info(this, "GhidraGo accepting the resource at " + projectUrl);
|
||||
FrontEndTool frontEndTool = AppInfo.getFrontEndTool();
|
||||
|
||||
// Check for case where server access has already been blocked to
|
||||
// launching tool and then failing to access program.
|
||||
if (!ClientUtil.getAllowListProvider().isAllowed(url)) {
|
||||
Msg.showError(this, frontEndTool.getActiveWindow(), "URL Access Not Allowed",
|
||||
"Access denied by Server Allow List:\n" + projectUrl);
|
||||
try {
|
||||
URL projectUrl = GhidraURL.getProjectURL(url);
|
||||
|
||||
// Check for case where remote server access has already been blocked to
|
||||
// launching tool and then failing to access program.
|
||||
if (!GhidraURL.isLocalURL(url) && !ClientUtil.getAllowListProvider().isAllowed(url)) {
|
||||
Msg.showError(this, frontEndTool.getActiveWindow(), "URL Access Not Allowed",
|
||||
"Access denied by Server Allow List:\n" + projectUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
Msg.info(this, "GhidraGo accepting the resource at " + projectUrl);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, frontEndTool.getActiveWindow(), "GhidraGo Failed",
|
||||
"GhidraGo rejected invalid URL: " + url);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Swing.runLater(() -> {
|
||||
frontEndTool.toFront();
|
||||
frontEndTool.accept(url);
|
||||
|
||||
@@ -402,7 +402,7 @@ public class ClientUtil {
|
||||
if (hdl == null) {
|
||||
Exception e = connectTask.getException();
|
||||
if (e == null) {
|
||||
return null; // cancelled by user
|
||||
throw new CancelledException();
|
||||
}
|
||||
if (e instanceof IOException) {
|
||||
throw (IOException) e;
|
||||
|
||||
+6
@@ -23,6 +23,8 @@ import java.util.*;
|
||||
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import ghidra.framework.Application;
|
||||
@@ -113,6 +115,10 @@ public class UrlAllowListManager {
|
||||
*/
|
||||
public static synchronized Boolean getAccess(String protocol, String host, int port) {
|
||||
|
||||
if (StringUtils.isBlank(protocol) || StringUtils.isBlank(host)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always allow access to localhost if alwaysAllowLocalAccess is true
|
||||
if (alwaysAllowLocalAccess && ("localhost".equals(host) || "127.0.0.1".equals(host))) {
|
||||
return true;
|
||||
|
||||
+2
-2
@@ -513,8 +513,8 @@ public class GhidraObjectInputFilter implements ObjectInputFilter {
|
||||
* @param filterFile serial filter file
|
||||
* @param sourceNameSupplier source name supplied for use during logging, or null. It
|
||||
* is assumed that a the current thread may be used to differentiate a client connection
|
||||
* over which the serialization is occuring.
|
||||
* @throws IllegalStateException if error occured building or installing serial input filter
|
||||
* over which the serialization is occurring.
|
||||
* @throws IllegalStateException if error occurred building or installing serial input filter
|
||||
* and related filter factory.
|
||||
*/
|
||||
public static void configureServerSerialFilter(ResourceFile filterFile,
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ import java.util.function.BinaryOperator;
|
||||
* {@link GhidraSerialFilterFactory} provides the serial filter factory which imposes
|
||||
* {@link GhidraObjectInputFilter} as a global serial input filter.
|
||||
* <p>
|
||||
* NOTE: With the use of Gradle test JVM instances it may be neccessary for those instances
|
||||
* NOTE: With the use of Gradle test JVM instances it may be necessary for those instances
|
||||
* to specify this class as the serial filter factory and rely on lazy initialization of the
|
||||
* {@link GhidraObjectInputFilter global serial filter}.
|
||||
* <pre>
|
||||
@@ -38,7 +38,7 @@ public class GhidraSerialFilterFactory implements BinaryOperator<ObjectInputFilt
|
||||
private final GhidraObjectInputFilter globalFilter;
|
||||
|
||||
/**
|
||||
* Constructor. Caller is reposponsible for installation.
|
||||
* Constructor. Caller is responsible for installation.
|
||||
* See {@link ObjectInputFilter.Config#setSerialFilterFactory}.
|
||||
*/
|
||||
public GhidraSerialFilterFactory() {
|
||||
@@ -71,7 +71,7 @@ public class GhidraSerialFilterFactory implements BinaryOperator<ObjectInputFilt
|
||||
}
|
||||
|
||||
/**
|
||||
* Get, and install if neccessary, the serial filter factory instance. If a new factory is
|
||||
* Get, and install if necessary, the serial filter factory instance. If a new factory is
|
||||
* installed it will have an uninitialized {@link GhidraObjectInputFilter} instance.
|
||||
* <p>
|
||||
* See {@link java.io.ObjectInputFilter.Config#setSerialFilterFactory(java.util.function.BinaryOperator)}.
|
||||
|
||||
@@ -87,7 +87,7 @@ public interface Project extends AutoCloseable, Iterable<DomainFile> {
|
||||
* @param visible true if project may be made visible or false if hidden. Hidden viewed
|
||||
* projects are used when only life-cycle management is required (e.g., close view project
|
||||
* when this project is closed).
|
||||
* @return project data for this view
|
||||
* @return project data for this view or null if user cancels operation (e.g., cancels password prompt)
|
||||
* @throws IOException if this project is closed, an invalid URL is specified, or failed to
|
||||
* open/connect to project/repository.
|
||||
*/
|
||||
|
||||
@@ -259,7 +259,10 @@ public class DefaultProject implements Project {
|
||||
StatusCode responseCode = c.getStatusCode();
|
||||
switch (responseCode) {
|
||||
case OK:
|
||||
break;
|
||||
break; // project data is established below
|
||||
|
||||
case CANCELLED:
|
||||
return null; // e.g., user cancelled password request
|
||||
|
||||
case UNAUTHORIZED:
|
||||
throw new IOException("Authorization failure");
|
||||
|
||||
+1
@@ -72,6 +72,7 @@ public class DefaultGhidraProtocolConnector extends GhidraProtocolConnector {
|
||||
ClientUtil.getRepositoryServer(url.getHost(), url.getPort(), true);
|
||||
if (!repositoryServerAdapter.isConnected()) {
|
||||
if (repositoryServerAdapter.isCancelled()) {
|
||||
statusCode = StatusCode.CANCELLED;
|
||||
return statusCode;
|
||||
}
|
||||
Throwable t = repositoryServerAdapter.getLastConnectError();
|
||||
|
||||
+2
-1
@@ -608,8 +608,9 @@ public class GhidraURL {
|
||||
*
|
||||
* @param ghidraUrl Ghidra local or remote file/folder URL (server-only URL not permitted)
|
||||
* @return pathname of file or folder
|
||||
* @throws IllegalArgumentException if an invalid URL is specified
|
||||
*/
|
||||
public static String getProjectPathname(URL ghidraUrl) {
|
||||
public static String getProjectPathname(URL ghidraUrl) throws IllegalArgumentException {
|
||||
|
||||
try {
|
||||
URI uri = ghidraUrl.toURI();
|
||||
|
||||
+4
@@ -50,6 +50,10 @@ public class GhidraURLConnection extends URLConnection {
|
||||
* This status code occurs when project is locked (i.e., in use).
|
||||
*/
|
||||
LOCKED(423, "Locked Project"),
|
||||
/**
|
||||
* Ghidra Status-Code 499: Connect Request Cancelled (likely during password prompt)
|
||||
*/
|
||||
CANCELLED(499, "Client Cancelled Request"),
|
||||
/**
|
||||
* Ghidra Status-Code 503: Unavailable.
|
||||
* This status code includes a variety of connection errors
|
||||
|
||||
+4
-3
@@ -165,11 +165,12 @@ public class GhidraURLQuery {
|
||||
c.setReadOnly(readOnly); // writable repository connection
|
||||
obj = c.getContent(); // read-only access
|
||||
status = c.getStatusCode();
|
||||
if (status == StatusCode.CANCELLED) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
if (status == null) {
|
||||
status = StatusCode.UNAVAILABLE;
|
||||
}
|
||||
status = StatusCode.UNAVAILABLE;
|
||||
resultHandler.handleError("URL Connection Error", e.getMessage(), ghidraUrl, e);
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -19,6 +19,8 @@ import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.framework.client.ClientUtil;
|
||||
import ghidra.framework.remote.GhidraServerHandle;
|
||||
import ghidra.util.Msg;
|
||||
@@ -71,8 +73,8 @@ public class Handler extends URLStreamHandler {
|
||||
}
|
||||
|
||||
if (url.getAuthority() != null) {
|
||||
// assume standard ghidra URL (ghidra://...) - query not allowed
|
||||
return url.getQuery() == null;
|
||||
// assume standard ghidra URL (ghidra://host...) - query not allowed
|
||||
return !StringUtils.isBlank(url.getHost()) && url.getQuery() == null;
|
||||
}
|
||||
try {
|
||||
return getProtocolExtensionHandler(url) != null;
|
||||
|
||||
Reference in New Issue
Block a user