android: native - hold charon_mutex while reading routing engine stats
getRoutingStats/getDeadDirectTargets are polled from the UI once a second; a concurrent disconnect frees the engine under charon_mutex, so reading it without the lock was a use-after-free. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5e38fc2f76
commit
793ca1b410
1 file changed
+11
-2
@@ -1325,16 +1325,21 @@ JNI_METHOD(CharonVpnService, setUserspaceRoutingData, void,
|
|||||||
*/
|
*/
|
||||||
JNI_METHOD(CharonVpnService, getRoutingStats, jlongArray)
|
JNI_METHOD(CharonVpnService, getRoutingStats, jlongArray)
|
||||||
{
|
{
|
||||||
direct_engine_t *engine = direct_engine_get();
|
direct_engine_t *engine;
|
||||||
direct_stats_t s = {};
|
direct_stats_t s = {};
|
||||||
jlong v[22];
|
jlong v[22];
|
||||||
jlongArray result;
|
jlongArray result;
|
||||||
|
|
||||||
memset(&s, 0, sizeof(s));
|
memset(&s, 0, sizeof(s));
|
||||||
|
/* polled from the UI: a concurrent disconnect frees the engine under
|
||||||
|
* charon_mutex, so the pointer may only be used while holding it */
|
||||||
|
pthread_mutex_lock(&charon_mutex);
|
||||||
|
engine = direct_engine_get();
|
||||||
if (engine)
|
if (engine)
|
||||||
{
|
{
|
||||||
engine->get_stats(engine, &s);
|
engine->get_stats(engine, &s);
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&charon_mutex);
|
||||||
v[0] = (jlong)s.tunnel_pkts;
|
v[0] = (jlong)s.tunnel_pkts;
|
||||||
v[1] = (jlong)s.tunnel_bytes;
|
v[1] = (jlong)s.tunnel_bytes;
|
||||||
v[2] = (jlong)s.direct_pkts;
|
v[2] = (jlong)s.direct_pkts;
|
||||||
@@ -1370,7 +1375,7 @@ JNI_METHOD(CharonVpnService, getRoutingStats, jlongArray)
|
|||||||
*/
|
*/
|
||||||
JNI_METHOD(CharonVpnService, getDeadDirectTargets, jobjectArray)
|
JNI_METHOD(CharonVpnService, getDeadDirectTargets, jobjectArray)
|
||||||
{
|
{
|
||||||
direct_engine_t *engine = direct_engine_get();
|
direct_engine_t *engine;
|
||||||
direct_dead_target_t t[DIRECT_DEAD_MAX];
|
direct_dead_target_t t[DIRECT_DEAD_MAX];
|
||||||
jobjectArray result;
|
jobjectArray result;
|
||||||
jclass cls;
|
jclass cls;
|
||||||
@@ -1379,10 +1384,14 @@ JNI_METHOD(CharonVpnService, getDeadDirectTargets, jobjectArray)
|
|||||||
/* stack snapshot: zero it so no field can ever leak garbage */
|
/* stack snapshot: zero it so no field can ever leak garbage */
|
||||||
memset(t, 0, sizeof(t));
|
memset(t, 0, sizeof(t));
|
||||||
|
|
||||||
|
/* same race against a concurrent disconnect as getRoutingStats() */
|
||||||
|
pthread_mutex_lock(&charon_mutex);
|
||||||
|
engine = direct_engine_get();
|
||||||
if (engine)
|
if (engine)
|
||||||
{
|
{
|
||||||
n = engine->get_dead_targets(engine, t, DIRECT_DEAD_MAX);
|
n = engine->get_dead_targets(engine, t, DIRECT_DEAD_MAX);
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&charon_mutex);
|
||||||
cls = (*env)->FindClass(env, "java/lang/String");
|
cls = (*env)->FindClass(env, "java/lang/String");
|
||||||
if (!cls)
|
if (!cls)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user