我们的Android软件使用了一个用于SQLite的虚拟文件系统(VFS),该系统一直正常工作。一旦我们开始在Android 6(棉花糖)中使用它,就开始出现各种奇怪的错误,向ftruncate()传递大的负偏移、堆栈溢出、数据损坏等。使用readelf
(以及其他工具),我们最终将问题归结为libsqlite.so
使用的导入的变化:棒棒糖和早期的导入ftruncate
和mmap
,最新的库导入CCD_ 5和CCD_。我们通过根据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.zip和https://github.com/android/platform_external_sqlite/blob/master/dist/sqlite3.cC
源调用的都是ftruncate
和mmap
,这使得我们的方法论充其量是"有问题的"。
libsqlite.so
如何导入和使用源代码仅调用ftruncate
和mmap
的ftruncate64
和mmap64
?我们是否没有查看正确的源代码存储库?链接步骤发生了什么事情吗?棉花糖删除了对这些函数的非64位版本的支持吗?
事实证明,NDK中的标头与OS的相应标头并不完全匹配用构建!
仿生:https://android.googlesource.com/platform/bionic.git/+/棉花糖发布/libc/include
以下是构建NDK的方法:https://android.googlesource.com/platform/ndk/+/棉花糖释放
特别是
https://android.googlesource.com/platform/bionic.git/+/棉花糖发布/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/+/marshmallowrelease/libc/include/sys/man.h对mmap
有类似的宏-系统头文件中的__RENAME()
意味着任何使用系统头文件构建的代码(例如libc.so
)都只导出ftruncate64
,而不是ftruncate
。当调用ftruncate
的应用程序链接到libc.so
时,它会导入ftruncate64
,而不是编写源代码时使用的调用。
我们并没有深入研究__RENAME()
宏来研究这种魔力是如何发生的——试图将产品推出市场的现实阻碍了我们进入兔子洞的深度。然而,如果有人想进一步调查这件事,这就是你的出发点。