libbinder: support TF_CLEAR_BUF

This flag instructs the kernel to clear transactions from send/reply
buffers for certain transactions which may contain sensitive data, as a
security precaution.

Bug: 171501998
Test: binderLibTest (only checks there is no error)
Change-Id: I69d732e5cc2b15472dc52d47c66716bc1b3be6ae
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 27cf97c..feeb819 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -49,6 +49,7 @@
 
 #include <private/binder/binder_module.h>
 #include "Static.h"
+#include "Utils.h"
 
 #define LOG_REFS(...)
 //#define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
@@ -502,6 +503,11 @@
     return mHasFds;
 }
 
+void Parcel::markSensitive() const
+{
+    mDeallocZero = true;
+}
+
 void Parcel::updateWorkSourceRequestHeaderPosition() const {
     // Only update the request headers once. We only want to point
     // to the first headers read/written.
@@ -2627,6 +2633,9 @@
             LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
             gParcelGlobalAllocSize -= mDataCapacity;
             gParcelGlobalAllocCount--;
+            if (mDeallocZero) {
+                zeroMemory(mData, mDataSize);
+            }
             free(mData);
         }
         if (mObjects) free(mObjects);
@@ -2649,6 +2658,21 @@
             : continueWrite(std::max(newSize, (size_t) 128));
 }
 
+static uint8_t* reallocZeroFree(uint8_t* data, size_t oldCapacity, size_t newCapacity, bool zero) {
+    if (!zero) {
+        return (uint8_t*)realloc(data, newCapacity);
+    }
+    uint8_t* newData = (uint8_t*)malloc(newCapacity);
+    if (!newData) {
+        return nullptr;
+    }
+
+    memcpy(newData, data, std::min(oldCapacity, newCapacity));
+    zeroMemory(data, oldCapacity);
+    free(data);
+    return newData;
+}
+
 status_t Parcel::restartWrite(size_t desired)
 {
     if (desired > INT32_MAX) {
@@ -2662,7 +2686,7 @@
         return continueWrite(desired);
     }
 
-    uint8_t* data = (uint8_t*)realloc(mData, desired);
+    uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);
     if (!data && desired > mDataCapacity) {
         mError = NO_MEMORY;
         return NO_MEMORY;
@@ -2813,7 +2837,7 @@
 
         // We own the data, so we can just do a realloc().
         if (desired > mDataCapacity) {
-            uint8_t* data = (uint8_t*)realloc(mData, desired);
+            uint8_t* data = reallocZeroFree(mData, mDataCapacity, desired, mDeallocZero);
             if (data) {
                 LOG_ALLOC("Parcel %p: continue from %zu to %zu capacity", this, mDataCapacity,
                         desired);
@@ -2881,6 +2905,7 @@
     mHasFds = false;
     mFdsKnown = true;
     mAllowFds = true;
+    mDeallocZero = false;
     mOwner = nullptr;
     mOpenAshmemSize = 0;
     mWorkSourceRequestHeaderPosition = 0;