2

我们的Android软件为SQLite使用了一个虚拟文件系统(VFS),它一直在正常工作。一旦我们开始在Android 6(Marshmallow)中使用它,各种奇怪的错误开始发生,传递给ftruncate(),堆栈溢出,数据损坏等的负偏移量很大。使用readelf(和其他工具),我们最终跟踪问题到libsqlite.so使用的进口变化:棒棒糖和较早的进口ftruncatemmap,最新的库进口ftruncate64mmap64。我们通过改变“解决”这个问题我们使用取决于API版本的功能(棉花糖是版本23):当源代码调用ftruncate时,Android Marshmallow libsqlite.so如何使用ftruncate64?

/* 
* 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进口和使用ftruncate64mmap64其中源代码仅调用ftruncatemmap?我们没有看到正确的源代码库吗?在链接步骤中发生了什么?棉花糖是否取消了对这些功能的非64位版本的支持?

回答

1

事实证明NDK中的标题并不完全匹配OS所用的相应标题!

仿生: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()宏观中来研究这种魔法是如何发生的 - 试图让产品离开门的现实阻止了我们可以在兔子洞下跌多深。如果有人想进一步调查,那么这就是你开始的地方。