libbinder: Don't abort when rpc parcel size is invalid

No test becaue this is only reachable by bypassing the binder client
library (i.e. writing non-sense directly to the socket).

Test: binder_rpc_fuzzer
Bug: 238497894
Change-Id: I85ef57df4b8970c35904a5e84e61cb87653a39be
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 0ae75cd..a898497 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -643,14 +643,21 @@
     Span<const uint32_t> objectTableSpan;
     if (session->getProtocolVersion().value() >=
         RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
-        Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+        std::optional<Span<const uint8_t>> objectTableBytes =
+                parcelSpan.splitOff(rpcReply.parcelDataSize);
+        if (!objectTableBytes.has_value()) {
+            ALOGE("Parcel size larger than available bytes: %" PRId32 " vs %zu. Terminating!",
+                  rpcReply.parcelDataSize, parcelSpan.byteSize());
+            (void)session->shutdownAndWait(false);
+            return BAD_VALUE;
+        }
         std::optional<Span<const uint32_t>> maybeSpan =
-                objectTableBytes.reinterpret<const uint32_t>();
+                objectTableBytes->reinterpret<const uint32_t>();
         if (!maybeSpan.has_value()) {
             ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32
                   " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!",
                   command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize,
-                  objectTableBytes.size);
+                  objectTableBytes->size);
             return BAD_VALUE;
         }
         objectTableSpan = *maybeSpan;
@@ -893,15 +900,22 @@
         Span<const uint32_t> objectTableSpan;
         if (session->getProtocolVersion().value() >
             RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
-            Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+            std::optional<Span<const uint8_t>> objectTableBytes =
+                    parcelSpan.splitOff(transaction->parcelDataSize);
+            if (!objectTableBytes.has_value()) {
+                ALOGE("Parcel size (%" PRId32 ") greater than available bytes (%zu). Terminating!",
+                      transaction->parcelDataSize, parcelSpan.byteSize());
+                (void)session->shutdownAndWait(false);
+                return BAD_VALUE;
+            }
             std::optional<Span<const uint32_t>> maybeSpan =
-                    objectTableBytes.reinterpret<const uint32_t>();
+                    objectTableBytes->reinterpret<const uint32_t>();
             if (!maybeSpan.has_value()) {
                 ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu "
                       "sizeofHeader=%zu parcelSize=%" PRId32
                       " objectTableBytesSize=%zu. Terminating!",
                       transactionData.size(), sizeof(RpcWireTransaction),
-                      transaction->parcelDataSize, objectTableBytes.size);
+                      transaction->parcelDataSize, objectTableBytes->size);
                 return BAD_VALUE;
             }
             objectTableSpan = *maybeSpan;
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 7c6d6f1..e04199c 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -48,9 +48,11 @@
     // Truncates `this` to a length of `offset` and returns a span with the
     // remainder.
     //
-    // Aborts if offset > size.
-    Span<T> splitOff(size_t offset) {
-        LOG_ALWAYS_FATAL_IF(offset > size);
+    // `std::nullopt` iff offset > size.
+    std::optional<Span<T>> splitOff(size_t offset) {
+        if (offset > size) {
+            return std::nullopt;
+        }
         Span<T> rest = {data + offset, size - offset};
         size = offset;
         return rest;