The backstory of the Electra jailbreak, and how it eventually turned into a nightmare

Back in December 2017, the async_wake exploit was released by Ian Beer for iOS 11.0 - 11.1.2. Shortly after, some other developers (ninjaprawn and stek29) got Dropbear and some basic tools running by using xerub’s trust-cache injection.

My iPad was sitting unused on 9.3.3 for a while, so I figured I’d update it and see what I could do on 11.1.2. I quickly replaced the bootstrap with some freshly compiled GNU core utilities. Meanwhile, ninjaprawn built an initial payload to inject into amfid to try getting arbitrary executables to load. I then (at the same time as, but independently from Morpheus) figured out we needed to add the platform-application entitlement for our fancy new amfid patch to work, and we were off to the paces.

However, we still couldn’t inject tweaks just yet. Our injector could inject dylibs into SpringBoard, however, library validation prevented our dylibs from working unless they were in trust cache. Furthermore, there were timing issues with the dylibs injecting too late. Something better needed to be done.

I began working on a “jailbreakd” that would take the kernel task port given by async_wake and hold onto it, so we could do modifications in the kernel as needed (by having jailbreakd receive commands over UDP from localhost). Starting off with injecting codesigning flags and injecting entitlements, I was quickly able to disable library validation, and was able to get dylibs loaded. However, we still needed a better solution. With some modifications to our injector, I was able to get injection into launchd working. However, the latest build of substrate (this was back in December 2017, but is still valid as of March 2018) failed to work and was giving vague assertion failures when our own injector was working fine.

I decided to reach out to saurik to see if he was interested in getting substrate working, as it would be a fairly trivial task at this point. However, he stated he was not interested at all. Having come this far (and with the stock icons on my iPad still looking ugly), I decided to start building my own solution. I built my own payloads for launchd and xpcproxy which would inject the necessary DYLD_INSERT_LIBRARIES environment variable and call jailbreakd to fixup entitlements and codesigning as needed.

However, we still needed a library for tweaks to hook method calls, as we couldn’t expect everyone to only rely on bundling fishhook or using the Objective-C runtime directly. With substrate closed source,non-functional and the developer uninterested, I looked out for alternatives and remembered comex’s substitute. Substitute is supported on iOS, however it had previously only been tested on iOS 8, and definitely not in mass-deployment. However, with some further patches to our injector to lower codesigning restrictions, surprisingly substitute worked on iOS 11.

With substitute working, I was able to get Anemone not just running, but almost fully functional on iOS 11. The entire stack was fairly new and in beta, but I decided it would be cool to share it so tweak developers could get tweaks working on iOS 11 while the stack was worked on simultaneously. Thus on January 12, 2018, I released Electra beta 1 - a toolkit that installed Dropbear, GNU coreutilities, Substitute, Tweak Injector (then known as SBInject), PreferenceLoader and Anemone. The beta was contained in /bootstrap to have the least issues and for easy cleanup and upgrade path.

Electra beta 1 (and the async_awake fork it was prior to that) were open source, so Electra received some notable contributions. Contributions were received for setting host special port 4, for loading our own launch daemons, for setting jailbreakd as a launchd service, and for mitigating sandbox restrictions.

All was working well and good, one would think.

However, we quickly ran into some issues. Remember that jailbreakd used UDP for receiving commands. However, UDP could potentially drop packets if too many messages were sent (especially since jailbreakd used NSLog() for debug logging, which could halt the thread and cause packets to drop even on localhost). This was most notable if we attempted to reload all launch daemons, which is necessary for tweaks to load into all processes.

A contribution was received to swap jailbreakd to XPC, in launchd, xpcproxy, and everywhere else. However, I noticed with the XPC changes my test devices froze after 30 minutes of usage. I suspected the issue was with our hack to get XPC working in launchd, so I switched launchd back to UDP. However, we were still left with the problem with packets being dropped. So I decided to implement TCP in launchd and let it use XPC everywhere else. This fixed the issue with packets being dropped as they were simply re-transmitted. However, launch daemons were still getting stuck when we were reloading all of them at once…

Until I realized it was NSLog() that was causing problems all along. With some patches to swap it for fprintf’s, the issue was alleviated and we could reload without any problems, and the freezing issue was gone from my own device, so I decided to release these updates as beta 11.

I ran some stress tests to check the stability of the jailbreak by reloading all launch daemons several times, and it was working perfectly, so I decided it was time we start making it the full jailbreak it could be. I started rebuilding all the dependencies needed to run Debian’s APT and dpkg from the latest upstream sources (from both GNU and Apple/BSD respectively), since the newer sources built fairly easily for iOS, so it made sense to use them rather than using the patches saurik used back on iOS 2.0. I was then provided some scripts by nitoTV to build APT and dpkg. After building a new bootstrap (which had to be extracted to the rootfs, couldn’t sandbox it anymore), I was able to get apt-get working!

With some patches to Cydia (binary patches mind you, since the main Cydia app was near impossible to build), I managed to get it working on iOS 11 with our versions of dpkg, APT, etc. I took a look at my iOS 10 device to see how the packages were set up, and setup the layout for Electra’s packages so that it would be an easy upgrade path, should saurik decide to support iOS 11 and provide updates for it (with possible interchanging of packages, should his also support iOS 11 – this was tested on iOS 10 and does work). As none of saurik’s packages were updated since October 2017, I didn’t expect him to post any updates until he decided to start supporting iOS 11. So I marked Electra’s packages as the versions they really were (since most of the tools were quite possibly a decade newer than saurik’s [being built in 2018 rather than 2009]), and where we were using the same version as saurik’s tools, I incremented the version by 1 and added the “-coolstar” suffix (this was only for APT, uikittools and cydia).

I built Release Candidate builds and began submitting them privately to developers to test, as some wanted a more realistic setup with dpkg and APT to be able to test certain packages. However, with our setup not finalized yet, I didn’t want to make it public, since we could potentially make breaking changes with no upgrade path past one minor RC version (since keeping track of all changes from RC 1 to final release 1.0 could potentially be a huge burden if any major breaking changes were made, as we couldn’t simply wipe /bootstrap and place a new one in). Furthermore, with the SHSH window closed I didn’t want to potentially bootloop devices by overwriting files, so I used tar’s “-k” option to keep existing files.

The situation was already complicated by the fact that the device the jailbreak would be installed to might not have been on stock iOS to begin with (something all other jailbreaks assumed). For example, the “topanga” toolkit installed the iOS 10 bootstrap (which doesn’t work at all on iOS 11 due to usage of 32 bit binaries, which Apple dropped support for in 11). Furthermore, since we configured tar to not overwrite files already on the filesystem, if the filesystem wasn’t clean, our bootstrap could potentially not extract at all, resulting in a messy situation.

I decided to compromise by detecting these problematic files and indicating to the user that they installed “topanga” and needed to either uninstall it somehow or futurerestore their device to stock iOS 11.

However, one of the developers who was given the RC 1.2 build (initial testers only got RC 1.1 due to some delays with RC 1.2′s rollout) decided to leak it. Normally I wouldn’t care about a beta leak, however, with the SHSH window closed, this caused the already sticky situation with topanga to get even worse, as we had to deal with potential users already having the RC that should have been private, especially as the bootstrap layout wasn’t finalized yet.

I decided not to deal with this, especially as it wasn’t an official release, and simply issue warnings against installing the RC, and state that people using the RC may not be able to upgrade as it wasn’t finalized and we could make breaking changes.

This was when everything turned into a nightmare. People on /r/jailbreak and on twitter began spewing all sorts of conspiracy theories about how we were adding “DRM” into Electra by checking for topanga and/or the leaked RC (we actually don’t check for the leaked RC), when these in reality are safety checks. Furthermore, certain individuals on /r/jailbreak were trying to pull out the “that guy’s childish” card on us, when in reality, we have every right not to support such an unclean installation of iOS. (/r/jailbreak moderators, where were you???)

I decided that the noise was enough for the time, so I temporarily deactivated my twitter to work on it privately. Meanwhile, I issued the release candidates out to more developers and testing appeared to go well.

On February 26th, I was then able to finally announce the release of Electra 1.0, as most of the developers I gave the RC’s out to privately didn’t complain about any issues, neither did I notice any issues in my own testing. I even updated my other iOS 10 device (my iPhone 6S) to iOS 11, since I noticed how stable 1.0 was on my iPad Air 2.

A day after, however, saurik decided to push an update for APT (both late at night, and unexpectedly after months of no updates), which was missing 64 bit support or the necessary entitlements entirely, and thus wouldn’t work on iOS 11, breaking Cydia on Electra if the update was installed. As Cydia broke on iOS 11 devices, saurik made a post, which was quickly misinterpreted by a majority of people on reddit (who then created conspiracy theories all over again and filling the subreddit with spam – where are the moderators????). Eventually I was able to address the issue by stopping updates from saurik’s repo (since he indicated he didn’t want to support Electra, and his packages were all non-functional on Electra anyways even if they were downloaded and could actualy cause problems) and by installing the correct APT version in 1.0.2.

Later, however, several iPhone X users and some users of other devices began reporting issues with the device freezing randomly (very similar to what I noticed with the original XPC change before I switched launchd off XPC). These reports ranged from constructive feedback to downright insults. All of this, mind you, was with my own iPhone 6S and iPad Air 2 running perfectly fine.

I suspected the issue could possibly be a bad tweak (as safe mode only protects SpringBoard and backboardd, not system daemons) or a bad launch daemon simply crashing and looping when it was restarted by launchd. As a test I decided to load the broken build of RocketBootstrap (version 1.0.5, before it was fixed in 1.0.6), which was missing the “platform-application” entitlement in rocketd. As expected, rocketd was crash-looping as it was started by launchd and then killed by sandbox for missing the entitlement. This was hogging up plenty of resources and actually also preventing launchd from starting new processes other than rocketd, which also manifested itself in the UI as a significant device slowdown with the device entirely freezing up after a few minutes.

When the problematic tweak removed, the freezing was gone and my device was back to normal, with everything working correctly. I decided to take a survey using Google Forms and noticed a substantial number of the responses had people using pirated tweaks. Normally I don’t care about piracy, however, in situations where the device is unstable, it can be a legitimate problem. Piracy repos, by definition, are re-hosting tweaks (sometimes even free ones), which are often outdated compared to their original source, depending on the repo. Some of them could definitely contain bad launch daemons (e.g. older versions of RocketBootstrap, the current version of Filza, and some other tools) that are missing the necessary entitlement to run on iOS 11.

Thus, I had every right to believe that the issue was caused by tweaks (although I later found out that 1.0.2 did actually have an issue on certain devices from using XPC in xpcproxy). However, many obvious pirates in particular were spamming my social media channels about the very issue, making it very difficult to see any messages from non-pirates. (It’s very easy to ignore a few people, but if they reach the 100′s of people, it becomes very difficult, as their spam takes up most of the visible space when looking at twitter/reddit).

To be clear, I quite frankly don’t care what people install on their own devices; however, it gets annoying when hundreds of people submit bug reports with their device clearly having pirated packages (some of which were outdated and definitely problematic). I made a retortical comment about how blocking piracy repos would make Electra less buggy. This was very much true as it would lower the number of potentially problematic tweaks (as piracy repos often ship outdated tweaks with modified version numbers – see Appsync Unified). However, this also caused huge outcry as people began clamoring thinking I’d permanently block piracy repos; although I don’t care if users are using them. However, they should not have them as they alone can cause the same issue that was also caused by the same bug in the jailbreak at the time.

Meanwhile, a certain prominent developer decided to try claiming I was lying by stating *after the final release* that he was having issues with freezing. (Keep in mind, this developer had access to the release candidates, most definitely downloaded and installed them, and didn’t report a single issue). This developer was being very passive-aggressive when asked for logs and info that would be useful (which he didn’t provide by the way) and was stating he’d rather wait for the tool saurik hinted at, even though Electra was already complete and only needed that bug fix.

With some help from the PokeGo++ developer (thank you), I was able to fix this bug in 1.0.3, confirm the bug was fixed, and make the update available. However, the conspiracy theories from the earlier tweet spiraled out of control both on /r/jailbreak and my personal twitter that it became absolutely insane to try and handle.

As of right now, 1.0.3 is the latest version of Electra with no major known bugs (the launchd issue seems more of an issue with how launchd is implemented on iOS, as daemons shouldn’t crash constantly on iOS). Maybe issues will be discovered and fixed, maybe not. However, 1.0.3 works perfectly on my device as well as many others. The entire situation, unfortunately has become too complicated, as it’s near-impossible to attempt to debug issues that could crop up from 3rd party packages, especially if they can exhibit the same issues that can crop up from a bug in the jailbreak itself. (And the spam from people who think they know more than someone who has actually worked on the jailbreak they’re talking about)

So at the end of the day, while Electra has definitely benefited from being open, it also has ended up becoming a nightmare to maintain, with some reasons that were external, and some that were from Electra being open. However, the amount of spam and hatred I’ve been receiving from conspiracy theorists putting words in my mouth has gotten to a level that it seems better to do devleopment in private and occasionally only pop up to release…