High severity7.5NVD Advisory· Published Mar 22, 2024· Updated Apr 15, 2026
CVE-2023-5685
CVE-2023-5685
Description
A flaw was found in XNIO. The XNIO NotifierState that can cause a Stack Overflow Exception when the chain of notifier states becomes problematically large can lead to uncontrolled resource management and a possible denial of service (DoS).
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.jboss.xnio:xnio-apiMaven | < 3.8.14.Final | 3.8.14.Final |
Patches
1ffabdcdda508[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
1 file changed · +187 −51
api/src/main/java/org/xnio/AbstractIoFuture.java+187 −51 modified@@ -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,136 +378,138 @@ 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; } 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; } 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; } }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
14- github.com/advisories/GHSA-7f88-5hhx-67m2ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-5685ghsaADVISORY
- access.redhat.com/errata/RHSA-2023:7637nvdWEB
- access.redhat.com/errata/RHSA-2023:7638nvdWEB
- access.redhat.com/errata/RHSA-2023:7639nvdWEB
- access.redhat.com/errata/RHSA-2023:7641nvdWEB
- access.redhat.com/errata/RHSA-2024:10207nvdWEB
- access.redhat.com/errata/RHSA-2024:10208nvdWEB
- access.redhat.com/errata/RHSA-2024:2707nvdWEB
- access.redhat.com/security/cve/CVE-2023-5685nvdWEB
- bugzilla.redhat.com/show_bug.cginvdWEB
- github.com/xnio/xnio/blob/3.8.13.Final/api/src/main/java/org/xnio/AbstractIoFuture.javaghsaWEB
- github.com/xnio/xnio/commit/ffabdcdda508ef87aeadad5ca3f854e274d60ec1ghsaWEB
- issues.redhat.com/browse/XNIO-423ghsaWEB
News mentions
0No linked articles in our index yet.