React Native 0.71.3 generates .so files that are not stack canary protected
Description
Spinning up a new project using React Native 0.71.3 will generate various .so files packaged in the Android APK generated when running ./gradlew assembleRelease . Of these .so files, some were found to not be stack canary protected using security tools like MobSF, checksec, or readelf. This happens despite placing the below in my android/app/build.gradle configurations.
externalNativeBuild{ cmake{ cppFlags "-fstack-protector-all" } }
These were the files we found so far: libreact_debug libreact_render_debug libreact_utils libruntimeexecutor
React Native Version
0.71.3
Output of npx react-native info
System: OS: Windows 10 10.0.19045 CPU: (8) x64 11th Gen Intel(R) Core(TM) i5-1145G7 @ 2.60GHz Memory: 2.64 GB / 15.69 GB Binaries: Node: 18.15.0 - C:\Program Files\nodejs\node.EXE Yarn: Not Found npm: 9.5.0 - C:\Program Files\nodejs\npm.CMD Watchman: Not Found SDKs: Android SDK: Not Found Windows SDK: Not Found IDEs: Android Studio: AI-221.6008.13.2211.9619390 Visual Studio: Not Found Languages: Java: 11.0.15.1 - C:\Program Files\Common Files\Oracle\Java\javapath\javac.EXE npmPackages: @react-native-community/cli: ^11.1.2 => 10.2.2 react: ^18.2.0 => 18.2.0 react-native: ^0.71.3 => 0.71.6 react-native-windows: Not Found npmGlobalPackages: react-native: Not Found
Steps to reproduce
- Create new react app
- npm install
- cd android && ./gradlew assembleRelease
- cd app/build/outputs/release/apk/release/
- apktool d app-release.apk
- cd app-release/lib/x86_64
- readelf -s libreact_utils.so OR readelf -S libreact_utils.so
It can be noted here that the libreact_utils.so does not have stack canary symbols or stack_chk_fail function implemented.
Snack, code example, screenshot, or link to a repository
| :warning: | Newer Version of React Native is Available! |
|---|---|
| :information_source: | You are on a supported minor version, but it looks like there's a newer patch available. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases. |
This happens despite placing the below in my android/app/build.gradle configurations.
That happens because those .so files are prebuilt.
You can't specify custom flags as the compilation for those libraries already happened.
If you wish to customize the compilation of those libraries, you should switch to a build from source on Android: https://reactnative.dev/contributing/how-to-build-from-source
@cortinico Thank you for your prompt reply. I'm currently trying to remedy the issue by building from source, but I do understand building from source is not the recommended approach of development and would require the node_modules to not be updated as well.
Sorry if I am not really well-versed on this matter, and am not sure if you would be able to advise, but would like to inquire why these source files are not built with stack canary flags as a default when prebuilt?
It seems to be a common enough use case for security requirements for developers. I understand the intention of the prebuilt files are for quicker build times, but it seems the ability to add these additional configs requires quite an atypical dev flow, as well as lots of additional debugging on the ReactAndroid etc. config files just to force this flag in. Additionally it would not be able to be maintained on version control unless I remove node_modules from .gitignore.
Sorry if I am not really well-versed on this matter, and am not sure if you would be able to advise, but would like to inquire why these source files are not built with stack canary flags as a default when prebuilt?
I've done further investigation and noticed that we do have the -fstack-protector-strong flag set on all the compilation targets.
You can verify this by yourself by cloning the repo and running cd packages/react-native/ && ./gradlew build. The build will run and inside packages/react-native/ReactAndroid/.cxx you'll find the temp of the compilation flags.
Here the flags used for a debug run I did locally for the target react_utils:
# =============================================================================
# Object build statements for SHARED_LIBRARY target react_utils
#############################################
# Order-only phony target for react_utils
build cmake_object_order_depends_target_react_utils: phony || cmake_object_order_depends_target_boost cmake_object_order_depends_target_double-conversion cmake_object_order_depends_target_fmt cmake_object_order_depends_target_folly_runtime cmake_object_order_depends_target_glog cmake_object_order_depends_target_glog_init cmake_object_order_depends_target_react_debug
build ReactCommon/react/utils/CMakeFiles/react_utils.dir/ManagedObjectWrapper.mm.o: CXX_COMPILER__react_utils_Debug /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactCommon/react/utils/ManagedObjectWrapper.mm || cmake_object_order_depends_target_react_utils
DEFINES = -Dreact_utils_EXPORTS
DEP_FILE = ReactCommon/react/utils/CMakeFiles/react_utils.dir/ManagedObjectWrapper.mm.o.d
FLAGS = -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fexceptions -frtti -stdlib=libc++ -g -fno-limit-debug-info -fPIC -Wall -Werror -std=c++17 -fexceptions -frtti -Wpedantic -Wno-gnu-zero-variadic-macro-arguments -DLOG_TAG=\"Fabric\" -DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_MOBILE=1 -DFOLLY_HAVE_RECVMMSG=1 -DFOLLY_HAVE_PTHREAD=1 -DFOLLY_HAVE_XSI_STRERROR_R=1
INCLUDES = -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactCommon -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/glog/exported -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/jni/first-party/fbgloginit/. -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/folly/. -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/double-conversion/. -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/boost/boost_1_76_0 -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/fmt/include
OBJECT_DIR = ReactCommon/react/utils/CMakeFiles/react_utils.dir
OBJECT_FILE_DIR = ReactCommon/react/utils/CMakeFiles/react_utils.dir
build ReactCommon/react/utils/CMakeFiles/react_utils.dir/RunLoopObserver.cpp.o: CXX_COMPILER__react_utils_Debug /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactCommon/react/utils/RunLoopObserver.cpp || cmake_object_order_depends_target_react_utils
DEFINES = -Dreact_utils_EXPORTS
DEP_FILE = ReactCommon/react/utils/CMakeFiles/react_utils.dir/RunLoopObserver.cpp.o.d
FLAGS = -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fexceptions -frtti -stdlib=libc++ -g -fno-limit-debug-info -fPIC -Wall -Werror -std=c++17 -fexceptions -frtti -Wpedantic -Wno-gnu-zero-variadic-macro-arguments -DLOG_TAG=\"Fabric\" -DFOLLY_NO_CONFIG=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_MOBILE=1 -DFOLLY_HAVE_RECVMMSG=1 -DFOLLY_HAVE_PTHREAD=1 -DFOLLY_HAVE_XSI_STRERROR_R=1
INCLUDES = -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactCommon -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/glog/exported -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/jni/first-party/fbgloginit/. -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/folly/. -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/double-conversion/. -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/boost/boost_1_76_0 -I/Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/third-party-ndk/fmt/include
OBJECT_DIR = ReactCommon/react/utils/CMakeFiles/react_utils.dir
OBJECT_FILE_DIR = ReactCommon/react/utils/CMakeFiles/react_utils.dir
# =============================================================================
# Link build statements for SHARED_LIBRARY target react_utils
#############################################
# Link the shared library /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libreact_utils.so
build /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libreact_utils.so: CXX_SHARED_LIBRARY_LINKER__react_utils_Debug ReactCommon/react/utils/CMakeFiles/react_utils.dir/ManagedObjectWrapper.mm.o ReactCommon/react/utils/CMakeFiles/react_utils.dir/RunLoopObserver.cpp.o | /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libglog_init.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libreact_debug.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libfolly_runtime.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libglog.so build/third-party-ndk/double-conversion/libdouble-conversion.a build/third-party-ndk/boost/libboost.a build/third-party-ndk/fmt/libfmt.a || /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libfolly_runtime.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libglog.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libglog_init.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libreact_debug.so build/third-party-ndk/boost/libboost.a build/third-party-ndk/double-conversion/libdouble-conversion.a build/third-party-ndk/fmt/libfmt.a
LANGUAGE_COMPILE_FLAGS = -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security -fexceptions -frtti -stdlib=libc++ -g -fno-limit-debug-info
LINK_FLAGS = -Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,--fatal-warnings -Qunused-arguments -Wl,--no-undefined -Wl,--build-id
LINK_LIBRARIES = /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libglog_init.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libreact_debug.so -llog /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libfolly_runtime.so /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libglog.so build/third-party-ndk/double-conversion/libdouble-conversion.a build/third-party-ndk/boost/libboost.a build/third-party-ndk/fmt/libfmt.a -latomic -lm
OBJECT_DIR = ReactCommon/react/utils/CMakeFiles/react_utils.dir
POST_BUILD = :
PRE_LINK = :
SONAME = libreact_utils.so
SONAME_FLAG = -Wl,-soname,
TARGET_FILE = /Users/ncor/fbsource/xplat/js/react-native-github/packages/react-native/ReactAndroid/build/intermediates/cxx/Debug/335v2y43/obj/arm64-v8a/libreact_utils.so
TARGET_PDB = react_utils.so.dbg
Our security team raised the exact same issue for the same version. They also reported that those libraries are missing the FORTIFY protection. I do see a FORTIFY_SOURCE command line argument though. From this build log it seems like both measures are actually being applied for the prebuilt libs, but then when our security team investigates our app it appears that it actually is not applied. 🤷🏻♂️
Maybe something is going wrong in the build pipeline reverting/overriding these security measures resulting in final .so files that don't have them applied after all?
I do see a FORTIFY_SOURCE command line argument though. From this build log it seems like both measures are actually being applied for the prebuilt libs, but then when our security team investigates our app it appears that it actually is not applied. 🤷🏻♂️
Could you provide more evidence that those flags are missing? How are they investigating the .so files? Is this something we can replicate locally somehow?
Sure. This is from their report.
The affected native libraries are all part of the split_config.arm64_v8a.apk. This file format is a zip file, which could be extracted using an archiving utility. A reverse engineering framework like Rizin11 or Radare212 could be used to verify if exploit mitigations have been enabled for a binary, by using the following command for Rizin:
$ rz-bin -s lib/arm64-v8a/libreact_utils.so|grep _chk
When no mitigations have been enabled, no output is given after execution of the command. If checks have been enabled, an output will look similar to the output below:
$ rz-bin -s lib/arm64-v8a/librrc_view.so|grep _chk
142 0x00010eb0 0x00010eb0 GLOBAL FUNC 16 imp.__vsnprintf_chk
144 0x00010f30 0x00010f30 GLOBAL FUNC 16 imp.__stack_chk_fail
The first line is for the FORTIFY_SOURCE obtain, which adds a check for all dangerous standard functions. The second line is for the stack canary protection.
The following libraries are missing stack canary protection: • lib/arm64-v8a/libreact_utils.so • lib/arm64-v8a/libreact_config.so • lib/arm64-v8a/libreact_debug.so • lib/arm64-v8a/libreact_render_telemetry.so • lib/arm64-v8a/libruntimeexecutor.so • lib/arm64-v8a/libreact_render_debug.so • lib/arm64-v8a/libreanimated.so
The following libraries are missing the FORTIFY protection: • lib/arm64-v8a/libreact_utils.so • lib/arm64-v8a/libreact_config.so • lib/arm64-v8a/libreact_debug.so • lib/arm64-v8a/libreact_render_telemetry.so • lib/arm64-v8a/libruntimeexecutor.so • lib/arm64-v8a/libreact_render_debug.so • lib/arm64-v8a/libreanimated.so • lib/arm64-v8a/libreact_render_leakchecker.so • lib/arm64-v8a/libreactperfloggerjni.so • lib/arm64-v8a/libnative-filters.so • lib/arm64-v8a/libreact_render_scheduler.so • lib/arm64-v8a/libreact_codegen_rncore.so • lib/arm64-v8a/librrc_scrollview.so • lib/arm64-v8a/libreact_render_mounting.so • lib/arm64-v8a/libjsc.so • lib/arm64-v8a/libjsijniprofiler.so • lib/arm64-v8a/libjsinspector.so • lib/arm64-v8a/libreact_render_templateprocessor.so • lib/arm64-v8a/librrc_textinput.so • lib/arm64-v8a/libimagepipeline.so • lib/arm64-v8a/libglog_init.so • lib/arm64-v8a/librrc_unimplementedview.so • lib/arm64-v8a/librrc_text.so • lib/arm64-v8a/liblogger.so • lib/arm64-v8a/libfb.so • lib/arm64-v8a/libreact_render_attributedstring.so • lib/arm64-v8a/libreact_render_graphics.so • lib/arm64-v8a/libreact_render_imagemanager.so • lib/arm64-v8a/libreact_render_componentregistry.so • lib/arm64-v8a/libreact_render_textlayoutmanager.so • lib/arm64-v8a/libreact_render_animations.so • lib/arm64-v8a/librrc_root.so • lib/arm64-v8a/libreact_render_core.so • lib/arm64-v8a/librrc_image.so
Sure. This is from their report.
Thanks this is really valuable. I'd love to have this looked into. Also @kelset do you know someone at Microsoft that might help the investigation?
Also this is up for grab. It's going to be a matter of adding missing flags to CMakeLists.txt files and verifying with rz-bin that those symbols are there as expected
sorry, can't think of anyone MSFT side that can take this up
Hello, our support team raised the same issue for the React Native 0.71.0, tried to use:
externalNativeBuild { cmake { cppFlags "-fstack-protector-all" } }
in android/app/build.gradle under android / defaultConfig but it didn't help in any way.
Hello, our support team raised the same issue for the React Native 0.71.0, tried to use:
externalNativeBuild { cmake { cppFlags "-fstack-protector-all" } }
This obviously has no effect as we distribute prebuilts, so you can't add new cppFlags as the compilation already happened on CI.
I identified a potential bug in the NDK that is causing this. I believe version 0.72 of React Native will fix this issue, so I ask you to try again once we'll have a stable version out.
Hi @cortinico , I am also being to repro the same issue on React Native 0.71. Do we know whether react native 0.72 fixes this problem? If so, can we also maybe back port the fix to RN 0.71? fyi - @kelset
Just FYI I think we can do this much easily even without using rz-bin.
Steps below (MAC):
- Extracting an apk using any archiver (I personally rename the extension to .zip and use mac's default archiver to extract it)
- Navigate inside the
/lib/arm-xyzfolder. - Create a new shell script e.g. soChecker.sh with the following code
for file in *; do
echo $file
strings $file | grep 'stack_chk_fail'
done
- chmodx +x ./soChecker.sh
- ./soChecker.sh
This will print "__stack_chk_fail" for all files which have stack smash protection enabled. For files which do not have this, it will just print the file name.
The strings command will look for all printable strings inside the $file and pipe it to the adjacent grep command.
Do we know whether react native 0.72 fixes this problem? If so, can we also maybe back port the fix to RN 0.71?
Yes I believe 0.72 will fix this issue to some degree. Can someone try the latest RC of 72 and report back if there are some libraries that are still not stack protected?
@cortinico let me check that.
@cortinico @kelset @dragorwyin
I downloaded ReactAndroid~0.72-rc6 from maven and it looks like the following .so files are still not stack protected.
libreact_config.so libreact_debug.so libreact_render_debug.so libreact_render_telemetry.so libreact_utils.so libruntimeexecutor.so
These not-stack-protected .so files are common for all architectures (arm68-v8a, armeabi-v7a, x86, x86_64).
@cortinico @kelset @dragorwyin this PR: https://github.com/facebook/react-native/pull/38018 should solve the stack_chk_fail part of this issue.
I downloaded
ReactAndroid~0.72-rc6from maven and it looks like the following.sofiles are still not stack protected.
Could you clarify which file in the .aar is not stack protected (as there are several called libreact_config.so, one per architecture + one per prefab/non-prefab)?
Hello, as it's essential to my team, I need to ask: what is the estimated fixing date for this one? If there is any?
Hello, as it's essential to my team, I need to ask: what is the estimated fixing date for this one? If there is any?
There are no ETAs
@cortinico I am not sure what prefab/non-prefab is but the "__stack_chk_fail" string is missing for the above shared objects in all architectures. x86, x86_64, armeabi-v7a and arm68-v8a
@cortinico I am not sure what prefab/non-prefab is but the "__stack_chk_fail" string is missing for the above shared objects in all architectures. x86, x86_64, armeabi-v7a and arm68-v8a
What I mean is that if you download this file: https://repo1.maven.org/maven2/com/facebook/react/react-android/0.72.0/react-android-0.72.0-release.aar
and unzip it, search for libreact_render_debug.so you will have 8 of them:
jni/arm64-v8a/libreact_render_debug.so
jni/armeabi-v7a/libreact_render_debug.so
jni/x86/libreact_render_debug.so
jni/x86_64/libreact_render_debug.so
prefab/modules/react_render_debug/libs/android.arm64-v8a/libreact_render_debug.so
prefab/modules/react_render_debug/libs/android.armeabi-v7a/libreact_render_debug.so
prefab/modules/react_render_debug/libs/android.x86/libreact_render_debug.so
prefab/modules/react_render_debug/libs/android.x86_64/libreact_render_debug.so
which one have you checked @SparshaSaha ?
as for example, I just checked jni/arm64-v8a/libreact_render_debug.so and I could see a __stack_chk_fail so I'm unsure what are you looking at.
Let me take a look again. I will report back here once I have an answer
@cortinico I just downloaded the release 0.72 and I checked jni/arm64-v8a/lib_react_render_debug.so.
But unfortunately I do not see any stack_chk_fail string inside it. I am not sure how we are seeing different things on the same .so. I might be doing something wrong.
I used the $strings command then then piped it into grep.
To confirm once again, I tried to search for it by opening the file in a code editor.
But unfortunately I do not see any stack_chk_fail string inside it. I am not sure how we are seeing different things on the same
.so.
You're correct. That was my fault. I was looking at a stale .aar I had downloaded previously. We're looking into doing the NDK 25 update that will potentially fix this issue in the immediate future
Hello, just kindly pinging ;) Any update here or is it stuck? Thank you!
Hello, just kindly pinging ;) Any update here or is it stuck? Thank you!
Currently blocked by this:
- https://github.com/facebook/react-native/pull/37974