In any case, I assume that there is something similar affecting Android.
I would natively imagine the kernel could trap that and remap on the fly, at the tiny cost of murdering performance. Is that untrue, or is the perf so bad that it's not worth it?
In the worst case, ~every memory access causes the kernel to need to fix it, causing every memory access to be several orders of magnitude worse (e.g. a hot cache hit vs trapping into kernel, wiping caches, at the very least hundreds more accesses).
EDIT: I see you suggested remapping the page permissions. Maybe that helps! But maybe it adds the cost of the remapping onto the worst case, e.g. the first 4kb are instructions that write into the second 4kb.
They literally remove almost 50% total android app earlier this year, they clearly devoted to quality and security
https://android-developers.googleblog.com/2022/04/expanding-...
You have to update an application every year, even if it is just meaningless version bump. Otherwise it will be removed after 2 years. Despite saying that this policy is required to ensure user security, several recent Android releases didn't have any corresponding major security changes.
It could be that Google explicitly wants to dump un(der) maintained apps. Sure some might be clean and basic utilities that will work till the end of time, but many are probably abandonware or crummy demos and hello-world apps that look old and dated. They went on a whole purge recently already.
The App Store market is changing as Google/Apple grapple with efforts to end their monopolies. Maybe they're seeing that change and trying to use their dying advantage to frame themselves as the curated and reputable stores with high-quality maintained and up to date apps. When distribution is available from other places, they can chose their customers.
I realize that most apps wouldn’t need to make changes and that a recompilation would suffice, but is this time frame enough for the apps that do need code changes?
They only added support in android 15, in august 2024. https://android-developers.googleblog.com/2024/08/adding-16-...
I don't know what "targetting Android 15+" means specifically. Does that include anything with a lower API level?
- On Android, apps are built with targetSdkVersion set to the API version you're app is compiled for and tested against, but you cam set a lower minSdkVersion to the lowest device API version your app will run on.
- On devices with API level newer than targetSdkVersion, the OS looks at your app's targetSdkVersion and disables newer behaviours than your app is targetting. So the app should run well on newer devices.
- On devices with API level older than targetSdkVersion, but newer than (or same as) minSdkVersion, your own app is responsible for detecting missing APIs before trying to use them, and adapting itself to the older environment.
- On devices with API level older than minSdkVersion, your app will not be run. This ensures the user gets a clear failure, rather than unpredictable crashes or unexpected behaviour due to missing APIs the app tries to call.
So, in principle, it's possible to build an app which targets the most recent Android 15, while being capable of running on all versions of Android back to version 1. Apps linked for 16 kiB page-alignment should run on older devices that use 4 kiB pages too.
The Google Play Store enforces that targetSdkVersion is fairly close to the latest Android version. But it doesn't place requirements on minSdkVersion.
What typically tends to break when changing it?
If you rely on being able to do things like mark a range of memory as read-only or executable, you now have to care about page sizes. If your code is still assuming 4KB pages you may try to change the protection of a subset of a page and it will either fail to do what you want or change way too much. In both cases weird failures will result.
It also can have performance consequences. For example, if before you were making a lot of 3.5KB allocations using mmap, the wastage involved in allocating a 4KB page for each one might not have been too bad. But now those 3.5KB allocations will eat a whole 16KB page, making your app waste a lot of memory. Ideally most applications aren't using mmap directly for this sort of thing though. I could imagine it making life harder for the authors of JIT compilers.
Some algorithms also take advantage of the page size to do addressing tricks. For example, if you know your page size is 4KB, the addresses '3' and '4091' both can be known to have the same protection flags applied (R/W/X) and be the same kind of memory (mmap'd file on disk, shared memory segment, mapped memory from a GPU, etc.) This would allow any tables tracking information like that to only have 4KB granularity and make the tables much smaller. So that sort of trick needs to know the page size too.
Everything's ok until some obscure library suddenly segfaults without any error
If you have a 4KB segment that is marked Read-Write followed immediately by a Read-Execute, naively loading it will open a can of security issues.
Moreover many platform data structures like Global Object Table of the dynamic executable uses addresses. You cannot simply bump things around.
On top of that libraries like C++ standard library (or abseil from Google) rely on the page size to optimize data structures like hash maps (i.e. unordered_map).
If your code that created two guard pages sandwiching a security critical page to make sure that under/overruns caused a page fault and crashed that assumed the boundary was at 4KiB, but is really now at 16KiB, that means that buffer overruns now will not get caught.
Further, code that assumed it was on a page boundary for some reason, for performance reasons, will now have only a 25% chance of being so.
It also means that MMIO physical pages that were expected to be contained within a 4KiB page such that when mapped into a sensitive user space driver context, neighboring MMIO control blocks wouldn't be touched, might be affected too since you'll get up to 3 neighboring blocks in either direction. This probably doesn't happen so often, I don't know Android internals much, but still something to consider.
This is in large part because PAGE_SIZE in a lot of C code is a macro or constant, rather than something populated at runtime depending on the system the code is running - something I've always felt is a bit problematic.
Applications should assume the page size is 1 byte. One should be able to map, protect, etc memory ranges down to byte granularity - which is the granularity of everything else in computers. One fewer thing for programmers to worry about. History has shown that performance hacks with ongoing complexity tend not to survive (eg. interlaced video).
At the hardware level, rather than picking a certain number of bits of the address as the page size, you have multiple page tables, and multiple TLB caches - eg. one for 1 megabyte pages, one for 4 kilobyte pages, and one for individual byte pages. The hardware will simultaneously check all the tables (parallelism is cheap in hardware!).
The benefit of this is that, assuming the vast majority of bytes in a process address space are made of large mappings, you can fit far more mappings in the (divided up) TLB - which results in better performance too, whilst still being able to do precise byte-level protections.
The OS is the only place there is complexity - which has to find a way to fit the mappings the application wants into what the hardware can do (ie. 123456 bytes might become 30 4-kilobyte pages and 576 byte pages.).
But you can do this, you simply have to pay the cost of using PAGE_SIZE of memory per byte you want to protect?
userbinator•6h ago
https://www.kernel.org/doc/html/next/arm64/memory.html
jeffbee•6h ago
https://developer.arm.com/documentation/101811/0104/Translat...
ryao•5h ago
tux3•1h ago
On a phone with limited RAM, this starts to be a bad tradeoff quickly. 16K is a reasonable jump from the venerable 4K page size.