GP-1 Revised Ghidra Server interface version and compatibility checks.

This commit is contained in:
ghidra1
2026-05-05 13:35:15 -04:00
parent daa0bc243a
commit e18f7bb4e5
4 changed files with 84 additions and 33 deletions
@@ -243,15 +243,15 @@ public class GhidraServer extends UnicastRemoteObject implements GhidraServerHan
}
@Override
public void checkCompatibility(int minServerInterfaceVersion) throws RemoteException {
if (minServerInterfaceVersion > INTERFACE_VERSION) {
public void checkCompatibility(int clientInterfaceVersion) throws RemoteException {
if (clientInterfaceVersion > SERVER_INTERFACE_VERSION) {
throw new RemoteException(
"Incompatible server interface, a newer Ghidra Server version is required.");
}
else if (minServerInterfaceVersion < MINIMUM_INTERFACE_VERSION) {
else if (clientInterfaceVersion < SERVER_MIN_CLIENT_INTERFACE_VERSION) {
throw new RemoteException(
"Incompatible server interface, the minimum supported Ghidra version is " +
MIN_GHIDRA_VERSION);
ALT_GHIDRA_BIND_VERSION);
}
}
@@ -871,9 +871,20 @@ public class GhidraServer extends UnicastRemoteObject implements GhidraServerHan
Registry registry = LocateRegistry.createRegistry(
ServerPortFactory.getRMIRegistryPort(), clientSocketFactory, serverSocketFactory);
StringBuilder bindVersions = new StringBuilder(" (");
bindVersions.append(GHIDRA_BIND_VERSION);
registry.bind(BIND_NAME, svr);
log.info("Registered Ghidra Server.");
if (!BIND_NAME.equals(ALT_BIND_NAME)) {
// Include alternate binding in support of older Ghidra client versions
bindVersions.append(", ");
bindVersions.append(ALT_GHIDRA_BIND_VERSION);
registry.bind(ALT_BIND_NAME, svr);
}
bindVersions.append(")");
log.info("Registered Ghidra Server" + bindVersions);
}
catch (Throwable t) {
@@ -199,7 +199,7 @@ public class RepositoryServerAdapter {
lastConnectError = t;
}
Msg.showError(this, null, "Server Error",
"An error occurred on the server (" + serverInfoStr + ").\n" + msg, e);
"An error occurred on the server (" + serverInfoStr + ").\n" + msg);
}
catch (IOException e) {
String err = e.getMessage();
@@ -208,8 +208,8 @@ public class RepositoryServerAdapter {
}
String msg = err != null ? err : e.toString();
Msg.showError(this, null, "Server Error",
"An error occurred while connecting to the server (" + serverInfoStr + ").\n" + msg,
e);
"An error occurred while connecting to the server (" + serverInfoStr + ").\n" +
msg);
}
throw new NotConnectedException("Not connected to repository server", lastConnectError);
}
@@ -175,7 +175,7 @@ class ServerConnectTask extends Task {
gsh = (GhidraServerHandle) reg.lookup(GhidraServerHandle.BIND_NAME);
// Check interface compatibility with the minimum supported version
gsh.checkCompatibility(GhidraServerHandle.MINIMUM_INTERFACE_VERSION);
gsh.checkCompatibility(GhidraServerHandle.MIN_CLIENT_INTERFACE_VERSION);
}
catch (NotBoundException e) {
throw new IOException(e.getMessage());
@@ -420,29 +420,32 @@ class ServerConnectTask extends Task {
}
}
private static void checkServerBindNames(Registry reg) throws RemoteException {
private static void checkServerBindNames(Registry reg) throws IOException {
String requiredVersion = GhidraServerHandle.MIN_GHIDRA_VERSION;
String requiredVersion = GhidraServerHandle.GHIDRA_BIND_VERSION;
if (!Application.getApplicationVersion().startsWith(requiredVersion)) {
requiredVersion = requiredVersion + " - " + Application.getApplicationVersion();
}
requiredVersion += " (or possibly newer)";
String[] regList = reg.list();
RemoteException exc = null;
IOException exc = null;
int badVerCount = 0;
String version = null;
for (String name : regList) {
if (name.equals(GhidraServerHandle.BIND_NAME)) {
return; // found it
}
else if (name.startsWith(GhidraServerHandle.BIND_NAME_PREFIX)) {
String version = name.substring(GhidraServerHandle.BIND_NAME_PREFIX.length());
// NOTE: We only report one version even if server has multiple bindings
version = name.substring(GhidraServerHandle.BIND_NAME_PREFIX.length());
if (version.length() == 0) {
version = "4.3.x (or older)";
}
exc = new RemoteException(
"Incompatible Ghidra Server interface, detected interface version " + version +
",\nthis client requires server version " + requiredVersion);
exc = new IOException(
"Incompatible Ghidra Server - detected interface version " + version +
".\nThis client requires server version " + requiredVersion);
++badVerCount;
}
}
@@ -450,11 +453,11 @@ class ServerConnectTask extends Task {
if (badVerCount == 1) {
throw exc;
}
throw new RemoteException("Incompatible Ghidra Server interface, detected " +
badVerCount + " incompatible server versions" +
",\nthis client requires server version " + requiredVersion);
throw new IOException("Incompatible Ghidra Server - detected " +
badVerCount + " incompatible server versions." +
"\nThis client requires server version " + requiredVersion);
}
throw new RemoteException("Ghidra Server not found.");
throw new IOException("Ghidra Server not found.");
}
}
@@ -52,23 +52,53 @@ public interface GhidraServerHandle extends Remote {
* unchanged allowing 9.1 clients to connect to 9.0 server.
* 12: Revised RepositoryFile serialization to facilitate support for text-data used
* for link-file storage (12.0).
* 13: Client-side serialization filters have been implemented and server-side thrown
* exceptions reduced to be compliant with client-side filters. Server still
* supports older clients back to interface version 11. Server may now BIND
* to the RMI registery with two different names if needed.
*/
/**
* The server interface version that the server will use and is the maximum version that the
* client can operate with.
* The server interface version that the server implements. This corresponds to the maximum
* supported client interface version.
*/
public static final int INTERFACE_VERSION = 12;
public static final int SERVER_INTERFACE_VERSION = 13;
/**
* The minimum server interface version that the client can operate with.
*/
public static final int MINIMUM_INTERFACE_VERSION = 11;
public static final int MIN_CLIENT_INTERFACE_VERSION = 13;
/**
* Minimum version of Ghidra which utilized the current INTERFACE_VERSION
* The minimum interface version that the server will support for older client versions.
* When this version is less than {@link #MIN_CLIENT_INTERFACE_VERSION} it allows the following:
* <ul>
* <li>Older ghidra client versions can continue using the current server version, while</li>
* <li>Current ghidra clients version cannot use an older version server.</li>
* </ul>
* When this version differs from {@link #MIN_CLIENT_INTERFACE_VERSION} the server will bind two
* both {@link #BIND_NAME} and {@value #ALT_BIND_NAME}.
* <p>
* NOTE: It is important that the server authentication interface not be modified between this
* version and {@value #MIN_CLIENT_INTERFACE_VERSION}.
*/
public static final String MIN_GHIDRA_VERSION = "9.0";
public static final int SERVER_MIN_CLIENT_INTERFACE_VERSION = 11;
/**
* The server BIND version which the Ghidra client can communicate with.
* This corresponds to {@value #MIN_CLIENT_INTERFACE_VERSION}.
*/
public static final String GHIDRA_BIND_VERSION = "12.0.5";
/**
* Minimum version of a Ghidra client release which can communicate with the current
* Ghidra Server. This corresponds to {@value #SERVER_MIN_CLIENT_INTERFACE_VERSION}
* and {@link #ALT_BIND_NAME}.
* <p>
* This version is used only by the server only in publishing an alternate BIND name and
* identifies the oldest Ghidra client version that may connect.
*/
public static final String ALT_GHIDRA_BIND_VERSION = "9.0";
/**
* Default RMI base port for Ghidra Server
@@ -81,13 +111,21 @@ public interface GhidraServerHandle extends Remote {
static final String BIND_NAME_PREFIX = "GhidraServer";
/**
* RMI registry binding name for the supported version of the remote GhidraServerHandle object.
* Primary RMI registry binding name for the remote GhidraServerHandle object.
* This BIND name is used by both the server and client.
*/
static final String BIND_NAME = BIND_NAME_PREFIX + MIN_GHIDRA_VERSION;
static final String BIND_NAME = BIND_NAME_PREFIX + GHIDRA_BIND_VERSION;
/**
* Alternate RMI registry binding name for the remote GhidraServerHandle object.
* This alternate BIND name is used only by the server in support of older Ghidra clients
* and corresponds to {@link #SERVER_MIN_CLIENT_INTERFACE_VERSION}.
*/
static final String ALT_BIND_NAME = BIND_NAME_PREFIX + ALT_GHIDRA_BIND_VERSION;
/**
* Returns user authentication proxy object.
* @throws RemoteException
* @throws RemoteException if failure occurs while generating authentication callbacks
* @return authentication callbacks which must be satisfied or null if authentication not
* required.
*/
@@ -107,11 +145,10 @@ public interface GhidraServerHandle extends Remote {
throws FailedLoginException, RemoteException;
/**
* Check server interface compatibility
* @param serverInterfaceVersion client/server interface version
* Check server interface compatibility with the specified client interface version.
* @param clientInterfaceVersion client/server interface version
* @throws RemoteException if requested server interface version not available
* @see #INTERFACE_VERSION
*/
void checkCompatibility(int serverInterfaceVersion) throws RemoteException;
void checkCompatibility(int clientInterfaceVersion) throws RemoteException;
}