【问题标题】:Heap Corruption - SEGV_MAPERR in Android Native code堆损坏 - Android 本机代码中的 SEGV_MAPERR
【发布时间】:2014-05-04 22:25:01
【问题描述】:

我正在尝试为流 AES 加密创建一个小型库,我基于 Facebook Conceal 项目 (https://github.com/facebook/conceal) 开始了我的工作,只是更改了一些内容并改进了本机周围的包装器以支持带有填充的密码。

它正在工作,它可以毫无问题地解密文件,但是当我处理大型流时,我会遇到随机堆内存损坏,并且经过大量时间调试后,我无法找到错误。

这是我的代码:
https://gist.github.com/frisco82/9782725

我试图找到内存分配或空闲问题,但几乎没有 malloc 或空闲,jni 调用应该是安全的,openssl 也是如此(我自己编译了但隐藏提供的也失败了)

CheckJni 不会发出任何警告,虽然上下文处理有点开箱即用,但它似乎并没有损坏(实际上,Android conscrypt 似乎使用了类似的东西)。

此外,如果有人可以将我指向 Android 原生 AES 多步(多次更新调用)库,我将切换到该库并忘记这一点。

错误不时变化,但通常与他的相似:

03-26 10:33:02.065: A/dalvikvm(2475): @@@ ABORTING: DALVIK: HEAP MEMORY CORRUPTION IN mspace_malloc addr=0x0
03-26 10:33:02.065: A/libc(2475): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 2494 (AsyncTask #1)
03-26 10:33:02.205: I/DEBUG(933): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-26 10:33:02.205: I/DEBUG(933): Build fingerprint: 'generic_x86/google_sdk_x86/generic_x86:4.4.2/KK/999428:eng/test-keys'
03-26 10:33:02.205: I/DEBUG(933): Revision: '0'
03-26 10:33:02.205: I/DEBUG(933): pid: 2475, tid: 2494, name: AsyncTask #1  >>> com.proton <<<
03-26 10:33:02.205: I/DEBUG(933): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad

完整的堆栈跟踪:
http://pastebin.com/f6mDuQEj

【问题讨论】:

  • 崩溃转储的其余部分在哪里?您需要检查堆栈跟踪并与您的程序进行比较以了解故障。
  • 添加了带有几条痕迹的馅饼,但由于这是内存损坏,因此在发现损坏时,strack 痕迹不会显示错误,这就是为什么这要复杂得多。
  • 只是好奇,为什么隐藏不适合你?如果您在 github 上提出问题,我可能会提供帮助。
  • @user868459 好吧,我需要使用支持多种密钥长度的 AES CBC PKCS5,因为我们的 android 应用程序只是用于不同平台的几个应用程序之一,加密文件可以在它们之间共享。今天我将发布我的更改,因为最终解决了这个问题。
  • @frisco 我明白了。如果您能提交一份包含您的特定用例和解决方法的报告,将不胜感激。这将帮助我们决定 Conceal 可以提供什么样的支持来支持该案例:github.com/facebook/conceal/issues?state=open

标签: android c encryption openssl java-native-interface


【解决方案1】:

它正在工作,它可以毫无问题地破译文件,但我明白了 处理大型流时随机堆内存损坏。

在我看来,您的程序显然正在覆盖由您的代码隐式或显式分配的内存。我试图理解你的代码,但我不清楚。但是我尝试从内存损坏的情况来看,发现你的程序确实有 malloc/free 调用,这可能会导致内存溢出。

EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX*) malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);

EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX*) malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);

我尝试检查 EVP_CIPHER_CTX 结构 的布局,但它在您的代码中不可用。但是我看到这些指针在您的程序中的各种上下文中得到使用。现在您应该检查在哪种情况下您的缓冲区可以被覆盖,因为某些地方您使用了不同的 keyLength 并且取决于此您的程序正在执行不同的功能。我想你可能想查看这些代码,看看是否可能溢出!!!....

由于您的应用程序将在基于 android 的系统上运行,因此我们无法运行任何动态工具(Valgrind/WinDBG/Pageheap..),所以我想您需要通过将一些日志放在重要位置来查看您的代码并查看您的位置正在覆盖。

希望以上信息对您了解您的问题有所帮助。

【讨论】:

  • EVP_CIPHER_CTX 和所有 EVP 调用都是对 openssl 库的调用,实际上我在没有使用该 malloc 的情况下使用 EVP_CIPHER_CTX_new() 在内部进行了 malloc 测试,但没有运气。我知道如果没有事先的 openssl 知识,代码不是很清晰,但它只是 openssl 库的 init、update 和 final 函数的接口。
  • @frisco:嗯,我的解释只是提供一些输入,以便您可以继续,因为代码不容易理解。您提到您已经尝试过并排除了它。好吧,我无法弄清楚任何额外的东西,所以没有什么可以补充我在之前的回复中提到的内容。
  • 不,别担心,我没有排除任何可能,我已经尝试了很多,但我开始怀疑一切:D 感谢您的评论
【解决方案2】:

毕竟我能够解决这个问题,EVP_CipherUpdate(或 jni ReleaseByteArrayElements)有时会溢出输出缓冲区导致堆损坏,我的代码中没有任何问题,而且调用者也没有问题将 EVP_CipherUpdate 替换为具有相同参数的 memcpy 调用按预期工作,并且没有堆损坏。

因此解决方案是向发送到 nativeUpdate 的输出缓冲区添加一些额外的长度,并且错误消失了。

我已经制作了库的完整工作版本供其他人在以下位置使用: https://github.com/frisco82/conceal

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-02-10
    • 1970-01-01
    • 2010-11-15
    相关资源
    最近更新 更多