diff options
author | Roshan Pius <rpius@google.com> | 2018-09-27 11:36:37 -0700 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2018-11-01 09:37:54 -0700 |
commit | 2734bc5c446f62fcd2bce9aa0072e222a94f07a1 (patch) | |
tree | 1984f49ae058958269442ad2ce07f95e596edaae /service | |
parent | 0c4c806bcd0990fce252a6c6f0a413faf8e197f3 (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.java | 195 | ||||
-rw-r--r-- | service/java/com/android/server/wifi/WifiNetworkFactory.java | 5 |
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." |