OSDN Git Service

Merge "Drop PROHIBIT_NON_VPN priority 11500 -> 12500" into nyc-dev
[android-x86/system-netd.git] / server / RouteController.cpp
index b2cd93a..fa39c89 100644 (file)
@@ -48,6 +48,7 @@ const uint32_t RULE_PRIORITY_VPN_OVERRIDE_SYSTEM = 10000;
 const uint32_t RULE_PRIORITY_VPN_OVERRIDE_OIF    = 10500;
 const uint32_t RULE_PRIORITY_VPN_OUTPUT_TO_LOCAL = 11000;
 const uint32_t RULE_PRIORITY_SECURE_VPN          = 12000;
+const uint32_t RULE_PRIORITY_PROHIBIT_NON_VPN    = 12500;
 const uint32_t RULE_PRIORITY_EXPLICIT_NETWORK    = 13000;
 const uint32_t RULE_PRIORITY_OUTPUT_INTERFACE    = 14000;
 const uint32_t RULE_PRIORITY_LEGACY_SYSTEM       = 15000;
@@ -180,6 +181,15 @@ void updateTableNamesFile() {
 // |iov| is an array of struct iovec that contains the netlink message payload.
 // The netlink header is generated by this function based on |action| and |flags|.
 // Returns -errno if there was an error or if the kernel reported an error.
+
+// Disable optimizations in ASan build.
+// ASan reports an out-of-bounds 32-bit(!) access in the first loop of the
+// function (over iov[]).
+#ifdef __clang__
+#if __has_feature(address_sanitizer)
+__attribute__((optnone))
+#endif
+#endif
 WARN_UNUSED_RESULT int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) {
     nlmsghdr nlmsg = {
         .nlmsg_type = action,
@@ -242,10 +252,8 @@ int padInterfaceName(const char* input, char* name, size_t* length, uint16_t* pa
 
 // Adds or removes a routing rule for IPv4 and IPv6.
 //
-// + If |priority| is RULE_PRIORITY_UNREACHABLE, the rule returns ENETUNREACH (i.e., specifies an
-//   action of FR_ACT_UNREACHABLE). Otherwise, the rule specifies an action of FR_ACT_TO_TBL.
 // + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the table is
-//   unspecified. An unspecified table is only allowed when deleting a rule.
+//   unspecified. An unspecified table is not allowed when creating an FR_ACT_TO_TBL rule.
 // + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is
 //   ignored.
 // + If |iif| is non-NULL, the rule matches the specified incoming interface.
@@ -254,8 +262,8 @@ int padInterfaceName(const char* input, char* name, size_t* length, uint16_t* pa
 //   range (inclusive). Otherwise, the rule matches packets from all UIDs.
 //
 // Returns 0 on success or negative errno on failure.
-WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
-                                    uint32_t fwmark, uint32_t mask, const char* iif,
+WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint8_t ruleType,
+                                    uint32_t table, uint32_t fwmark, uint32_t mask, const char* iif,
                                     const char* oif, uid_t uidStart, uid_t uidEnd) {
     // Ensure that if you set a bit in the fwmark, it's not being ignored by the mask.
     if (fwmark & ~mask) {
@@ -280,12 +288,12 @@ WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t
         ALOGE("incompatible start and end UIDs (%u vs %u)", uidStart, uidEnd);
         return -EUSERS;
     }
+
     bool isUidRule = (uidStart != INVALID_UID);
 
     // Assemble a rule request and put it in an array of iovec structures.
     fib_rule_hdr rule = {
-        .action = static_cast<uint8_t>(priority != RULE_PRIORITY_UNREACHABLE ? FR_ACT_TO_TBL :
-                                                                               FR_ACT_UNREACHABLE),
+        .action = ruleType,
         // Note that here we're implicitly setting rule.table to 0. When we want to specify a
         // non-zero table, we do this via the FRATTR_TABLE attribute.
     };
@@ -336,6 +344,13 @@ WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t
 }
 
 WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
+                                    uint32_t fwmark, uint32_t mask, const char* iif,
+                                    const char* oif, uid_t uidStart, uid_t uidEnd) {
+    return modifyIpRule(action, priority, FR_ACT_TO_TBL, table, fwmark, mask, iif, oif, uidStart,
+                        uidEnd);
+}
+
+WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
                                     uint32_t fwmark, uint32_t mask) {
     return modifyIpRule(action, priority, table, fwmark, mask, IIF_NONE, OIF_NONE, INVALID_UID,
                         INVALID_UID);
@@ -721,8 +736,8 @@ WARN_UNUSED_RESULT int addDirectlyConnectedRule() {
 // behaviour. We do flush the kernel-default rules at startup, but having an explicit unreachable
 // rule will hopefully make things even clearer.
 WARN_UNUSED_RESULT int addUnreachableRule() {
-    return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, RT_TABLE_UNSPEC, MARK_UNSET,
-                        MARK_UNSET);
+    return modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, FR_ACT_UNREACHABLE, RT_TABLE_UNSPEC,
+                        MARK_UNSET, MARK_UNSET, IIF_NONE, OIF_NONE, INVALID_UID, INVALID_UID);
 }
 
 WARN_UNUSED_RESULT int modifyLocalNetwork(unsigned netId, const char* interface, bool add) {
@@ -754,6 +769,24 @@ WARN_UNUSED_RESULT int modifyPhysicalNetwork(unsigned netId, const char* interfa
     return modifyImplicitNetworkRule(netId, table, permission, add);
 }
 
+WARN_UNUSED_RESULT int modifyRejectNonSecureNetworkRule(const UidRanges& uidRanges, bool add) {
+    Fwmark fwmark;
+    Fwmark mask;
+    fwmark.protectedFromVpn = false;
+    mask.protectedFromVpn = true;
+
+    for (const UidRanges::Range& range : uidRanges.getRanges()) {
+        if (int ret = modifyIpRule(add ? RTM_NEWRULE : RTM_DELRULE,
+                                   RULE_PRIORITY_PROHIBIT_NON_VPN, FR_ACT_PROHIBIT, RT_TABLE_UNSPEC,
+                                   fwmark.intValue, mask.intValue, IIF_LOOPBACK, OIF_NONE,
+                                   range.first, range.second)) {
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
 WARN_UNUSED_RESULT int modifyVirtualNetwork(unsigned netId, const char* interface,
                                             const UidRanges& uidRanges, bool secure, bool add,
                                             bool modifyNonUidBasedRules) {
@@ -1031,6 +1064,14 @@ int RouteController::modifyPhysicalNetworkPermission(unsigned netId, const char*
     return modifyPhysicalNetwork(netId, interface, oldPermission, ACTION_DEL);
 }
 
+int RouteController::addUsersToRejectNonSecureNetworkRule(const UidRanges& uidRanges) {
+    return modifyRejectNonSecureNetworkRule(uidRanges, true);
+}
+
+int RouteController::removeUsersFromRejectNonSecureNetworkRule(const UidRanges& uidRanges) {
+    return modifyRejectNonSecureNetworkRule(uidRanges, false);
+}
+
 int RouteController::addUsersToVirtualNetwork(unsigned netId, const char* interface, bool secure,
                                               const UidRanges& uidRanges) {
     return modifyVirtualNetwork(netId, interface, uidRanges, secure, ACTION_ADD,