F-5714: hold WolfSSLX509Name lock across setSubjectName native call

pull/389/head
Chris Conlon 2026-07-22 15:22:38 -06:00
parent e6fb3844a4
commit 844c9a9013
2 changed files with 69 additions and 3 deletions

View File

@ -127,7 +127,8 @@ public class WolfSSLCertRequest {
* @param name Initialized and populated WolfSSLX509 name to be set into
* Subject Name of WolfSSLCertRequest for cert generation.
*
* @throws IllegalStateException if WolfSSLCertRequest has been freed.
* @throws IllegalStateException if WolfSSLCertRequest has been freed, or
* if the provided WolfSSLX509Name has been freed.
* @throws WolfSSLException if native JNI error occurs.
*/
public void setSubjectName(WolfSSLX509Name name)
@ -142,9 +143,12 @@ public class WolfSSLCertRequest {
WolfSSLDebug.INFO, this.x509ReqPtr,
() -> "entered setSubjectName(" + name + ")");
/* TODO somehow lock WolfSSLX509Name object while using pointer? */
ret = X509_REQ_set_subject_name(this.x509ReqPtr,
/* Synchronize on the name so its free() can't release the native
* pointer during the call below. */
synchronized (name) {
ret = X509_REQ_set_subject_name(this.x509ReqPtr,
name.getNativeX509NamePtr());
}
}
if (ret != WolfSSL.SSL_SUCCESS) {

View File

@ -32,6 +32,8 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.security.PublicKey;
import java.security.PrivateKey;
@ -725,4 +727,64 @@ public class WolfSSLCertRequestTest {
throws IOException {
Files.write(new File(path).toPath(), csr);
}
/* setSubjectName() holds the WolfSSLX509Name lock across the native call
* so a concurrent free() cannot free the pointer mid-call. Races the two
* operations to check concurrency safety and deadlock-freedom of the added
* locking, tolerating the expected exceptions when free() wins the race. */
@Test(timeout = 60000)
public void testSetSubjectNameFreeRace()
throws WolfSSLException, WolfSSLJNIException, InterruptedException {
Assume.assumeTrue(WolfSSL.certReqEnabled());
final int iterations = 200;
final AtomicReference<Throwable> failure =
new AtomicReference<Throwable>();
for (int i = 0; i < iterations && failure.get() == null; i++) {
final WolfSSLCertRequest req = new WolfSSLCertRequest();
final WolfSSLX509Name name = GenerateTestSubjectName();
final CountDownLatch start = new CountDownLatch(1);
Thread setter = new Thread(new Runnable() {
public void run() {
try {
start.await();
req.setSubjectName(name);
} catch (IllegalStateException | WolfSSLException e) {
/* expected if free() won the race */
} catch (Throwable t) {
failure.compareAndSet(null, t);
}
}
});
Thread freer = new Thread(new Runnable() {
public void run() {
try {
start.await();
name.free();
} catch (Throwable t) {
failure.compareAndSet(null, t);
}
}
});
setter.start();
freer.start();
start.countDown();
setter.join();
freer.join();
name.free();
req.free();
}
if (failure.get() != null) {
throw new AssertionError(
"unexpected error during setSubjectName/free race",
failure.get());
}
}
}