Skip to content

Commit 1ecb04e

Browse files
committed
I have implemented heap-copy approach for both buffering queues in the interceptor:
Inbound Queue (savedMessages): In DataPlaneListener.onMessage, when a message is queued (because we are waiting for external processor header responses), it is now synchronously copied into a heap-allocated ByteString and queued as a KnownLengthInputStream. This prevents gRPC's deframer from recycling the underlying Netty direct buffers when onMessage returns, fully resolving the inbound Use-After-Free risk. Outbound Queue (pendingDrainingMessages): In DataPlaneClientCall.sendMessage, when outbound messages are queued (because the ext-proc stream is draining or completing), we now synchronously read the stream into a heap-allocated ByteString and queue it as a KnownLengthInputStream before returning immediately to the application. This ensures that even if the application manually reclaims off-heap direct buffers immediately after sendMessage returns, the buffered message remains perfectly safe and valid for later transmission, resolving the outbound Use-After-Free/caching risk.
1 parent 6d62895 commit 1ecb04e

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

xds/src/main/java/io/grpc/xds/ExternalProcessorClientInterceptor.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,12 @@ public void sendMessage(InputStream message) {
991991

992992
ExtProcStreamState state = extProcStreamState.get();
993993
if (state.isDraining() || state.isCompleted()) {
994-
pendingDrainingMessages.add(message);
994+
try {
995+
ByteString copiedBody = ByteString.readFrom(message);
996+
pendingDrainingMessages.add(new KnownLengthInputStream(copiedBody));
997+
} catch (IOException e) {
998+
rawCall.cancel("Failed to copy outbound message for buffering", e);
999+
}
9951000
return;
9961001
}
9971002
}
@@ -1301,7 +1306,12 @@ public void onMessage(InputStream message) {
13011306

13021307
if (savedHeaders != null
13031308
|| dataPlaneClientCall.getExtProcStreamState().get().isDraining()) {
1304-
savedMessages.add(message);
1309+
try {
1310+
ByteString copiedBody = ByteString.readFrom(message);
1311+
savedMessages.add(new KnownLengthInputStream(copiedBody));
1312+
} catch (IOException e) {
1313+
rawCall.cancel("Failed to copy inbound message for buffering", e);
1314+
}
13051315
return;
13061316
}
13071317
}

0 commit comments

Comments
 (0)