2

我们的 Android 软件使用 SQLite 的虚拟文件系统 (VFS),该系统一直正常工作。一旦我们开始在 Android 6 (Marshmallow) 上使用它,就会开始出现各种奇怪的错误,将大的负偏移量传递给 ftruncate()、堆栈溢出、数据损坏等。使用readelf(以及其他工具),我们最终追踪到了问题更改使用的导入libsqlite.so:棒棒糖和更早的导入ftruncatemmap,最新的库导入ftruncate64mmap64。我们通过根据 API 版本(Marshmallow 是 23 版)更改我们使用的函数来“解决”这个问题:

/*
 * Empirical testing of Tab S2 running Marshmallow revealed the SQLite
 * unix_syscall table uses "ftruncate" and "mmap" as connection points,
 * but the actual functions linked against are the *64 versions.  This
 * leads to stack corruption and all sorts of nasty errors as a result.
 */
if (getApiVersion() >= 23)  // for Marshmallow
{   setUnixSystemCall(NULL, "ftruncate", our_ftruncate64);
    setUnixSystemCall(NULL, "mmap", our_mmap64);
}
else                        // for Lollipop & older
{   setUnixSystemCall(NULL, "ftruncate", our_ftruncate);
    setUnixSystemCall(NULL, "mmap", our_mmap);
}

查看来自http://www.sqlite.org/2015/sqlite-amalgamation-3081002.ziphttps://github.com/android/platform_external_sqlite/blob/master/dist/sqlite3.c的源代码C消息来源是ftruncatemmap这使得我们的方法充其量是“有问题的” 。

如何libsqlite.so导入和使用ftruncate64以及mmap64源代码只调用ftruncatemmap?我们不是在查看正确的源代码存储库吗?链接步骤是否发生了什么?Marshmallow 是否删除了对这些函数的非 64 位版本的支持?

4

1 回答 1

1

事实证明,NDK 中的标头与构建操作系统的相应标头不完全匹配!

仿生: https ://android.googlesource.com/platform/bionic.git/+/marshmallow-release/libc/include

这是构建 NDK 的方法: https ://android.googlesource.com/platform/ndk/+/marshmallow-release

尤其是,

https://android.googlesource.com/platform/bionic.git/+/marshmallow-release/libc/include/unistd.h

#if defined(__USE_FILE_OFFSET64)
extern int truncate(const char *, off_t) __RENAME(truncate64);
extern off_t lseek(int, off_t, int) __RENAME(lseek64);
extern ssize_t pread(int, void *, size_t, off_t) __RENAME(pread64);
extern ssize_t pwrite(int, const void *, size_t, off_t) __RENAME(pwrite64);
extern int ftruncate(int, off_t) __RENAME(ftruncate64);

https://android.googlesource.com/platform/bionic.git/+/marshmallow-release/libc/include/sys/mman.h具有类似的宏mmap-__RENAME() 系统标头中的意味着使用系统标头构建的任何代码(例如,libc.so)只会导出ftruncate64,而不是ftruncate,当调用的应用程序ftruncate链接到时libc.so,它会导入ftruncate64而不是编写源代码的调用。

我们没有__RENAME()深入研究这种魔法是如何发生的——试图将产品推向市场的现实限制了我们可以深入兔子洞。但是,如果有人想进一步调查,这就是你的起点。

于 2016-08-04T21:42:36.013 回答