Fix CVE-2023-5685

(cherry picked from commit 739fb5330095948c1f24c27a407858697dd422ac)
This commit is contained in:
starlet-dx 2024-11-06 16:07:48 +08:00 committed by openeuler-sync-bot
parent efda39b5ff
commit caf37048b1
2 changed files with 371 additions and 1 deletions

View File

@ -0,0 +1,364 @@
From a2fce38d48cca947ea42ee3bead08dd138b42c01 Mon Sep 17 00:00:00 2001
From: Flavia Rainone <frainone@redhat.com>
Date: Fri, 14 Oct 2022 17:00:46 -0300
Subject: [PATCH] [XNIO-423] CVE-2023-5685 Move the recursion in NotifierState
to a iteration, preventing a stack overflow exception when the chain of
notifier states becomes problematically big
Signed-off-by: Flavia Rainone <frainone@redhat.com>
Origin:
https://github.com/xnio/xnio/commit/a2fce38d48cca947ea42ee3bead08dd138b42c01
---
.../main/java/org/xnio/AbstractIoFuture.java | 238 ++++++++++++++----
1 file changed, 187 insertions(+), 51 deletions(-)
diff --git a/api/src/main/java/org/xnio/AbstractIoFuture.java b/api/src/main/java/org/xnio/AbstractIoFuture.java
index 6118a0c7e3..030336b918 100644
--- a/api/src/main/java/org/xnio/AbstractIoFuture.java
+++ b/api/src/main/java/org/xnio/AbstractIoFuture.java
@@ -74,6 +74,141 @@ IOException getException() {
}
}
+ private static abstract class NestedState<T> extends State<T> {
+ private final State<T> next;
+
+ public NestedState(final State next) {
+ this.next = next;
+ }
+
+ /**
+ * Perform any actions that need to be executed when future is done, delegation of done notification to next is
+ * taken care of by invoker.
+ *
+ * @param future the future
+ * @param result the result
+ */
+ protected abstract void doNotifyDone(AbstractIoFuture<T> future, T result);
+
+ @Override
+ public void notifyDone(AbstractIoFuture<T> future, T result) {
+ doNotifyDone(future, result);
+ if (next instanceof NestedState) {
+ NestedState<T> current = this;
+ do {
+ current = (NestedState<T>) current.next;
+ current.doNotifyDone(future, result);
+ } while (current.next instanceof NestedState);
+ current.next.notifyDone(future, result);
+ } else {
+ next.notifyDone(future, result);
+ }
+
+ }
+
+ /**
+ * Perform any actions that need to be done at this state for handling failure, delegation of failure
+ * notification to next is taken care of by invoker
+ *
+ * @param future the future
+ * @param exception the failure
+ */
+ protected abstract void doNotifyFailed(AbstractIoFuture<T> future, IOException exception);
+
+ @Override
+ public void notifyFailed(AbstractIoFuture<T> future, IOException exception) {
+ doNotifyFailed(future, exception);
+ if (next instanceof NestedState) {
+ NestedState<T> current = this;
+ do {
+ current = (NestedState<T>) current.next;
+ current.doNotifyFailed(future, exception);
+ } while (current.next instanceof NestedState);
+ current.next.notifyFailed(future, exception);
+ } else {
+ next.notifyFailed(future, exception);
+ }
+ }
+
+ /**
+ * Perform any actions that need to be done at this state for handling cancellation, delegation of cancellation
+ * notification to next is taken care of by invoker
+ *
+ * @param future the future
+ */
+ protected abstract void doNotifyCancelled(AbstractIoFuture<T> future);
+
+
+
+ @Override
+ public void notifyCancelled(AbstractIoFuture<T> future) {
+ doNotifyCancelled(future);
+ if (next instanceof NestedState) {
+ NestedState<T> current = this;
+ do {
+ current = (NestedState<T>) current.next;
+ current.doNotifyCancelled(future);
+ } while (current.next instanceof NestedState);
+ current.next.notifyCancelled(future);
+ } else {
+ next.notifyCancelled(future);
+ }
+ }
+
+ /**
+ * Perform any actions that need to be done at this state for cancellation. Delegation of cancellation to next
+ * is taken care of by invoker.
+ */
+ protected abstract void doCancel();
+
+ /**
+ * Just delegate cancel() to first next state in the nested chain that is not a NestedState.
+ */
+ @Override
+ public void cancel() {
+ doCancel();
+ if (next instanceof NestedState) {
+ NestedState<T> current = this;
+ do {
+ current = (NestedState<T>) current.next;
+ current.doCancel();
+ } while (current.next instanceof NestedState);
+ current.next.cancel();
+ } else {
+ next.cancel();
+ }
+ }
+
+ /**
+ * Return {@code true} to indicate that, at this state, cancel is requested. If returns false, invoker
+ * will check for inner next states in the chain until it finds a positive result or the final state in the
+ * chain.
+ *
+ * @return {@code true} to indicate that cancel is requested; {@code false} to delegate response to nested
+ * state.
+ */
+ protected abstract boolean isCancelRequested();
+
+ @Override
+ public boolean cancelRequested() {
+ if (isCancelRequested()) {
+ return true;
+ }
+ if (next instanceof NestedState) {
+ NestedState<T> current = this;
+ do {
+ current = (NestedState<T>) current.next;
+ if (current.isCancelRequested()) {
+ return true;
+ }
+ } while (current.next instanceof NestedState);
+ return current.next.cancelRequested();
+ } else {
+ return next.cancelRequested();
+ }
+ }
+ }
+
static final class InitialState<T> extends State<T> {
Status getStatus() {
@@ -229,13 +364,12 @@ boolean cancelRequested() {
}
}
- static final class NotifierState<T, A> extends State<T> {
- final State<T> next;
+ static final class NotifierState<T, A> extends NestedState<T> {
final Notifier<? super T, A> notifier;
final A attachment;
NotifierState(final State<T> next, final Notifier<? super T, A> notifier, final A attachment) {
- this.next = next;
+ super(next);
this.notifier = notifier;
this.attachment = attachment;
}
@@ -244,40 +378,41 @@ Status getStatus() {
return Status.WAITING;
}
- void notifyDone(final AbstractIoFuture<T> future, final T result) {
+ @Override
+ protected void doNotifyDone(final AbstractIoFuture<T> future, final T result) {
doNotify(future);
- next.notifyDone(future, result);
}
- void notifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
+ @Override
+ protected void doNotifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
doNotify(future);
- next.notifyFailed(future, exception);
}
- void notifyCancelled(final AbstractIoFuture<T> future) {
+ @Override
+ protected void doNotifyCancelled(final AbstractIoFuture<T> future) {
doNotify(future);
- next.notifyCancelled(future);
}
- void cancel() {
- next.cancel();
+
+ @Override
+ protected void doCancel() {
}
private void doNotify(final AbstractIoFuture<T> future) {
future.runNotifier(new NotifierRunnable<T, A>(notifier, future, attachment));
}
- boolean cancelRequested() {
- return next.cancelRequested();
+ @Override
+ protected boolean isCancelRequested() {
+ return false;
}
}
- static final class WaiterState<T> extends State<T> {
- final State<T> next;
+ static final class WaiterState<T> extends NestedState<T> {
final Thread waiter;
WaiterState(final State<T> next, final Thread waiter) {
- this.next = next;
+ super(next);
this.waiter = waiter;
}
@@ -285,36 +420,35 @@ Status getStatus() {
return Status.WAITING;
}
- void notifyDone(final AbstractIoFuture<T> future, final T result) {
+ @Override
+ protected void doNotifyDone(final AbstractIoFuture<T> future, final T result) {
LockSupport.unpark(waiter);
- next.notifyDone(future, result);
}
- void notifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
+ @Override
+ protected void doNotifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
LockSupport.unpark(waiter);
- next.notifyFailed(future, exception);
}
- void notifyCancelled(final AbstractIoFuture<T> future) {
+ @Override
+ protected void doNotifyCancelled(final AbstractIoFuture<T> future) {
LockSupport.unpark(waiter);
- next.notifyCancelled(future);
}
- void cancel() {
- next.cancel();
- }
+ @Override
+ protected void doCancel() {}
- boolean cancelRequested() {
- return next.cancelRequested();
+ @Override
+ protected boolean isCancelRequested() {
+ return false;
}
}
- static final class CancellableState<T> extends State<T> {
- final State<T> next;
+ static final class CancellableState<T> extends NestedState<T> {
final Cancellable cancellable;
CancellableState(final State<T> next, final Cancellable cancellable) {
- this.next = next;
+ super(next);
this.cancellable = cancellable;
}
@@ -322,58 +456,60 @@ Status getStatus() {
return Status.WAITING;
}
- void notifyDone(final AbstractIoFuture<T> future, final T result) {
- next.notifyDone(future, result);
+ @Override
+ protected void doNotifyDone(final AbstractIoFuture<T> future, final T result) {
}
- void notifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
- next.notifyFailed(future, exception);
+ @Override
+ protected void doNotifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
}
- void notifyCancelled(final AbstractIoFuture<T> future) {
- next.notifyCancelled(future);
+ @Override
+ protected void doNotifyCancelled(final AbstractIoFuture<T> future) {
}
- void cancel() {
+ @Override
+ protected void doCancel() {
try {
cancellable.cancel();
} catch (Throwable ignored) {}
- next.cancel();
}
- boolean cancelRequested() {
- return next.cancelRequested();
+ @Override
+ protected boolean isCancelRequested() {
+ return false;
}
}
- static final class CancelRequestedState<T> extends State<T> {
- final State<T> next;
+ static final class CancelRequestedState<T> extends NestedState<T> {
CancelRequestedState(final State<T> next) {
- this.next = next;
+ super(next);
}
Status getStatus() {
return Status.WAITING;
}
- void notifyDone(final AbstractIoFuture<T> future, final T result) {
- next.notifyDone(future, result);
+ @Override
+ protected void doNotifyDone(final AbstractIoFuture<T> future, final T result) {
}
- void notifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
- next.notifyFailed(future, exception);
+ @Override
+ protected void doNotifyFailed(final AbstractIoFuture<T> future, final IOException exception) {
}
- void notifyCancelled(final AbstractIoFuture<T> future) {
- next.notifyCancelled(future);
+ @Override
+ protected void doNotifyCancelled(final AbstractIoFuture<T> future) {
}
- void cancel() {
+ @Override
+ protected void doCancel() {
// terminate
}
- boolean cancelRequested() {
+ @Override
+ protected boolean isCancelRequested() {
return true;
}
}

View File

@ -1,6 +1,6 @@
Name: xnio Name: xnio
Version: 3.4.0 Version: 3.4.0
Release: 10 Release: 11
Summary: A simplified low-level I/O layer Summary: A simplified low-level I/O layer
License: ASL 2.0 and LGPLv2+ License: ASL 2.0 and LGPLv2+
URL: http://www.jboss.org/xnio URL: http://www.jboss.org/xnio
@ -18,6 +18,9 @@ BuildRequires: mvn(org.wildfly.common:wildfly-common)
Patch0001: 0001-Disable-tests-use-TLSv1-protocol.patch Patch0001: 0001-Disable-tests-use-TLSv1-protocol.patch
Patch0002: 0002-skip-connect-timeout.patch Patch0002: 0002-skip-connect-timeout.patch
Patch0003: 0003-skip-Future-cancel-test-case.patch Patch0003: 0003-skip-Future-cancel-test-case.patch
Patch3000: backport-CVE-2023-5685.patch
%description %description
XNIO is a simplified low-level I/O layer which can be used anywhere you are using NIO today. XNIO is a simplified low-level I/O layer which can be used anywhere you are using NIO today.
It frees you from the hassle of dealing with Selectors and the lack of NIO support for It frees you from the hassle of dealing with Selectors and the lack of NIO support for
@ -67,6 +70,9 @@ rm api/src/test/java/org/xnio/racecondition/ResumeReadsOnHandlingReadableChannel
%files help -f .mfiles-javadoc %files help -f .mfiles-javadoc
%changelog %changelog
* Wed Nov 06 2024 yaoxin <yao_xin001@hoperun.com> - 3.4.0-11
- Fix CVE-2023-5685
* Tue Aug 23 2022 liyanan <liyanan32@h-partners.com> - 3.4.0-10 * Tue Aug 23 2022 liyanan <liyanan32@h-partners.com> - 3.4.0-10
- skip cancelAcceptStreamConnection test case - skip cancelAcceptStreamConnection test case