
Why I’m not enabling Bitcode - sinak
https://medium.com/@FredericJacobs/why-i-m-not-enabling-bitcode-f35cd8fbfcc5?
======
tptacek
_an adversary could find a vulnerability in the LLVM backend to obtain remote
code execution on Apple’s Bitcode compilation infrastructure to inject a
compiler trojan that would affect every single app on the App Store that was
submitted with Bitcode_

I'm not clear on how Bitcode changes this, apart from expanding the already
huge attack surface of the app store. Code execution inside app store servers
is already game over for end-user privacy, isn't it?

The bit about how Bitcode makes backdoor injection harder is also very hand-
wavy, since backdoor injection into fully compiled binaries is a teenaged
pastime going back to the late 1980s. About the most you can say here is that
Bitcode makes a trivial task trivial-er.

The concern about introducing side-channels into crypto apps seems legitimate
(though: if you believe this is a real issue, and I do too, you're also saying
"I will never trust Javascript cryptography"). I wouldn't want Signal
submitting Bitcode.

~~~
tedunangst
Are you aware of any side channels introduced by compiler optimizations that
weren't present in unoptimized code? Recompiling with -O0 vs -O2 doesn't seem
likely to fix your pkcs padding bug. Or hmac strcmp.

~~~
pbsd
Very small one, but (taken from [1]):
[http://goo.gl/M8XThn](http://goo.gl/M8XThn) vs
[http://goo.gl/RZZf1N](http://goo.gl/RZZf1N)

[1]
[https://cryptocoding.net/index.php/Coding_rules#Compare_secr...](https://cryptocoding.net/index.php/Coding_rules#Compare_secret_strings_in_constant_time)

~~~
tedunangst
Interesting. Looks like it affects all version of llvm (at least those that
compile).

I guess with LTO the result could be the same, but asking to always inline
seems like asking the compiler to fuse operations, and then it sees shortcuts.
Dunno.

~~~
pbsd
`always_inline` is only there to make -O0 smaller for presentation purposes.
It has no impact on -O2.

The trick here is that -march=i386 predates CMOV, and that LLVM specializes
code emitting for bool (and _Bool). If the secret bit were an uint32_t, there
wouldn't be a branch anymore.

~~~
tedunangst
Oh! I did not look closely enough to see that this was c++ with bool. Now I am
even less worried. :)

~~~
pbsd
Yeah, I'm not too worried either.

There is one class of cryptographic code, however, that is entirely unsuitable
to distribute in Bitcode---DPA/EM-protected code. EM attacks on middle-end ARM
chips have been demonstrated recently [1, 2].

Protecting against these attacks usually involves splitting the computation
into 2 or more "shares" (see, for example, [3]); these require strict control
of which register each word goes into, and which registers overwrite which.
This cannot be enforced in Bitcode---or any other bytecode, for that matter---
and direct assembly must be used.

[1] [https://eprint.iacr.org/2015/561](https://eprint.iacr.org/2015/561)

[2] [http://cr.yp.to/talks/2014.09.25-2/slides-
dan+tanja-20140925...](http://cr.yp.to/talks/2014.09.25-2/slides-
dan+tanja-20140925-2-4x3.pdf)

[3]
[http://keccak.noekeon.org/NoteSideChannelAttacks.pdf](http://keccak.noekeon.org/NoteSideChannelAttacks.pdf)

------
devit
I don't think there any additional security issues regarding Apple altering
the binaries.

iOS devices are already running a closed source proprietary OS, which can
easily set an hardware breakpoint in a binary and then do anything that could
be done by modifying the binary itself without leaving traces anywhere (other
than timing and cache effects).

Apple even designs and manufactures the CPU so they could even modify the CPU
to detect instruction patterns and siphon off private keys without any
detectable timing or cache effects at all.

Of course, that doesn't mean that it's all fine, but rather that the system is
already completely broken to begin with in this respect.

~~~
sneak
Yeah, this is important.

As much as I'd like to be upset about the lack of binary verifiability
throughout the chain, as the article even points out, without jailbreaking it
is already impossible. We have no idea what code Apple is telling our devices
to run, regardless of the form in which it is submitted to the App Store.

It's a bummer, but rms was right all along.

------
mikeash
The security implications of new compiler optimizations potentially
eliminating security-essential code really interest me. As do the plain old
reliability implications of hitting new compiler bugs.

It's going to be really really really Fun with a capital PH when Apple enables
some new optimization that contains a subtle bug, and recompiles everybody's
apps, and us third parties are left holding the bag trying to figure out why
our apps are crashing with no visibility whatsoever into the process.

~~~
ris
How is this significantly different from shipping java/dalvik/whatever
bytecode?

~~~
notacoward
The real issue is who gets to sign the code. Formerly, you could sign the code
yourself, so the cryptographic "chain of custody" between you and your users
would be preserved. Now, since Apple generates the code that users see, you
can't check and sign it. Apple can sign it, somebody who has compromised
Apple's infrastructure can sign it, but you can't (unless you're the one who
compromised their infrastructure). So, basically, this is a giant MITM just
waiting to be exploited.

~~~
NateLawson
Apple already re-signs all apps sent through the App Store. That plus Fairplay
encryption makes it unnecessarily difficult for end recipients to verify the
chain of custody for the code.

I don't quite get why Xcode couldn't generate both the LLVM bitcode + the fat
binary for all architectures, along with any flags. Then Apple could
regenerate the same binary (to verify the two match) but use the bitcode for
their program analysis tools. Then, the developer's signature could be left
intact on the binary and Apple would add an additional signature over the
whole thing that indicated it was approved for distribution via the App Store.

~~~
eridius
Because Apple explicitly wants to be able to regenerate binaries from the
bitcode, which means that any locally-generated binary is meaningless. The
claimed reason for this is to take advantage of new optimizations added to
LLVM (which is a perfectly sensible thing to take advantage of), but probably
the more useful reason is to take advantage of new microarchitectures that
Apple introduces in new devices.

~~~
NateLawson
Yes, this is the real thing that should be debated -- where does the
developer's responsibility end and the App Store's begin?

If I created an app, both distributed internally (say, to my corporate users)
and via the App Store, but the App Store version has a bug because they're
using a different ARM backend than my Xcode, that will be a real pain to
debug.

------
api
He's right, but he's almost too right: absolutely everything he says is a
problem with bitcode applies to normal app store distribution and all other
centralized cloud-powered OSes and apps. Therefore I don't see this as a good
argument against bitcode -- not using bitcode does not prevent anything he
says from occurring since anything that can be done to bitcode can be done to
machine code.

(1) Apple has the signing master keys for app store certificates. It would be
easy for them to binary-patch your app with anything they want, generate their
own signing certificate in your name, and re-sign the app as they push it out
to users. Since app store transactions are on a per-customer basis this could
be done only for some customers -- such as only residents of a certain
country, people whose names are on a list, etc. It's very unlikely that anyone
would notice.

(2) It would also be easy for an attacker to do this if they compromised
Apple's core infrastructure as described in this article. Then they could
generate signing certs in other developers' names and trojanize apps in
exactly the same way. A "doomsday hack" that trojanized all Apple devices in
the world within hours is not impossible. If they all started, say, DDOSing
core BGP and DNS systems at the same time, such an attack could take down the
entire Internet.

(3) Apple, since they control the platform and can remotely patch it at any
time, needn't bother with trojanizing apps. They could simply trojanize the OS
kernel or user-space OS components and accomplish anything a trojanized app
accomplishes.

The same also applies, by the way, to Windows and also to Linux if you trust
remote code repositories and do not compile everything yourself from verified
known-safe source code. It also applies to from-source-compiled OSes and
distributions _if you did not painstakingly check every line of code
yourself_. Google the "underhanded C contest."

If you run code that is not yours, you are trusting someone else. It's a
subset of a larger principle: civilization implies trust. Without trust you
cannot have specialization of labor, commerce, or law. Without those there
could be no advanced technology or infrastructure, so none of this would
matter.

To use an Apple device is to trust Apple, at least insofar as that device and
any data you keep on it goes. To use Ubuntu and its repositories implies the
same level of trust in Canonical, etc.

The privacy problems of the digital age are not entirely technical in nature
and do not have entirely technical solutions. They can only really be solved
legislatively and socially.

~~~
SomeCallMeTim
>The same also applies, by the way, to Windows and also to Linux if you trust
remote code repositories

Curiously, Google/Android has developers sign the app, and that exact signed
package is what's distributed, so _at least_ the app developer can verify that
the distributed app is identical to the one shipped to the store.

On the other hand, Amazon/Android signs apps with their own keys, so they
suffer from the same issue as Apple.

~~~
joosters
Users don't check the signature of apps that they download, their phone does
it for them.

So even if apps are signed by the developer, the app store owner can throw
away the signature, modify the app and then sign it with their own key. People
downloading and running the app won't see a difference.

~~~
SomeCallMeTim
If a developer downloads the app, they can verify it.

But more to the point, I published an app on the Play Store that actually
_verified its own signatures_ (as an anti-piracy measure) and it worked
correctly. Not only that, but it used the signature as a key to decrypt some
of the assets, so a changed signature would mean the app would completely fail
to work.

So it's a solvable problem on Android. But not at all on other ecosystems.

------
nfg
Something we're a little worried about (shipping middleware for games on iOS)
is the potential difficulty of debugging client issues when we don't (I
assume?) have native binary identical libs.

~~~
seivan
Oh shit, I never thought of this. You just make middleware, and not the game
themselves? Is this integrated into SpriteKit on iOS or a standalone lib?

~~~
nfg
Just standalone libs. It will be interesting to see how much trouble it
causes.

------
nekitamo
There are intellectual property concerns. You are now giving Apple your LLVM
IR along with the program symbols. What happens if you have sensitive code in
your application that you don't want Apple reverse engineering and having
access to?

LLVM bitcode also limits the kind of tamper resistance and obfuscation you can
put into your apps. Fairplay offers almost no security if your attacker has a
jailbroken device. He can simply dump the decrypted app from memory and
reverse enegineer it. If you care about protecting your secrets, or preventing
your app from being pirated and redistributed on Chinese app stores, you could
at least apply fairly sophisticated obfuscation & integrity checks to the app
binary. With LLVM bitcode that all becomes much harder, and applying integrity
checks to the app becomes impossible.

Also, Apple doesn't really need the LLVM bitcode of the app to carry out app
thinning. All they really need to do is extract the proper architecture from a
FAT binary, and send that to the user's device, instead of the entire FAT
binary.

It makes me wonder what will they even be using the LLVM bitcode for? Will it
become a requirement for all apps submitted to the app store sometime in the
future? If so, why?

~~~
tptacek
There is nothing that the LLVM ARM backend is going to emit that Apple, or
most security consultancies, can't trivially reverse engineer.

~~~
nekitamo
Reverse engineering machine code is not trivial if it is obfuscated, has its
symbols stripped, and has its ObjectiveC metadata obfuscated/encrypted.

LLVM bitcode is much easier to reverse engineer than machine code, and you
will be handing Apple all your symbols and metadata as well.

~~~
dymk
Symbols are obfuscated or removed entirely if you choose to build without
them; you don't have to hand Apple your .dSYM if you don't want. I'm not sure
what other metadata you're referring to.

~~~
nekitamo
I am referring to ObjectiveC metadata, which programs like IDA Pro can use to
identify function names/parameters, which give valuable insights to reverse
engineers.

With LLVM bitcode, it doesn't matter if you don't hand over your .dSYM file to
Apple, all the symbol information (and more!) is available in the bitcode.

~~~
tptacek
There is metadata in a fat binary (or in bitcode) that makes reversing _more
convenient_ , but there is none that makes reversing _possible_ ; reversing
raw ARM assembly spat out by a normal compiler backend is _always possible_.

It's 2015. Lack of source code is no longer a meaningful obstacle for
attackers.

~~~
nekitamo
I agree, reverse engineering is always possible :) However, reverse
engineering with the LLVM bitcode present is much much easier, which is a
problem.

Also, if Apple requires apps to be submitted as LLVM bitcode, then certain
things like integrity checks and certain useful types of obfuscation will
become impossible, making apps much easier to reverse engineer, or to pirate
and repackage on another app store.

~~~
NateLawson
I disagree that LLVM bitcode makes reverse-engineering any easier on iOS. You
can do everything in bitcode that you can do in native ARM code. The
limitations are already there in terms of code signing, sandboxing, and page
protection and bitcode distribution doesn't change any of these OS attributes.

Are you concerned about _Apple_ reversing your code? You can still use
arbitrary types (e.g. int64 instead of a pointer) and give them no additional
data about the structure of your code. As you pointed out elsewhere, tools
like OLLVM perform obfuscation at the bitcode level already.

I'm guessing Apple made this change to make it easier to do program analysis
of iOS apps being published. You can certainly find bugs easier in bitcode
that has proper type information and clear differentiation between safe and
unsafe branches. One of the first steps in program analysis tools is to lift
native code to an IR in order to determine its correctness.

With bitcode distribution, Apple has potentially made it easier on themselves
to skip the lifting and type recovery steps _for conforming apps_ in order to
look for bugs. But unless they start requiring bitcode conform to certain
additional standards, you can always transform bitcode to obfuscated bitcode,
destroy type information via aliasing, etc.

~~~
nekitamo
I concede that LLVM bitcode can be obfuscated just like machine code ( with
enough effort, and LLVM bugs aside ) . However, you're still losing the
ability to self-checksum your code, which in turn means you can't protect
against things like piracy or unwanted modification of your binary.

I agree also that Apple probably made this change to better analyze programs
being submitted to the app store. That and to recompile programs to use
intrinsics more efficiently, as new intrinsics become available.

And finally, while I would not be concerned about Apple reversing my code,
certain companies are and have to undertake steps to make that as difficult as
possible.

~~~
NateLawson
Yes, self-checksumming becomes impossible [1].

If you are concerned about anyone reversing your code (Apple or otherwise),
you must obfuscate it. Either you work at the ARM level or the bitcode level
(watchOS for now), but the basic techniques are the same. Or, you can avoid
changing tools by doing source-level transformation.

One of the companies probably impacted by this change is Arxan or other
obfuscators. They have to change both front and backend to be LLVM -> LLVM.

[1] Except for the case I mentioned before, where you predict the generated
code for known architectures and use that to generate your constants. This
still breaks if Apple generates code for a new architecture without your help.

------
azinman2
Does anyone know more, or have a link to more info, about the problems with
dSYM and bitcode?

------
teambob
Aside from the security - Apple made much of write once run anywhere being a
terrible idea (e.g. Java, Flash and iOS/Android frameworks) yet now it is a
fabulous idea that Apple just thought of

------
draw_down
Obviously you're welcome to do what you like. But it seems how these things go
with Apple is: they introduce it, and it's optional, then they build on it
some (still optional), then they say "using this is a _really_ good idea",
then they say "a year from now you have to use this". And maybe not a year. So
you're free to exercise your choice... for a while.

~~~
coldtea
Any example of some other thing that went that way?

And no, the transition to 64 bit or Swift are not that.

~~~
draw_down
Java-Objc bridge, requiring Xcode (people used to use Metrowerks and other
tools). I don't do this for my day job so there are probably lots of others...
something around ARC maybe?

~~~
coldtea
OK, I though you meant some kind of evil plan, lockdown etc impossed to people
by Apple progressively. That's why I said we should exclude ARC and transition
to Swift. I meant in general that we shouldn't count "migration to newer
technologies/frameworks" as such a thing.

If you meant, Apple imposing newer stuff to developers, then yes Apple does
that.

Though, I'd say most of that is for the platform's good. Even stuff like
deprecating Java -- it never got popular for OS X apps as Apple intented, the
situation with SUN had changed, and keeping it going forward would be dead
weight.

And Metrowerks might be good for early '00s, but not going forward with iOS,
and multiple languages, and Storyboards, and all those things.

~~~
BlunderX
Still, the forced transition is PITA for anyone who has had a successful app
on the AppStore for several years. Essentially, you are being forced making a
new app every other year, just to have an app, in spite of the fact that the
old one(s) work perfectly well and everyone is happy with them. In my book,
that is throwing money - it's cost us half the price to keep three other
competing platforms afloat.

And I find it disheartening that most developers seem so accepting of
unnecessary costs to their time and health. Much like the worker class before
the unions - any work conditions go. I for one am pretty tired of years of
iOS-update introduced incidents and overtime work to manage new products,
while juggling undue maintenance on old products. I also find it disheartening
developer companies don't take a good look at costs and demand improvements,
instead of accepting a steady trickle of punishment for success.

If it is for the platform's good, I wish the platform ended so we can develop
for platforms that deliver better working conditions and less motivated
uncertainty, fear, and doubt.

