From 4846fff84d4c6bdf271f20b4b39d707a2f3002de Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 9 Jul 2021 00:05:48 +0000 Subject: [PATCH] Only pass the NRI for removal in NRI#binderDied When NetworkRequestInfo#binderDied is called in ConnectivityService, only pass the NRI to handleRemoveNetworkRequest. This is to prevent a potential crash when unlinkDeathRecipient is called twice for the same NRI. Also, as a cleanup, don't iterate mRequests in the log message on binderDied. As per the bug, the chain of events leading to a potential crash are: - `Connectivity.NetworkRequestInfo#binderDied()` is called for an NRI tracking multiple `NetworkRequest` items. This can happen for a TRACK_DEFAULT request filed by a UID on a different preference than the default, which copies the request list. - This in turn triggers multiple `EVENT_RELEASE_NETWORK_REQUEST` events for the same NRI, one for reach `NetworkRequest` tracked. - When handling `EVENT_RELEASE_NETWORK_REQUEST`, each `NetworkRequest` that is passed in will then be used to look up the parent NRI that originally sent it to be released. - Therefore if an NRI was tracking three requests, it would trigger three release network events, then each request would be used to look up the same NRI again when handling said release event. - Finally, `ConnectivityService.NetworkRequestInfo#unlinkDeathRecipient` is called for the NRI in question. Using the scenario above, that means we could call `unlinkDeathRecipient` multiple times for the same NRI if it was tracking multiple network requests causing the associated crash. - If `unlinkDeathRecipient` is called more than once for the same NRI, it will cause the crash listed in this bug. - The fix is to only call handleRemoveNetworkRequest for the NRI once. This works since when removing the NRI, we iterate over all of its requests to remove them. By only calling handleRemoveNetworkRequest once, it's ensured `unlinkDeathRecipient` for this NRI as part of `Connectivity.NetworkRequestInfo#binderDied()` is only called once and not potentially multiple times. Bug: 185541983 Change-Id: I918c8620f2975d810894c178277771764923b5a4 Test: atest FrameworksNetTests Merged-In: I2a2ad4ec6d415423182a1856a898779203658f8b --- .../com/android/server/ConnectivityService.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index b655ed6e6a..f6639dc987 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -4206,13 +4206,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) { ensureRunningOnConnectivityServiceThread(); - nri.unlinkDeathRecipient(); for (final NetworkRequest req : nri.mRequests) { - mNetworkRequests.remove(req); + if (null == mNetworkRequests.remove(req)) { + logw("Attempted removal of untracked request " + req + " for nri " + nri); + continue; + } if (req.isListen()) { removeListenRequestFromNetworks(req); } } + nri.unlinkDeathRecipient(); if (mDefaultNetworkRequests.remove(nri)) { // If this request was one of the defaults, then the UID rules need to be updated // WARNING : if the app(s) for which this network request is the default are doing @@ -5886,8 +5889,8 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void binderDied() { log("ConnectivityService NetworkRequestInfo binderDied(" + - mRequests + ", " + mBinder + ")"); - releaseNetworkRequests(mRequests); + "uid/pid:" + mUid + "/" + mPid + ", " + mBinder + ")"); + mHandler.post(() -> handleRemoveNetworkRequest(this)); } @Override @@ -6318,12 +6321,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return mNextNetworkProviderId.getAndIncrement(); } - private void releaseNetworkRequests(List networkRequests) { - for (int i = 0; i < networkRequests.size(); i++) { - releaseNetworkRequest(networkRequests.get(i)); - } - } - @Override public void releaseNetworkRequest(NetworkRequest networkRequest) { ensureNetworkRequestHasType(networkRequest);