GrapheneOS rooted and served via its own OTA server on GitHub pages
MIT License
GrapheneOS over the air updates (OTAs) patched with Magisk using avbroot allowing for AVB and locked bootloader and root access. Provides its own OTA server for Custota magisk module.
⚠️ OS and root work in general. However, zygisk does not (and likely never will) work, leading to magisk being easily discovered by other apps and lots of banking apps not working. See bellow for alternatives.
avb_pkmd.bin
from this repo.Download factory image and follow the official instructions to install GrapheneOS.
TLDR:
Enable OEM unlocking
Obtain latest fastboot
Unlock Bootloader:
Enable usb debugging and execute adb reboot bootloader
, or
> The easiest approach is to reboot the device and begin holding the volume down button until it boots up into the bootloader interface.
fastboot flashing unlock
flash factory image
bsdtar xvf DEVICE_NAME-factory-VERSION.zip # tar on windows and mac
./flash-all.sh # or .bat on windows
Stop after that and reboot (leave bootloader unlocked)
avbroot ota extract \
--input /path/to/ota.zip.patched \
--directory extracted
extracted/
, except for system
.
cd extracted
for img_file in *.img; do
partition_name=$(basename "$img_file" .img)
if [ "$partition" == "system" ]; then
continue
fi
fastboot flash "$partition_name" "$img_file"
done
system
:
fastboot reboot fastboot
fastboot flash system system.img
fastboot reboot-bootloader
fastboot erase avb_custom_key
curl -s https://raw.githubusercontent.com/schnatterer/rooted-graphene/main/avb_pkmd.bin > avb_pkmd.bin
fastboot flash avb_custom_key avb_pkmd.bin
adb shell su -c 'dmesg | grep libfs_avb'
If AVB is working properly, the following message should be printed out:
init: [libfs_avb]Returning avb_handle with status: Success
fastboot flashing lock
OEM unlocking
!adb sideload
:
No command
message, press the volume up button once while holding down the power button.Apply update from ADB
. Confirm by pressing power buttonadb sideload xyz.zip
In order to remove root, you can change to the "rootless" flavor.
To do so, set the following URL in custota: https://schnatterer.github.io/rooted-graphene/rootless/
Note that you can update to this flavor to disable root. However, after the upgrade, custota will no longer work. For re-enabling root, you will have to use adb sideload
.
In the future we might find a way to include an updater to the OTA, so rooting will also be possible via custota.
You can use the script in this repo to create your own OTAs and run your own OTA server.
# Generate keys
bash -c 'source rooted-ota.sh && generateKeys'
# Enter passphrases interactively
DEVICE_ID=oriole MAGISK_PREINIT_DEVICE='metadata' bash -c '. rooted-ota.sh && createRootedOta'
# Enter passphrases via env (e.g. on CI)
export PASSPHRASE_AVB=1
export PASSPHRASE_OTA=1
DEVICE_ID=oriole MAGISK_PREINIT_DEVICE='metadata' bash -c '. rooted-ota.sh && createRootedOta'
For IDs see grapheneos.org/releases. For Magisk preinit see,e.g. here.
See GitHub actions for automating this:
GITHUB_TOKEN=gh... \
GITHUB_REPO=schnatterer/rooted-graphene \
DEVICE_ID=oriole \
MAGISK_PREINIT_DEVICE=metadata \
bash -c '. rooted-ota.sh && createAndReleaseRootedOta'
As magisk does not seem a perfect match for GrapheneOS, you might be looking for alternatives.
I had a first go at patching kernelsu which booted but did not provide root. There even are some artifacts to try.
Patching kernelsu is much more complex that patching magisk. It might even be impossible to run GrapheneOS with it, without building GrapheneOS from scratch.
Also, some parts of kernelsu seem to be closed source, which feels suspicious and inappropriate for a tool with so much influence on your device.
Another alternative might be to use a version of magisk (like the one maintained by pixincreate) that contains patches to make zygisk work. This still has some limitations, like certain modules checking for magisk's signature won't work.
In general, using magisk and especially zygisk with Graphene seems to have the risk of breaking things with every new release. It's good to have the rootless version as a fallback!
# DEBUG some parts of the script interactively
DEBUG=1 bash --init-file rooted-ota.sh
# Test loading secrets from env
PASSPHRASE_AVB=1 PASSPHRASE_OTA=1 bash -c '. rooted-ota.sh && key2base64 && KEY_AVB=doesnotexist createAndReleaseRootedOta'
# Avoid having to download OTA all over again: SKIP_CLEANUP=true or:
mkdir -p .tmp && ln -s $PWD/shiba-ota_update-2023121200.zip .tmp/shiba-ota_update-2023121200.zip
# Test only releasing
GITHUB_TOKEN=gh... \
RELEASE_ID='' \
ASSET_EXISTS=false \
POTENTIAL_RELEASE_NAME=test \
POTENTIAL_ASSET_NAME=test.zip \
GITHUB_REPO=schnatterer/rooted-ota \
bash -c '. rooted-ota.sh && releaseOta'
# Test only GH pages deployment
GITHUB_REPO=schnatterer/rooted-ota \
DEVICE_ID=oriole \
MAGISK_PREINIT_DEVICE=metadata \
bash -c '. rooted-ota.sh && findLatestVersion && checkBuildNecessary && createOtaServerData && uploadOtaServerData'
# e2e test
GITHUB_TOKEN=gh... \
GITHUB_REPO=schnatterer/rooted-ota \
DEVICE_ID=oriole \
MAGISK_PREINIT_DEVICE=metadata \
SKIP_CLEANUP=true \
DEBUG=1 \
bash -c '. rooted-ota.sh && createAndReleaseRootedOta'
See release-multiple.yaml for examples.
How to extract:
avbroot ota extract \
--input /path/to/ota.zip \
--directory . \
--boot-only
Pre-init storage partition device ID: <name>
avbroot boot magisk-info \
--image magisk_patched-*.img
https://github.com/MuratovAS/grapheneos-magisk/blob/main/docker/Dockerfile
https://xdaforums.com/t/guide-to-lock-bootloader-while-using-rooted-otaos-magisk-root.4510295/