From a3bfa6f1ab492f1564b7d256f5b31496de3a974d Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 5 May 2023 02:56:51 +0200 Subject: [PATCH] ui: collect logs from IO thread only Otherwise the pop() from the producer might causes an OOB read in the consumer: Exception java.lang.ArrayIndexOutOfBoundsException: at androidx.collection.CircularArray.get (CircularArray.java) at com.wireguard.android.activity.LogViewerActivity.rawLogBytes (LogViewerActivity.java) at com.wireguard.android.activity.LogViewerActivity.onCreate$lambda$3 (LogViewerActivity.java:133) at android.view.View.performClick (View.java:6935) at android.view.View$PerformClick.run (View.java:26214) at android.os.Handler.handleCallback (Handler.java:790) at android.os.Handler.dispatchMessage (Handler.java:99) at android.os.Looper.loop (Looper.java:164) at android.app.ActivityThread.main (ActivityThread.java:7000) at java.lang.reflect.Method.invoke at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:441) at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1408) Signed-off-by: Jason A. Donenfeld --- .../android/activity/LogViewerActivity.kt | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt b/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt index 9deed440..37f4dcb6 100644 --- a/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt +++ b/ui/src/main/java/com/wireguard/android/activity/LogViewerActivity.kt @@ -112,19 +112,21 @@ class LogViewerActivity : AppCompatActivity() { } binding.shareFab.setOnClickListener { - revokeLastUri() - val key = KeyPair().privateKey.toHex() - LOGS[key] = rawLogBytes() - lastUri = Uri.parse("content://${BuildConfig.APPLICATION_ID}.exported-log/$key") - val shareIntent = ShareCompat.IntentBuilder(this) + lifecycleScope.launch { + revokeLastUri() + val key = KeyPair().privateKey.toHex() + LOGS[key] = rawLogBytes() + lastUri = Uri.parse("content://${BuildConfig.APPLICATION_ID}.exported-log/$key") + val shareIntent = ShareCompat.IntentBuilder(this@LogViewerActivity) .setType("text/plain") .setSubject(getString(R.string.log_export_subject)) .setStream(lastUri) .setChooserTitle(R.string.log_export_title) .createChooserIntent() .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - grantUriPermission("android", lastUri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - revokeLastActivityResultLauncher.launch(shareIntent) + grantUriPermission("android", lastUri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + revokeLastActivityResultLauncher.launch(shareIntent) + } } } @@ -151,11 +153,13 @@ class LogViewerActivity : AppCompatActivity() { private val downloadsFileSaver = DownloadsFileSaver(this) - private fun rawLogBytes() : ByteArray { + private suspend fun rawLogBytes() : ByteArray { val builder = StringBuilder() - for (i in 0 until rawLogLines.size()) { - builder.append(rawLogLines[i]) - builder.append('\n') + withContext(Dispatchers.IO) { + for (i in 0 until rawLogLines.size()) { + builder.append(rawLogLines[i]) + builder.append('\n') + } } return builder.toString().toByteArray(Charsets.UTF_8) }