Add 3rd deny firewall chain for OEM

Bug: 208371987
Test: atest
CtsNetTestCases:android.net.cts.ConnectivityManagerTest#testFirewallBlocking
ConnectivityServiceTest

Change-Id: Ib521fa02f6a19270cb88a3d85321bda822516c78
(cherry picked from commit 1d9054ba5fbbf86c821e0a74a5a2f9d3c9865e67)
Merged-In: Ib521fa02f6a19270cb88a3d85321bda822516c78
diff --git a/bpf_progs/bpf_shared.h b/bpf_progs/bpf_shared.h
index 2afb789..706dd1d 100644
--- a/bpf_progs/bpf_shared.h
+++ b/bpf_progs/bpf_shared.h
@@ -135,6 +135,7 @@
     LOCKDOWN_VPN_MATCH = (1 << 8),
     OEM_DENY_1_MATCH = (1 << 9),
     OEM_DENY_2_MATCH = (1 << 10),
+    OEM_DENY_3_MATCH = (1 << 11),
 };
 
 enum BpfPermissionMatch {
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index c1d0897..d754616 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -222,6 +222,9 @@
         if ((enabledRules & OEM_DENY_2_MATCH) && (uidRules & OEM_DENY_2_MATCH)) {
             return BPF_DROP;
         }
+        if ((enabledRules & OEM_DENY_3_MATCH) && (uidRules & OEM_DENY_3_MATCH)) {
+            return BPF_DROP;
+        }
     }
     if (direction == BPF_INGRESS && skb->ifindex != 1) {
         if (uidRules & IIF_MATCH) {
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 9c04e8c..f741c2b 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1006,6 +1006,13 @@
      */
     public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8;
 
+    /**
+     * Firewall chain used for OEM-specific application restrictions.
+     * Denylist of apps that will not have network access due to OEM-specific restrictions.
+     * @hide
+     */
+    public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = false, prefix = "FIREWALL_CHAIN_", value = {
@@ -1016,7 +1023,8 @@
         FIREWALL_CHAIN_LOW_POWER_STANDBY,
         FIREWALL_CHAIN_LOCKDOWN_VPN,
         FIREWALL_CHAIN_OEM_DENY_1,
-        FIREWALL_CHAIN_OEM_DENY_2
+        FIREWALL_CHAIN_OEM_DENY_2,
+        FIREWALL_CHAIN_OEM_DENY_3
     })
     public @interface FirewallChain {}
     // LINT.ThenChange(packages/modules/Connectivity/service/native/include/Common.h)
diff --git a/service/native/TrafficController.cpp b/service/native/TrafficController.cpp
index 548ecbe..4923b00 100644
--- a/service/native/TrafficController.cpp
+++ b/service/native/TrafficController.cpp
@@ -76,6 +76,7 @@
 const char* TrafficController::LOCAL_LOW_POWER_STANDBY = "fw_low_power_standby";
 const char* TrafficController::LOCAL_OEM_DENY_1 = "fw_oem_deny_1";
 const char* TrafficController::LOCAL_OEM_DENY_2 = "fw_oem_deny_2";
+const char* TrafficController::LOCAL_OEM_DENY_3 = "fw_oem_deny_3";
 
 static_assert(BPF_PERMISSION_INTERNET == INetd::PERMISSION_INTERNET,
               "Mismatch between BPF and AIDL permissions: PERMISSION_INTERNET");
@@ -103,6 +104,7 @@
     FLAG_MSG_TRANS(matchType, LOCKDOWN_VPN_MATCH, match);
     FLAG_MSG_TRANS(matchType, OEM_DENY_1_MATCH, match);
     FLAG_MSG_TRANS(matchType, OEM_DENY_2_MATCH, match);
+    FLAG_MSG_TRANS(matchType, OEM_DENY_3_MATCH, match);
     if (match) {
         return StringPrintf("Unknown match: %u", match);
     }
@@ -343,6 +345,8 @@
             return DENYLIST;
         case OEM_DENY_2:
             return DENYLIST;
+        case OEM_DENY_3:
+            return DENYLIST;
         case NONE:
         default:
             return DENYLIST;
@@ -377,6 +381,9 @@
         case OEM_DENY_2:
             res = updateOwnerMapEntry(OEM_DENY_2_MATCH, uid, rule, type);
             break;
+        case OEM_DENY_3:
+            res = updateOwnerMapEntry(OEM_DENY_3_MATCH, uid, rule, type);
+            break;
         case NONE:
         default:
             ALOGW("Unknown child chain: %d", chain);
@@ -458,6 +465,8 @@
         res = replaceRulesInMap(OEM_DENY_1_MATCH, uids);
     } else if (!name.compare(LOCAL_OEM_DENY_2)) {
         res = replaceRulesInMap(OEM_DENY_2_MATCH, uids);
+    } else if (!name.compare(LOCAL_OEM_DENY_3)) {
+        res = replaceRulesInMap(OEM_DENY_3_MATCH, uids);
     } else {
         ALOGE("unknown chain name: %s", name.c_str());
         return -EINVAL;
@@ -503,6 +512,9 @@
         case OEM_DENY_2:
             match = OEM_DENY_2_MATCH;
             break;
+        case OEM_DENY_3:
+            match = OEM_DENY_3_MATCH;
+            break;
         default:
             return -EINVAL;
     }
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index 9ec50af..df5955f 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -310,6 +310,7 @@
     checkUidOwnerRuleForChain(LOCKDOWN, LOCKDOWN_VPN_MATCH);
     checkUidOwnerRuleForChain(OEM_DENY_1, OEM_DENY_1_MATCH);
     checkUidOwnerRuleForChain(OEM_DENY_2, OEM_DENY_2_MATCH);
+    checkUidOwnerRuleForChain(OEM_DENY_3, OEM_DENY_3_MATCH);
     ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(NONE, TEST_UID, ALLOW, ALLOWLIST));
     ASSERT_EQ(-EINVAL, mTc.changeUidOwnerRule(INVALID_CHAIN, TEST_UID, ALLOW, ALLOWLIST));
 }
@@ -323,6 +324,7 @@
     checkUidMapReplace("fw_low_power_standby", uids, LOW_POWER_STANDBY_MATCH);
     checkUidMapReplace("fw_oem_deny_1", uids, OEM_DENY_1_MATCH);
     checkUidMapReplace("fw_oem_deny_2", uids, OEM_DENY_2_MATCH);
+    checkUidMapReplace("fw_oem_deny_3", uids, OEM_DENY_3_MATCH);
     ASSERT_EQ(-EINVAL, mTc.replaceUidOwnerMap("unknow", true, uids));
 }
 
diff --git a/service/native/include/Common.h b/service/native/include/Common.h
index 48f68ea..2427aa9 100644
--- a/service/native/include/Common.h
+++ b/service/native/include/Common.h
@@ -38,6 +38,7 @@
     LOCKDOWN = 6,
     OEM_DENY_1 = 7,
     OEM_DENY_2 = 8,
+    OEM_DENY_3 = 9,
     INVALID_CHAIN
 };
 // LINT.ThenChange(packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java)
diff --git a/service/native/include/TrafficController.h b/service/native/include/TrafficController.h
index 7a36e1e..c019ce7 100644
--- a/service/native/include/TrafficController.h
+++ b/service/native/include/TrafficController.h
@@ -90,6 +90,7 @@
     static const char* LOCAL_LOW_POWER_STANDBY;
     static const char* LOCAL_OEM_DENY_1;
     static const char* LOCAL_OEM_DENY_2;
+    static const char* LOCAL_OEM_DENY_3;
 
   private:
     /*
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index edcdfa8..d0cb294 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -11365,6 +11365,7 @@
             case ConnectivityManager.FIREWALL_CHAIN_STANDBY:
             case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1:
             case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2:
+            case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3:
                 defaultRule = FIREWALL_RULE_ALLOW;
                 break;
             case ConnectivityManager.FIREWALL_CHAIN_DOZABLE:
@@ -11420,6 +11421,9 @@
                 case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2:
                     mBpfNetMaps.replaceUidChain("fw_oem_deny_2", false /* isAllowList */, uids);
                     break;
+                case ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3:
+                    mBpfNetMaps.replaceUidChain("fw_oem_deny_3", false /* isAllowList */, uids);
+                    break;
                 default:
                     throw new IllegalArgumentException("replaceFirewallChain with invalid chain: "
                             + chain);
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index b90eeac..3300079 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -39,6 +39,7 @@
 import static android.net.ConnectivityManager.EXTRA_NETWORK_REQUEST;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
 import static android.net.ConnectivityManager.FIREWALL_RULE_ALLOW;
 import static android.net.ConnectivityManager.FIREWALL_RULE_DENY;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
@@ -3429,6 +3430,7 @@
         // doTestFirewallBlockingDenyRule(FIREWALL_CHAIN_STANDBY);
         doTestFirewallBlockingDenyRule(FIREWALL_CHAIN_OEM_DENY_1);
         doTestFirewallBlockingDenyRule(FIREWALL_CHAIN_OEM_DENY_2);
+        doTestFirewallBlockingDenyRule(FIREWALL_CHAIN_OEM_DENY_3);
     }
 
     private void assumeTestSApis() {
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 74731c3..b9a18ab 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -57,6 +57,7 @@
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_LOW_POWER_STANDBY;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_1;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_2;
+import static android.net.ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_POWERSAVE;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_RESTRICTED;
 import static android.net.ConnectivityManager.FIREWALL_CHAIN_STANDBY;
@@ -9579,6 +9580,7 @@
         doTestSetUidFirewallRule(FIREWALL_CHAIN_LOW_POWER_STANDBY, FIREWALL_RULE_DENY);
         doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_1, FIREWALL_RULE_ALLOW);
         doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_2, FIREWALL_RULE_ALLOW);
+        doTestSetUidFirewallRule(FIREWALL_CHAIN_OEM_DENY_3, FIREWALL_RULE_ALLOW);
     }
 
     @Test @IgnoreUpTo(SC_V2)
@@ -9590,7 +9592,8 @@
                 FIREWALL_CHAIN_RESTRICTED,
                 FIREWALL_CHAIN_LOW_POWER_STANDBY,
                 FIREWALL_CHAIN_OEM_DENY_1,
-                FIREWALL_CHAIN_OEM_DENY_2);
+                FIREWALL_CHAIN_OEM_DENY_2,
+                FIREWALL_CHAIN_OEM_DENY_3);
         for (final int chain: firewallChains) {
             mCm.setFirewallChainEnabled(chain, true /* enabled */);
             verify(mBpfNetMaps).setChildChain(chain, true /* enable */);
@@ -9619,6 +9622,7 @@
         doTestReplaceFirewallChain(FIREWALL_CHAIN_LOW_POWER_STANDBY, "fw_low_power_standby", true);
         doTestReplaceFirewallChain(FIREWALL_CHAIN_OEM_DENY_1, "fw_oem_deny_1", false);
         doTestReplaceFirewallChain(FIREWALL_CHAIN_OEM_DENY_2, "fw_oem_deny_2", false);
+        doTestReplaceFirewallChain(FIREWALL_CHAIN_OEM_DENY_3, "fw_oem_deny_3", false);
     }
 
     @Test @IgnoreUpTo(SC_V2)