From 6e294e1e7c00014eb1b0ec1e67aa643efd97e19f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 1 Feb 2023 10:33:52 +0800 Subject: [PATCH] Reject invalid DAP request (#466) --- .../core/adapter/DebugAdapterContext.java | 11 +++++++ .../java/debug/core/adapter/ErrorCode.java | 5 ++-- .../core/adapter/IDebugAdapterContext.java | 4 +++ .../handler/InitializeRequestHandler.java | 1 + .../adapter/handler/LaunchRequestHandler.java | 6 ++++ .../core/protocol/AbstractProtocolServer.java | 30 +++++++++++++++---- 6 files changed, 50 insertions(+), 7 deletions(-) diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java index 345b2fcdf..f8ac01c3e 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/DebugAdapterContext.java @@ -56,6 +56,7 @@ public class DebugAdapterContext implements IDebugAdapterContext { private StepFilters stepFilters; private Path classpathJar = null; private Path argsfile = null; + private boolean isInitialized = false; private long shellProcessId = -1; private long processId = -1; @@ -407,4 +408,14 @@ public long getJDWPLatency() { public void setJDWPLatency(long baseLatency) { this.jdwpLatency = baseLatency; } + + @Override + public boolean isInitialized() { + return isInitialized; + } + + @Override + public void setInitialized(boolean isInitialized) { + this.isInitialized = isInitialized; + } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java index 1cdc4f9ce..6cfe523cf 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/ErrorCode.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2017 Microsoft Corporation and others. +* Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -35,7 +35,8 @@ public enum ErrorCode { EXCEPTION_INFO_FAILURE(1018), EVALUATION_COMPILE_ERROR(2001), EVALUATE_NOT_SUSPENDED_THREAD(2002), - HCR_FAILURE(3001); + HCR_FAILURE(3001), + INVALID_DAP_HEADER(3002); private int id; diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java index 9df539e1d..9a38e8598 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/IDebugAdapterContext.java @@ -154,4 +154,8 @@ public interface IDebugAdapterContext { long getJDWPLatency(); void setJDWPLatency(long baseLatency); + + boolean isInitialized(); + + void setInitialized(boolean isInitialized); } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java index bf60b6456..6b9245166 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java @@ -67,6 +67,7 @@ public CompletableFuture handle(Requests.Command command, Req caps.supportsBreakpointLocationsRequest = true; caps.supportsStepInTargetsRequest = true; response.body = caps; + context.setInitialized(true); return CompletableFuture.completedFuture(response); } } diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java index b1daf1b01..e5662f936 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java @@ -77,6 +77,12 @@ public List getTargetCommands() { @Override public CompletableFuture handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) { + if (!context.isInitialized()) { + final String errorMessage = "'launch' request is rejected since the debug session has not been initialized yet."; + logger.log(Level.SEVERE, errorMessage); + return CompletableFuture.completedFuture( + AdapterUtils.setErrorResponse(response, ErrorCode.LAUNCH_FAILURE, errorMessage)); + } LaunchArguments launchArguments = (LaunchArguments) arguments; Map traceInfo = new HashMap<>(); traceInfo.put("asyncJDWP", context.asyncJDWP()); diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java index 9bec3c228..61d57bd85 100644 --- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java +++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/AbstractProtocolServer.java @@ -1,5 +1,5 @@ /******************************************************************************* -* Copyright (c) 2017 Microsoft Corporation and others. +* Copyright (c) 2017-2022 Microsoft Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -33,6 +33,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.microsoft.java.debug.core.adapter.AdapterUtils; +import com.microsoft.java.debug.core.adapter.ErrorCode; import com.microsoft.java.debug.core.protocol.Events.DebugEvent; import io.reactivex.disposables.Disposable; @@ -54,6 +56,7 @@ public abstract class AbstractProtocolServer implements IProtocolServer { private ByteBuffer rawData; private int contentLength = -1; private AtomicInteger sequenceNumber = new AtomicInteger(1); + private boolean isValidDAPRequest = true; private PublishSubject responseSubject = PublishSubject.create(); private PublishSubject requestSubject = PublishSubject.create(); @@ -217,7 +220,14 @@ private void processData() { if (message.type.equals("request")) { Messages.Request request = JsonUtils.fromJson(messageData, Messages.Request.class); - requestSubject.onNext(request); + if (this.isValidDAPRequest) { + requestSubject.onNext(request); + } else { + Messages.Response response = new Messages.Response(request.seq, request.command); + sendResponse(AdapterUtils.setErrorResponse(response, + ErrorCode.INVALID_DAP_HEADER, + String.format("'%s' request is rejected due to not being a valid DAP message.", request.command))); + } } else if (message.type.equals("response")) { Messages.Response response = JsonUtils.fromJson(messageData, Messages.Response.class); responseSubject.onNext(response); @@ -235,10 +245,20 @@ private void processData() { if (idx != -1) { Matcher matcher = CONTENT_LENGTH_MATCHER.matcher(rawMessage); if (matcher.find()) { - this.contentLength = Integer.parseInt(matcher.group(1)); - int headerByteLength = rawMessage.substring(0, idx + TWO_CRLF.length()) - .getBytes(PROTOCOL_ENCODING).length; + final String contentLengthText = matcher.group(1); + this.contentLength = Integer.parseInt(contentLengthText); + final String headerMessage = rawMessage.substring(0, idx + TWO_CRLF.length()); + final int headerByteLength = headerMessage.getBytes(PROTOCOL_ENCODING).length; this.rawData.removeFirst(headerByteLength); // Remove the header from the raw message. + + int expectedHeaderLength = 16 /*"Content-Length: ".length()*/ + contentLengthText.length(); + int actualHeaderLength = idx; + if (expectedHeaderLength != actualHeaderLength) { + this.isValidDAPRequest = false; + logger.log(Level.SEVERE, String.format("Illegal DAP request is detected: %s", headerMessage)); + } else { + this.isValidDAPRequest = true; + } continue; } }