Guard against failed array allocation
Also sanity check the fd count of incoming Parcels. Anything
exceeding our actual rlimit is inherently not legit.
Bug 26696080
Change-Id: Ib983dce8e8977d7e33195a4ee471115cdaf1c56b
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 678d98b..fe0ad9f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -27,6 +27,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/resource.h>
#include <unistd.h>
#include <binder/Binder.h>
@@ -88,6 +89,8 @@
static size_t gParcelGlobalAllocSize = 0;
static size_t gParcelGlobalAllocCount = 0;
+static size_t gMaxFds = 0;
+
// Maximum size of a blob to transfer in-place.
static const size_t BLOB_INPLACE_LIMIT = 16 * 1024;
@@ -1268,7 +1271,7 @@
const size_t len = val.getFlattenedSize();
const size_t fd_count = val.getFdCount();
- if ((len > INT32_MAX) || (fd_count > INT32_MAX)) {
+ if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
// don't accept size_t values which may have come from an
// inadvertent conversion from a negative int.
return BAD_VALUE;
@@ -1287,7 +1290,11 @@
int* fds = NULL;
if (fd_count) {
- fds = new int[fd_count];
+ fds = new (std::nothrow) int[fd_count];
+ if (fds == nullptr) {
+ ALOGE("write: failed to allocate requested %zu fds", fd_count);
+ return BAD_VALUE;
+ }
}
err = val.flatten(buf, len, fds, fd_count);
@@ -1479,7 +1486,7 @@
}
parcel->setDataPosition(start);
- val->reset(new std::vector<T>());
+ val->reset(new (std::nothrow) std::vector<T>());
status = readByteVectorInternal(parcel, val->get());
@@ -1551,7 +1558,7 @@
}
setDataPosition(start);
- val->reset(new std::vector<bool>());
+ val->reset(new (std::nothrow) std::vector<bool>());
status = readBoolVector(val->get());
@@ -1811,7 +1818,7 @@
}
setDataPosition(start);
- str->reset(new std::string());
+ str->reset(new (std::nothrow) std::string());
return readUtf8FromUtf16(str->get());
}
@@ -1864,7 +1871,7 @@
}
setDataPosition(start);
- pArg->reset(new String16());
+ pArg->reset(new (std::nothrow) String16());
status = readString16(pArg->get());
@@ -2040,7 +2047,7 @@
const size_t len = this->readInt32();
const size_t fd_count = this->readInt32();
- if (len > INT32_MAX) {
+ if ((len > INT32_MAX) || (fd_count >= gMaxFds)) {
// don't accept size_t values which may have come from an
// inadvertent conversion from a negative int.
return BAD_VALUE;
@@ -2053,7 +2060,11 @@
int* fds = NULL;
if (fd_count) {
- fds = new int[fd_count];
+ fds = new (std::nothrow) int[fd_count];
+ if (fds == nullptr) {
+ ALOGE("read: failed to allocate requested %zu fds", fd_count);
+ return BAD_VALUE;
+ }
}
status_t err = NO_ERROR;
@@ -2530,6 +2541,18 @@
mAllowFds = true;
mOwner = NULL;
mOpenAshmemSize = 0;
+
+ // racing multiple init leads only to multiple identical write
+ if (gMaxFds == 0) {
+ struct rlimit result;
+ if (!getrlimit(RLIMIT_NOFILE, &result)) {
+ gMaxFds = (size_t)result.rlim_cur;
+ ALOGI("parcel fd limit set to %zu", gMaxFds);
+ } else {
+ ALOGW("Unable to getrlimit: %s", strerror(errno));
+ gMaxFds = 1024;
+ }
+ }
}
void Parcel::scanForFds() const