Reputation: 1202
I'm building Unison (a file synchronization executable) for Android using the Android r10e NDK, but this isn't really an Android question.
Android > 5.0 (SDK 21) requires executables to be position-independent. So I pass -pie to arm-linux-androideabi-gcc while compiling, which works:
% hardening-check ./unison
./unison:
Position Independent Executable: yes
...
This works fine on Android 5.0 devices.
Android > 6.0 (SDK 21) still requires executables to be position-independent, but also requires executables to be built without text relocations. So I pass -fPIC to arm-linux-androideabi-gcc while compiling, and it appears to build a binary without text relocations:
% arm-linux-androideabi-readelf -a ./unison |& grep TEXTREL
(no output is shown)
The problem is, I can only satisfy one requirement at a time. If I use -pie and -fPIC together, the resulting executable is position-independent (yay!), but also has text relocations (boo!):
% hardening-check ./unison
./unison:
Position Independent Executable: yes
...
% arm-linux-androideabi-readelf -a ./unison |& grep TEXTREL
0x00000016 (TEXTREL) 0x0
0x0000001e (FLAGS) TEXTREL BIND_NOW
...and Android 6.0 devices refuse to run it:
% adb push unison /data/local/tmp
% adb shell '/data/local/tmp/unison -version'
WARNING: linker: /data/local/tmp/unison has text relocations. This is wasting memory and prevents security hardening. Please fix.
CANNOT LINK EXECUTABLE: can't protect segments for "/data/local/tmp/unison": Permission denied
What's the special sauce needed to get these flags to work together? Or, alternatively, what am I missing? Are PIC and PIE mutually exclusive?
Thanks!
Edit:
I am manually walking through the same process that the OPAM repo goes through to build Unison for Android. Namely:
Build the ocaml cross compilers.
Pull down the Unison source.
Apply a patch:
--- pty.c~ 2010-04-15 19:29:31.000000000 +0200
+++ pty.c 2013-01-16 19:28:56.258812188 +0100
@@ -10,7 +10,7 @@
extern void uerror (char * cmdname, value arg) Noreturn;
// openpty
-#if defined(__linux)
+#if defined(__linux) && !defined(__ANDROID__)
#include <pty.h>
#define HAS_OPENPTY 1
#endif
--- Makefile.OCaml~ 2013-01-16 19:27:10.686807807 +0100
+++ Makefile.OCaml 2013-01-16 19:29:46.814814286 +0100
@@ -136,7 +136,9 @@
# openpty is in the libutil library
ifneq ($(OSARCH),solaris)
ifneq ($(OSARCH),osx)
- CLIBS+=-cclib -lutil
+ ifneq ($(OSCOMP),android)
+ CLIBS+=-cclib -lutil
+ endif
endif
endif
buildexecutable::
Build with:
% make \
UISTYLE=text \
OCAMLOPT="arm-linux-androideabi-ocamlopt -verbose -ccopt '-fPIC -pie'" \
OSCOMP=android
The above process builds a PIE executable that runs fine on Android 5, but fails on Android 6 because it has text relocations. Removing "-pie" above build a binary without text relocations, but is not a PIE executable so it won't run on Android 5 or 6.
Upvotes: 3
Views: 5364
Reputation: 1988
Just to add that for some people seeing this question, thinking it matches their problem perfectly,
text relocations despite -fPIC?
will be the correct answer. In short, after double checking all your "C" code settings, don't forget assembly code problems.
Upvotes: 1
Reputation: 13317
The flags you're using should be right, although I haven't tried using the ocaml (cross) compiler. On a large, pure C codebase, I manage to build PIE executables without text relocations, by passing -fPIC
during compilation and -fPIE -pie
during linking.
The way you describe that the flags override each other sounds weird. My guess is that it somehow comes from how the ocaml frontend pass them on to the backend tools via the -ccopt
parameter. The -pie
flag is a linker flag, so it shouldn't need to be passed to the compilation steps at all. And if it isn't passed to the compilation steps, the generated code should be identical to before, it's only the linking step that should change, right?
Can you check which object files actually contain text relocations, and what compiler options they are built with? (I'm not sure if this is visible anywhere, I assume it's called internally by ocamlopt
.) If none of the individual object files contain text relocations, it seems like they would come from some of the ocaml specific object files that get linked in?
Upvotes: 0
Reputation: 821
I was stuck with something similar after the release of Lollipop. Since that moment, the use of PIE executable has been mandatory in order to ensure a better ASLR.
Provided that you can live with only 4.1+ support, a simple solution is just set APP_PLATFORM := android-16
.
By doing that,the compiler will activate the -fPIE flag at some stage.
This could be a very straightforward example of how your Application.mk migh look.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
APP_PLATFORM := android-16
APP_OPTIM : = release
APP_ABI := armeabi
include $(BUILD_EXECUTABLE)
Upvotes: 0