summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2018-09-27 11:36:37 -0700
committerRoshan Pius <rpius@google.com>2018-11-01 09:37:54 -0700
commit2734bc5c446f62fcd2bce9aa0072e222a94f07a1 (patch)
tree1984f49ae058958269442ad2ce07f95e596edaae /service
parent0c4c806bcd0990fce252a6c6f0a413faf8e197f3 (diff)
WifiConfigurationUtil: Validation for network specifier
Add a method to validate the WifiNetworkSpecifier. Bug: 113878056 Test: Unit tests Change-Id: Idf77e249f6b19825ce493be3445cb608a5f49558
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiConfigurationUtil.java195
-rw-r--r--service/java/com/android/server/wifi/WifiNetworkFactory.java5
2 files changed, 188 insertions, 12 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 0258834ea..9bf6e327d 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -16,15 +16,21 @@
package com.android.server.wifi;
+import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes;
+
import android.content.pm.UserInfo;
import android.net.IpConfiguration;
+import android.net.MacAddress;
import android.net.StaticIpConfiguration;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.WifiNetworkSpecifier;
import android.net.wifi.WifiScanner;
+import android.os.PatternMatcher;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.util.NativeUtil;
@@ -50,16 +56,21 @@ public class WifiConfigurationUtil {
/**
* Constants used for validating external config objects.
*/
- private static final int ENCLOSING_QUTOES_LEN = 2;
- private static final int SSID_UTF_8_MIN_LEN = 1 + ENCLOSING_QUTOES_LEN;
- private static final int SSID_UTF_8_MAX_LEN = 32 + ENCLOSING_QUTOES_LEN;
+ private static final int ENCLOSING_QUOTES_LEN = 2;
+ private static final int SSID_UTF_8_MIN_LEN = 1 + ENCLOSING_QUOTES_LEN;
+ private static final int SSID_UTF_8_MAX_LEN = 32 + ENCLOSING_QUOTES_LEN;
private static final int SSID_HEX_MIN_LEN = 2;
private static final int SSID_HEX_MAX_LEN = 64;
- private static final int PSK_ASCII_MIN_LEN = 8 + ENCLOSING_QUTOES_LEN;
- private static final int PSK_ASCII_MAX_LEN = 63 + ENCLOSING_QUTOES_LEN;
+ private static final int PSK_ASCII_MIN_LEN = 8 + ENCLOSING_QUOTES_LEN;
+ private static final int PSK_ASCII_MAX_LEN = 63 + ENCLOSING_QUOTES_LEN;
private static final int PSK_HEX_LEN = 64;
@VisibleForTesting
public static final String PASSWORD_MASK = "*";
+ private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
+ private static final Pair<MacAddress, MacAddress> MATCH_NONE_BSSID_PATTERN =
+ new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+ private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
+ new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
/**
* Check whether a network configuration is visible to a user or any of its managed profiles.
@@ -319,6 +330,34 @@ public class WifiConfigurationUtil {
return true;
}
+ private static boolean validateBssid(MacAddress bssid) {
+ if (bssid == null) return true;
+ if (bssid.getAddressType() != MacAddress.TYPE_UNICAST) {
+ Log.e(TAG, "validateBssid failed: invalid bssid");
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean validateBssid(String bssid) {
+ if (bssid == null) return true;
+ if (bssid.isEmpty()) {
+ Log.e(TAG, "validateBssid failed: empty string");
+ return false;
+ }
+ MacAddress bssidMacAddress;
+ try {
+ bssidMacAddress = MacAddress.fromString(bssid);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "validateBssid failed: malformed string: " + bssid);
+ return false;
+ }
+ if (!validateBssid(bssidMacAddress)) {
+ return false;
+ }
+ return true;
+ }
+
private static boolean validatePsk(String psk, boolean isAdd) {
if (isAdd) {
if (psk == null) {
@@ -461,13 +500,14 @@ public class WifiConfigurationUtil {
*
* This method checks for the following parameters:
* 1. {@link WifiConfiguration#SSID}
- * 2. {@link WifiConfiguration#preSharedKey}
- * 3. {@link WifiConfiguration#allowedKeyManagement}
- * 4. {@link WifiConfiguration#allowedProtocols}
- * 5. {@link WifiConfiguration#allowedAuthAlgorithms}
- * 6. {@link WifiConfiguration#allowedGroupCiphers}
- * 7. {@link WifiConfiguration#allowedPairwiseCiphers}
- * 8. {@link WifiConfiguration#getIpConfiguration()}
+ * 2. {@link WifiConfiguration#BSSID}
+ * 3. {@link WifiConfiguration#preSharedKey}
+ * 4. {@link WifiConfiguration#allowedKeyManagement}
+ * 5. {@link WifiConfiguration#allowedProtocols}
+ * 6. {@link WifiConfiguration#allowedAuthAlgorithms}
+ * 7. {@link WifiConfiguration#allowedGroupCiphers}
+ * 8. {@link WifiConfiguration#allowedPairwiseCiphers}
+ * 9. {@link WifiConfiguration#getIpConfiguration()}
*
* @param config {@link WifiConfiguration} received from an external application.
* @param isAdd {@link #VALIDATE_FOR_ADD} to indicate a network config received for an add,
@@ -480,6 +520,9 @@ public class WifiConfigurationUtil {
if (!validateSsid(config.SSID, isAdd)) {
return false;
}
+ if (!validateBssid(config.BSSID)) {
+ return false;
+ }
if (!validateBitSets(config)) {
return false;
}
@@ -497,6 +540,134 @@ public class WifiConfigurationUtil {
return true;
}
+ private static boolean validateBssidPattern(
+ Pair<MacAddress, MacAddress> bssidPatternMatcher) {
+ if (bssidPatternMatcher == null) return true;
+ MacAddress baseAddress = bssidPatternMatcher.first;
+ MacAddress mask = bssidPatternMatcher.second;
+ if (baseAddress.getAddressType() != MacAddress.TYPE_UNICAST) {
+ Log.e(TAG, "validateBssidPatternMatcher failed : invalid base address: " + baseAddress);
+ return false;
+ }
+ if (mask.equals(MacAddress.ALL_ZEROS_ADDRESS)
+ && !baseAddress.equals(MacAddress.ALL_ZEROS_ADDRESS)) {
+ Log.e(TAG, "validateBssidPatternMatcher failed : invalid mask/base: " + mask + "/"
+ + baseAddress);
+ return false;
+ }
+ // TBD: Can we do any more sanity checks?
+ return true;
+ }
+
+ // TODO(b/113878056): Some of this is duplicated in {@link WifiNetworkConfigBuilder}.
+ // Merge them somehow?.
+ private static boolean isValidNetworkSpecifier(WifiNetworkSpecifier specifier) {
+ PatternMatcher ssidPatternMatcher = specifier.ssidPatternMatcher;
+ Pair<MacAddress, MacAddress> bssidPatternMatcher = specifier.bssidPatternMatcher;
+ if (ssidPatternMatcher == null || bssidPatternMatcher == null) {
+ return false;
+ }
+ if (ssidPatternMatcher.getPath() == null || bssidPatternMatcher.first == null
+ || bssidPatternMatcher.second == null) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isMatchNoneNetworkSpecifier(WifiNetworkSpecifier specifier) {
+ PatternMatcher ssidPatternMatcher = specifier.ssidPatternMatcher;
+ Pair<MacAddress, MacAddress> bssidPatternMatcher = specifier.bssidPatternMatcher;
+ if (ssidPatternMatcher.getType() != PatternMatcher.PATTERN_PREFIX
+ && ssidPatternMatcher.getPath().equals(MATCH_EMPTY_SSID_PATTERN_PATH)) {
+ return true;
+ }
+ if (bssidPatternMatcher.equals(MATCH_NONE_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isMatchAllNetworkSpecifier(WifiNetworkSpecifier specifier) {
+ PatternMatcher ssidPatternMatcher = specifier.ssidPatternMatcher;
+ Pair<MacAddress, MacAddress> bssidPatternMatcher = specifier.bssidPatternMatcher;
+ if (ssidPatternMatcher.match(MATCH_EMPTY_SSID_PATTERN_PATH)
+ && bssidPatternMatcher.equals(MATCH_ALL_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Validate the configuration received from an external application inside
+ * {@link WifiNetworkSpecifier}.
+ *
+ * This method checks for the following parameters:
+ * 1. {@link WifiNetworkSpecifier#ssidPatternMatcher}
+ * 2. {@link WifiNetworkSpecifier#bssidPatternMatcher}
+ * 3. {@link WifiConfiguration#SSID}
+ * 4. {@link WifiConfiguration#BSSID}
+ * 5. {@link WifiConfiguration#preSharedKey}
+ * 6. {@link WifiConfiguration#allowedKeyManagement}
+ * 7. {@link WifiConfiguration#allowedProtocols}
+ * 8. {@link WifiConfiguration#allowedAuthAlgorithms}
+ * 9. {@link WifiConfiguration#allowedGroupCiphers}
+ * 10. {@link WifiConfiguration#allowedPairwiseCiphers}
+ * 11. {@link WifiConfiguration#getIpConfiguration()}
+ *
+ * @param specifier Instance of {@link WifiNetworkSpecifier}.
+ * @return true if the parameters are valid, false otherwise.
+ */
+ public static boolean validateNetworkSpecifier(WifiNetworkSpecifier specifier) {
+ if (!isValidNetworkSpecifier(specifier)) {
+ Log.e(TAG, "validateNetworkSpecifier failed : invalid network specifier");
+ return false;
+ }
+ if (isMatchNoneNetworkSpecifier(specifier)) {
+ Log.e(TAG, "validateNetworkSpecifier failed : match-none specifier");
+ return false;
+ }
+ if (isMatchAllNetworkSpecifier(specifier)) {
+ Log.e(TAG, "validateNetworkSpecifier failed : match-all specifier");
+ return false;
+ }
+ WifiConfiguration config = specifier.wifiConfiguration;
+ if (specifier.ssidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
+ // For literal SSID matches, the value should satisfy SSID requirements.
+ // WifiConfiguration.SSID needs quotes around ASCII SSID.
+ if (!validateSsid(addEnclosingQuotes(specifier.ssidPatternMatcher.getPath()), true)) {
+ return false;
+ }
+ } else {
+ if (config.hiddenSSID) {
+ Log.e(TAG, "validateNetworkSpecifier failed : ssid pattern not supported "
+ + "for hidden networks");
+ return false;
+ }
+ }
+ if (Objects.equals(specifier.bssidPatternMatcher.second, MacAddress.BROADCAST_ADDRESS)) {
+ // For literal BSSID matches, the value should satisfy MAC address requirements.
+ if (!validateBssid(specifier.bssidPatternMatcher.first)) {
+ return false;
+ }
+ } else {
+ if (!validateBssidPattern(specifier.bssidPatternMatcher)) {
+ return false;
+ }
+ }
+ if (!validateBitSets(config)) {
+ return false;
+ }
+ if (!validateKeyMgmt(config.allowedKeyManagement)) {
+ return false;
+ }
+ if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)
+ && !validatePsk(config.preSharedKey, true)) {
+ return false;
+ }
+ // TBD: Validate some enterprise params as well in the future here.
+ return true;
+ }
+
/**
* Check if the provided two networks are the same.
* Note: This does not check if network selection BSSID's are the same.
diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java
index 830ca6557..936b85dbb 100644
--- a/service/java/com/android/server/wifi/WifiNetworkFactory.java
+++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java
@@ -76,6 +76,11 @@ public class WifiNetworkFactory extends NetworkFactory {
}
WifiNetworkSpecifier wns = (WifiNetworkSpecifier) ns;
+ if (!WifiConfigurationUtil.validateNetworkSpecifier(wns)) {
+ Log.e(TAG, "Invalid network specifier."
+ + " Rejecting request from " + wns.requestorUid);
+ return false;
+ }
// Only allow specific wifi network request from foreground app/service.
if (!isRequestFromForegroundAppOrService(wns.requestorUid)) {
Log.e(TAG, "Request not from foreground app or service."