Limit unprivileged keepalives per uid

Public APIs for creating unprivileged NATT socket keepalive
might allow users to exhaust resource if malicious apps try
to create keepalives with fd which is not created by
IpSecService through binder call. Thus, this change add
customizable limitation per uid to prevent resource exhaustion
attack.

Bug: 129371366
Bug: 132307230
Test: atest FrameworksNetTests
Change-Id: Ibcb91105e46f7e898b8aa7c2babc3344ef2c6257
This commit is contained in:
junyulai
2019-04-30 14:42:05 +08:00
parent 4dca18aa31
commit 0586a60292

View File

@@ -104,6 +104,10 @@ public class KeepaliveTracker {
// the number of remaining keepalive slots is less than or equal to the threshold. // the number of remaining keepalive slots is less than or equal to the threshold.
private final int mReservedPrivilegedSlots; private final int mReservedPrivilegedSlots;
// Allowed unprivileged keepalive slots per uid. Caller's permission will be enforced if
// the number of remaining keepalive slots is less than or equal to the threshold.
private final int mAllowedUnprivilegedSlotsForUid;
public KeepaliveTracker(Context context, Handler handler) { public KeepaliveTracker(Context context, Handler handler) {
mConnectivityServiceHandler = handler; mConnectivityServiceHandler = handler;
mTcpController = new TcpKeepaliveController(handler); mTcpController = new TcpKeepaliveController(handler);
@@ -111,6 +115,8 @@ public class KeepaliveTracker {
mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext); mSupportedKeepalives = KeepaliveUtils.getSupportedKeepalives(mContext);
mReservedPrivilegedSlots = mContext.getResources().getInteger( mReservedPrivilegedSlots = mContext.getResources().getInteger(
R.integer.config_reservedPrivilegedKeepaliveSlots); R.integer.config_reservedPrivilegedKeepaliveSlots);
mAllowedUnprivilegedSlotsForUid = mContext.getResources().getInteger(
R.integer.config_allowedUnprivilegedKeepalivePerUid);
} }
/** /**
@@ -276,6 +282,18 @@ public class KeepaliveTracker {
return ERROR_INSUFFICIENT_RESOURCES; return ERROR_INSUFFICIENT_RESOURCES;
} }
// Count unprivileged keepalives for the same uid across networks.
int unprivilegedCountSameUid = 0;
for (final HashMap<Integer, KeepaliveInfo> kaForNetwork : mKeepalives.values()) {
for (final KeepaliveInfo ki : kaForNetwork.values()) {
if (ki.mUid == mUid) {
unprivilegedCountSameUid++;
}
}
}
if (unprivilegedCountSameUid > mAllowedUnprivilegedSlotsForUid) {
return ERROR_INSUFFICIENT_RESOURCES;
}
return SUCCESS; return SUCCESS;
} }
@@ -701,6 +719,7 @@ public class KeepaliveTracker {
public void dump(IndentingPrintWriter pw) { public void dump(IndentingPrintWriter pw) {
pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives)); pw.println("Supported Socket keepalives: " + Arrays.toString(mSupportedKeepalives));
pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots); pw.println("Reserved Privileged keepalives: " + mReservedPrivilegedSlots);
pw.println("Allowed Unprivileged keepalives per uid: " + mAllowedUnprivilegedSlotsForUid);
pw.println("Socket keepalives:"); pw.println("Socket keepalives:");
pw.increaseIndent(); pw.increaseIndent();
for (NetworkAgentInfo nai : mKeepalives.keySet()) { for (NetworkAgentInfo nai : mKeepalives.keySet()) {