Otagowane wskaźniki

Począwszy od Androida 11 wszystkie alokacje stosu w procesach 64-bitowych mają tag zdefiniowany przez implementację w górnym bajcie wskaźnika na urządzeniach z obsługą jądra dla ARM Top-byte Ignore (TBI). Każda aplikacja, która modyfikuje ten tag, jest zamykana, gdy zostanie sprawdzona podczas zwalniania pamięci. Jest to konieczne w przypadku przyszłego sprzętu z obsługą rozszerzenia ARM Memory Tagging Extension (MTE).

Ignorowanie najwyższego bajta

Funkcja ignorowania najwyższego bajtu ARM jest dostępna dla kodu 64-bitowego na wszystkich procesorach Armv8 AArch64. Oznacza to, że sprzęt ignoruje najwyższy bajt wskaźnika podczas dostępu do pamięci.

TBI wymaga kompatybilnego jądra, które poprawnie obsługuje otagowane wskaźniki przekazywane z przestrzeni użytkownika. Jądra Android Common od wersji 4.14 (Pixel 4) lub nowszej zawierają wymagane łatki TBI.

Urządzenia z wsparciem TBI w jądrze są wykrywane dynamicznie w momencie rozpoczęcia procesu, a w pierwszym bajcie wskaźnika dla wszystkich alokacji stosu jest wstawiany tag zależny od implementacji. Następnie przeprowadzana jest weryfikacja, aby upewnić się, że podczas dealokacji pamięci nie został obcięty żaden tag.

Gotowość rozszerzenia Memory Tagging

Rozszerzenie Memory Tagging Extension (MTE) firmy ARM pomaga rozwiązywać problemy z bezpieczeństwem pamięci. MTE działa poprzez oznaczanie 56–59 bitów adresu każdej alokacji pamięci na stosie, stosie i w pamięci globalnej. Zestaw sprzętowy i zestaw instrukcji automatycznie sprawdza, czy podczas każdego dostępu do pamięci jest używany prawidłowy tag.

Aplikacje na Androida, które nieprawidłowo przechowują informacje w górnym bajcie wskaźnika, zawsze się nie uruchomią na urządzeniu z obsługą MTE. Oznaczone znacznikiem wskaźniki ułatwiają wykrywanie i odrzucanie nieprawidłowego użycia najwyższego bajta wskaźnika przed udostępnieniem urządzeń MTE.

Pomoc dla programistów

Jeśli aplikacja uległa awarii i wyświetlił się ten link, może to oznaczać jedno z tych zdarzeń:

  1. Aplikacja próbowała zwolnić wskaźnik, który nie został przydzielony przez systemowy alokator stosu.
  2. Coś w Twojej aplikacji zmodyfikowało najwyższy bajt wskaźnika. Górnego bajta wskaźnika nie można zmodyfikować, więc aby rozwiązać ten problem, trzeba zmienić kod.

Przykłady nieprawidłowego użycia lub zmodyfikowania wskaźnika najwyższego bajta.

  • Wskaźniki na konkretny typ mają metadanychy aplikacji przechowywane w 16 najstarszych bitach adresu.
  • Przekształcenie wskaźnika na podwójny, a potem z powrotem, co powoduje utratę niższych bitów adresu.
  • Kod obliczający różnicę między adresami zmiennych lokalnych z różnych ramek stosu jako sposób pomiaru głębokości rekurencji.

Niektóre aplikacje mogą być zależne od bibliotek, które działają nieprawidłowo, gdy ustawiony jest najwyższy bajt wskaźnika. Zdajemy sobie sprawę, że szybkie rozwiązanie tych problemów w bibliotekach może być trudne. W związku z tym aplikacje korzystające z targetSdkLevel < 30 nie będą domyślnie miały włączonego tagowania kursora. Aby ułatwić okres przejściowy, udostępniamy też aplikacjom utworzonym za pomocą targetSdkLevel >= 30 opcję ominięcia.

Aby użyć luku awaryjnego, dodaj do pliku AndroidManifest.xml te informacje:

  <application android:allowNativeHeapPointerTagging="false">
  ...
  </application>

Spowoduje to wyłączenie w Twojej aplikacji funkcji oznaczania wskaźników. Nie rozwiąże to jednak problemu z jakością kodu. W przyszłych wersjach Androida ta funkcja zniknie, ponieważ tego typu problemy będą niezgodne z MTE.