diff options
| author | 2021-05-14 17:51:03 +0000 | |
|---|---|---|
| committer | 2021-05-14 17:51:03 +0000 | |
| commit | da55afdbd41f66d33af20c31630f18cfec4616ea (patch) | |
| tree | c4509cb97211ec161f5f67c38c9541e9585912b1 | |
| parent | 982e8b7d3be0eef5f47c715526e11206008f64b7 (diff) | |
| parent | 08cb54f49df91e1a4240eaa916dc0dc65689352e (diff) | |
Merge changes Id8fc889f,I2145ad0e am: 5426122b9b am: 08cb54f49d
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1707789
Change-Id: I44d1b684d2a177b71c2a0aa64bd19d5fd1ba7b14
| -rw-r--r-- | libs/binder/IPCThreadState.cpp | 44 | ||||
| -rw-r--r-- | libs/binder/RpcState.cpp | 16 | ||||
| -rw-r--r-- | libs/binder/include/binder/IPCThreadState.h | 27 | ||||
| -rw-r--r-- | libs/binder/tests/IBinderRpcTest.aidl | 2 | ||||
| -rw-r--r-- | libs/binder/tests/binderLibTest.cpp | 36 | ||||
| -rw-r--r-- | libs/binder/tests/binderRpcTest.cpp | 21 |
6 files changed, 137 insertions, 9 deletions
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index ef7fd44419..18b77e6692 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -366,19 +366,45 @@ status_t IPCThreadState::clearLastError() pid_t IPCThreadState::getCallingPid() const { + checkContextIsBinderForUse(__func__); return mCallingPid; } const char* IPCThreadState::getCallingSid() const { + checkContextIsBinderForUse(__func__); return mCallingSid; } uid_t IPCThreadState::getCallingUid() const { + checkContextIsBinderForUse(__func__); return mCallingUid; } +IPCThreadState::SpGuard* IPCThreadState::pushGetCallingSpGuard(SpGuard* guard) { + SpGuard* orig = mServingStackPointerGuard; + mServingStackPointerGuard = guard; + return orig; +} + +void IPCThreadState::restoreGetCallingSpGuard(SpGuard* guard) { + mServingStackPointerGuard = guard; +} + +void IPCThreadState::checkContextIsBinderForUse(const char* use) const { + if (mServingStackPointerGuard == nullptr) return; + + if (!mServingStackPointer || mServingStackPointerGuard < mServingStackPointer) { + LOG_ALWAYS_FATAL("In context %s, %s does not make sense.", + mServingStackPointerGuard->context, use); + } + + // in the case mServingStackPointer is deeper in the stack than the guard, + // we must be serving a binder transaction (maybe nested). This is a binder + // context, so we don't abort +} + int64_t IPCThreadState::clearCallingIdentity() { // ignore mCallingSid for legacy reasons @@ -847,15 +873,15 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) } IPCThreadState::IPCThreadState() - : mProcess(ProcessState::self()), - mServingStackPointer(nullptr), - mWorkSource(kUnsetWorkSource), - mPropagateWorkSource(false), - mIsLooper(false), - mStrictModePolicy(0), - mLastTransactionBinderFlags(0), - mCallRestriction(mProcess->mCallRestriction) -{ + : mProcess(ProcessState::self()), + mServingStackPointer(nullptr), + mServingStackPointerGuard(nullptr), + mWorkSource(kUnsetWorkSource), + mPropagateWorkSource(false), + mIsLooper(false), + mStrictModePolicy(0), + mLastTransactionBinderFlags(0), + mCallRestriction(mProcess->mCallRestriction) { pthread_setspecific(gTLS, this); clearCaller(); mIn.setDataCapacity(256); diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 2ba9fa2bd5..e5a6026f3b 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -18,7 +18,9 @@ #include "RpcState.h" +#include <android-base/scopeguard.h> #include <binder/BpBinder.h> +#include <binder/IPCThreadState.h> #include <binder/RpcServer.h> #include "Debug.h" @@ -28,6 +30,8 @@ namespace android { +using base::ScopeGuard; + RpcState::RpcState() {} RpcState::~RpcState() {} @@ -470,6 +474,18 @@ status_t RpcState::getAndExecuteCommand(const base::unique_fd& fd, const sp<RpcS status_t RpcState::processServerCommand(const base::unique_fd& fd, const sp<RpcSession>& session, const RpcWireHeader& command) { + IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull(); + IPCThreadState::SpGuard spGuard{"processing binder RPC command"}; + IPCThreadState::SpGuard* origGuard; + if (kernelBinderState != nullptr) { + origGuard = kernelBinderState->pushGetCallingSpGuard(&spGuard); + } + ScopeGuard guardUnguard = [&]() { + if (kernelBinderState != nullptr) { + kernelBinderState->restoreGetCallingSpGuard(origGuard); + } + }; + switch (command.command) { case RPC_COMMAND_TRANSACT: return processTransact(fd, session, command); diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 23a0cb0148..5220b62d62 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -81,6 +81,32 @@ public: */ uid_t getCallingUid() const; + /** + * Make it an abort to rely on getCalling* for a section of + * execution. + * + * Usage: + * IPCThreadState::SpGuard guard { "..." }; + * auto* orig = pushGetCallingSpGuard(&guard); + * { + * // will abort if you call getCalling*, unless you are + * // serving a nested binder transaction + * } + * restoreCallingSpGuard(orig); + */ + struct SpGuard { + const char* context; + }; + SpGuard* pushGetCallingSpGuard(SpGuard* guard); + void restoreGetCallingSpGuard(SpGuard* guard); + /** + * Used internally by getCalling*. Can also be used to assert that + * you are in a binder context (getCalling* is valid). This is + * intentionally not exposed as a boolean API since code should be + * written to know its environment. + */ + void checkContextIsBinderForUse(const char* use) const; + void setStrictModePolicy(int32_t policy); int32_t getStrictModePolicy() const; @@ -203,6 +229,7 @@ private: Parcel mOut; status_t mLastError; const void* mServingStackPointer; + SpGuard* mServingStackPointerGuard; pid_t mCallingPid; const char* mCallingSid; uid_t mCallingUid; diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl index ef4198d8f2..41daccc1cf 100644 --- a/libs/binder/tests/IBinderRpcTest.aidl +++ b/libs/binder/tests/IBinderRpcTest.aidl @@ -55,4 +55,6 @@ interface IBinderRpcTest { oneway void sleepMsAsync(int ms); void die(boolean cleanup); + + void useKernelBinderCallingId(); } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 0c3fbcd2da..45b277624c 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -73,6 +73,7 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_REGISTER_SERVER, BINDER_LIB_TEST_ADD_SERVER, BINDER_LIB_TEST_ADD_POLL_SERVER, + BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION, BINDER_LIB_TEST_CALL_BACK, BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF, BINDER_LIB_TEST_DELAYED_CALL_BACK, @@ -604,6 +605,24 @@ TEST_F(BinderLibTest, CallBack) EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR)); } +TEST_F(BinderLibTest, NoBinderCallContextGuard) { + IPCThreadState::SpGuard spGuard{"NoBinderCallContext"}; + IPCThreadState::SpGuard *origGuard = IPCThreadState::self()->pushGetCallingSpGuard(&spGuard); + + // yes, this test uses threads, but it's careful and uses fork in addServer + EXPECT_DEATH({ IPCThreadState::self()->getCallingPid(); }, + "In context NoBinderCallContext, getCallingPid does not make sense."); + + IPCThreadState::self()->restoreGetCallingSpGuard(origGuard); +} + +TEST_F(BinderLibTest, BinderCallContextGuard) { + sp<IBinder> binder = addServer(); + Parcel data, reply; + EXPECT_THAT(binder->transact(BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION, data, &reply), + StatusEq(DEAD_OBJECT)); +} + TEST_F(BinderLibTest, AddServer) { sp<IBinder> server = addServer(); @@ -1262,6 +1281,18 @@ class BinderLibTestService : public BBinder pthread_mutex_unlock(&m_serverWaitMutex); return ret; } + case BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION: { + IPCThreadState::SpGuard spGuard{"GuardInBinderTransaction"}; + IPCThreadState::SpGuard *origGuard = + IPCThreadState::self()->pushGetCallingSpGuard(&spGuard); + + // if the guard works, this should abort + (void)IPCThreadState::self()->getCallingPid(); + + IPCThreadState::self()->restoreGetCallingSpGuard(origGuard); + return NO_ERROR; + } + case BINDER_LIB_TEST_GETPID: reply->writeInt32(getpid()); return NO_ERROR; @@ -1489,6 +1520,11 @@ int run_server(int index, int readypipefd, bool usePoll) { binderLibTestServiceName += String16(binderserversuffix); + // Testing to make sure that calls that we are serving can use getCallin* + // even though we don't here. + IPCThreadState::SpGuard spGuard{"main server thread"}; + (void)IPCThreadState::self()->pushGetCallingSpGuard(&spGuard); + status_t ret; sp<IServiceManager> sm = defaultServiceManager(); BinderLibTestService* testServicePtr; diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 260be570f9..9c263b1f21 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -23,6 +23,7 @@ #include <android/binder_libbinder.h> #include <binder/Binder.h> #include <binder/BpBinder.h> +#include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/ProcessState.h> #include <binder/RpcServer.h> @@ -178,6 +179,13 @@ public: _exit(1); } } + Status useKernelBinderCallingId() override { + // this is WRONG! It does not make sense when using RPC binder, and + // because it is SO wrong, and so much code calls this, it should abort! + + (void)IPCThreadState::self()->getCallingPid(); + return Status::ok(); + } }; sp<IBinder> MyBinderRpcTest::mHeldBinder; @@ -874,6 +882,19 @@ TEST_P(BinderRpc, Die) { } } +TEST_P(BinderRpc, UseKernelBinderCallingId) { + auto proc = createRpcTestSocketServerProcess(1); + + // we can't allocate IPCThreadState so actually the first time should + // succeed :( + EXPECT_OK(proc.rootIface->useKernelBinderCallingId()); + + // second time! we catch the error :) + EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError()); + + proc.expectInvalid = true; +} + TEST_P(BinderRpc, WorksWithLibbinderNdkPing) { auto proc = createRpcTestSocketServerProcess(1); |