2

Unsere Android-Software verwendet ein virtuelles Dateisystem (VFS) für SQLite, das korrekt funktioniert hat. Sobald wir begannen, es mit Android 6 (Marshmallow) zu verwenden, begannen alle Arten von seltsamen Fehlern aufzutreten, mit großen negativen Offsets, die an ftruncate(), Stapelüberläufen, Datenbeschädigungen usw. übergeben wurden. Unter Verwendung von readelf (unter anderen Tools) verfolgten wir schließlich die Problem zu einer Änderung der Importe von libsqlite.so verwendet: Lollipop und früher importieren ftruncate und mmap, importieren die neuesten Bibliotheken ftruncate64 und mmap64. Wir „gelöst“ das Problem, indem Sie die Funktionen, die wir auf der API-Version verwenden abhängig (Eibisch ist Version 23):Wie verwendet Android Marshmallow libsqlite.so ftruncate64, wenn die Quelle ftruncate aufruft?

/* 
* 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); 
} 

Mit Blick auf den Quellcode sowohl von http://www.sqlite.org/2015/sqlite-amalgamation-3081002.zip und https://github.com/android/platform_external_sqlite/blob/master/dist/sqlite3.c alles, was die C Quelle nennt ftruncate und mmap, was unsere Methodik bestenfalls "fragwürdig" macht.

Wie libsqlite.so Import und Verwendung ftruncate64 und mmap64 wo der Quellcode nur ftruncate und mmap nennt? Schauen wir uns nicht das richtige Quellcode-Repository an? Ist bei einem Link-Schritt etwas los? Hat Marshmallow die Unterstützung für die Nicht-64-Bit-Versionen dieser Funktionen entfernt?

Antwort

1

Es stellt sich heraus, dass die Header im NDK nicht genau mit den entsprechenden Headern übereinstimmen, mit denen das Betriebssystem gebaut wurde!

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

Hier ist der Weg, um das NDK BUILD: https://android.googlesource.com/platform/ndk/+/marshmallow-release

Insbesondere

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 hat ähnliche Makros für mmap - die __RENAME()in die Systemheader bedeutet, dass jeder Code gebaut, um die System-Header verwendet (zum Beispiel libc.so) nur ftruncate64 exportieren, nicht ftruncate, und wenn eine Anwendung, die ftruncate ruft gegen libc.so verknüpft ist, es importiert stattdessen ftruncate64 anstatt der Aufruf der Quellcode mit geschrieben wurde.

Wir haben uns nicht in das __RENAME() Makro vertieft, um zu untersuchen, wie diese Magie passiert - die Realität des Versuchs, ein Produkt aus der Tür zu bekommen, verbietet, wie tief wir in das Kaninchenloch eindringen können. Wenn jemand das weiter untersuchen will, hier fängt man an.