summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Bonné <brambonne@google.com>2019-04-15 10:36:30 +0200
committerBram Bonné <brambonne@google.com>2019-05-06 13:55:37 +0000
commit6192d528888183b233f78977d2c974bbfb971d5f (patch)
treeea5da76d2688673b6cd1f940a47e2f733c562eba
parent63dec560c331910d929f618add9e913601f2e675 (diff)
Limit access to the device's fixed 802.11 MAC address.
MAC addresses are device identifiers that persist across factory data reset, and which third party apps should not be allowed to access for the user's privacy. This change prevents access to the (non-randomized, physical) 802.11 MAC of the device through WifiP2pManager, by replacing it with the anonymized MAC (02:00:00:00:00:00) whenever it is sent to an app in userspace. If the requesting app holds the LOCAL_MAC_ADDRESS permission, the address is not erased. Bug: 132055766 Test: atest tests/wifitests/src/com/android/server/wifi/p2p Test: Call WifiP2pManager#requestDeviceInfo() / register a listener for the WIFI_P2P_THIS_DEVICE_CHANGED_ACTION from an app, observe that MAC address for own device is 02:00:00:00:00:00. Test: Run the Wi-Fi Direct demo at https://android.googlesource.com/platform/development/+/master/samples/WiFiDirectDemo, observe that discovery and connection still works. Change-Id: I5580764eb96874051045fec8b2cef0709291f50d
-rw-r--r--service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java133
-rw-r--r--service/java/com/android/server/wifi/util/WifiPermissionsUtil.java9
-rw-r--r--tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java48
3 files changed, 183 insertions, 7 deletions
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index 32b46e4d1..adc863ba9 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -262,6 +262,10 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
// The empty device address set by wpa_supplicant.
private static final String EMPTY_DEVICE_ADDRESS = "00:00:00:00:00:00";
+ // An anonymized device address. This is used instead of the own device MAC to prevent the
+ // latter from leaking to apps
+ private static final String ANONYMIZED_DEVICE_ADDRESS = "02:00:00:00:00:00";
+
/**
* Error code definition.
* see the Table.8 in the WiFi Direct specification for the detail.
@@ -1049,11 +1053,13 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
break;
}
replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
- mGroup != null ? new WifiP2pGroup(mGroup) : null);
+ maybeEraseOwnDeviceAddress(mGroup, message.sendingUid));
break;
case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
- new WifiP2pGroupList(mGroups, null));
+ new WifiP2pGroupList(
+ maybeEraseOwnDeviceAddress(mGroups, message.sendingUid),
+ null));
break;
case WifiP2pManager.REQUEST_P2P_STATE:
replyToMessage(message, WifiP2pManager.RESPONSE_P2P_STATE,
@@ -1197,7 +1203,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
break;
}
replyToMessage(message, WifiP2pManager.RESPONSE_DEVICE_INFO,
- new WifiP2pDevice(mThisDevice));
+ maybeEraseOwnDeviceAddress(mThisDevice, message.sendingUid));
break;
default:
loge("Unhandled message " + message);
@@ -2979,7 +2985,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
private void sendThisDeviceChangedBroadcast() {
final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE,
+ eraseOwnDeviceAddress(mThisDevice));
mContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
RECEIVER_PERMISSIONS_FOR_BROADCAST);
}
@@ -2999,7 +3006,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
- intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, eraseOwnDeviceAddress(mGroup));
mContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
RECEIVER_PERMISSIONS_FOR_BROADCAST);
if (mWifiChannel != null) {
@@ -3285,6 +3292,122 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
}
/**
+ * Erase the MAC address of our interface if it is present in a given device, to prevent
+ * apps from having access to persistent identifiers.
+ *
+ * @param device a device possibly having the same physical address as the wlan interface.
+ * @return a copy of the input, possibly with the device address erased.
+ */
+ private WifiP2pDevice eraseOwnDeviceAddress(WifiP2pDevice device) {
+ if (device == null) {
+ return null;
+ }
+ WifiP2pDevice result = new WifiP2pDevice(device);
+ if (device.deviceAddress != null
+ && mThisDevice.deviceAddress != null
+ && device.deviceAddress.length() > 0
+ && mThisDevice.deviceAddress.equals(device.deviceAddress)) {
+ result.deviceAddress = ANONYMIZED_DEVICE_ADDRESS;
+ }
+ return result;
+ }
+
+ /**
+ * Erase the MAC address of our interface if it is set as the device address for any of the
+ * devices in a group.
+ *
+ * @param group a p2p group containing p2p devices.
+ * @return a copy of the input, with any devices corresponding to our wlan interface having
+ * their device address erased.
+ */
+ private WifiP2pGroup eraseOwnDeviceAddress(WifiP2pGroup group) {
+ if (group == null) {
+ return null;
+ }
+
+ WifiP2pGroup result = new WifiP2pGroup(group);
+
+ // Create copies of the clients so they're not shared with the original object.
+ for (WifiP2pDevice originalDevice : group.getClientList()) {
+ result.removeClient(originalDevice);
+ result.addClient(eraseOwnDeviceAddress(originalDevice));
+ }
+
+ WifiP2pDevice groupOwner = group.getOwner();
+ result.setOwner(eraseOwnDeviceAddress(groupOwner));
+
+ return result;
+ }
+
+ /**
+ * Erase the MAC address of our interface if it is present in a given device, to prevent
+ * apps from having access to persistent identifiers. If the requesting party holds the
+ * {@link Manifest.permission.LOCAL_MAC_ADDRESS} permission, the address is not erased.
+ *
+ * @param device a device possibly having the same physical address as the wlan interface.
+ * @param uid the user id of the app that requested the information.
+ * @return a copy of the input, possibly with the device address erased.
+ */
+ private WifiP2pDevice maybeEraseOwnDeviceAddress(WifiP2pDevice device, int uid) {
+ if (device == null) {
+ return null;
+ }
+ if (mWifiPermissionsUtil.checkLocalMacAddressPermission(uid)) {
+ // Calling app holds the LOCAL_MAC_ADDRESS permission, and is allowed to see this
+ // device's MAC.
+ return new WifiP2pDevice(device);
+ } else {
+ return eraseOwnDeviceAddress(device);
+ }
+ }
+
+ /**
+ * Erase the MAC address of our interface if it is set as the device address for any of the
+ * devices in a group. If the requesting party holds the
+ * {@link Manifest.permission.LOCAL_MAC_ADDRESS} permission, the address is not erased.
+ *
+ * @param group a p2p group containing p2p devices.
+ * @param uid the user id of the app that requested the information.
+ * @return a copy of the input, with any devices corresponding to our wlan interface having
+ * their device address erased. If the requesting app holds the LOCAL_MAC_ADDRESS
+ * permission, this method returns a copy of the input.
+ */
+ private WifiP2pGroup maybeEraseOwnDeviceAddress(WifiP2pGroup group, int uid) {
+ if (group == null) {
+ return null;
+ }
+ if (mWifiPermissionsUtil.checkLocalMacAddressPermission(uid)) {
+ // Calling app holds the LOCAL_MAC_ADDRESS permission, and is allowed to see this
+ // device's MAC.
+ return new WifiP2pGroup(group);
+ } else {
+ return eraseOwnDeviceAddress(group);
+ }
+ }
+
+ /**
+ * Erase the MAC address of our interface if it is set as the device address for any of the
+ * devices in a list of groups. If the requesting party holds the
+ * {@link Manifest.permission.LOCAL_MAC_ADDRESS} permission, the address is not erased.
+ *
+ * @param groupList a list of p2p groups containing p2p devices.
+ * @param uid the user id of the app that requested the information.
+ * @return a copy of the input, with any devices corresponding to our wlan interface having
+ * their device address erased. If the requesting app holds the LOCAL_MAC_ADDRESS
+ * permission, this method returns a copy of the input.
+ */
+ private WifiP2pGroupList maybeEraseOwnDeviceAddress(WifiP2pGroupList groupList, int uid) {
+ if (groupList == null) {
+ return null;
+ }
+ WifiP2pGroupList result = new WifiP2pGroupList();
+ for (WifiP2pGroup group : groupList.getGroupList()) {
+ result.add(maybeEraseOwnDeviceAddress(group, uid));
+ }
+ return result;
+ }
+
+ /**
* Start a p2p group negotiation and display pin if necessary
* @param config for the peer
*/
diff --git a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
index eeacac044..7f743e8d8 100644
--- a/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
+++ b/service/java/com/android/server/wifi/util/WifiPermissionsUtil.java
@@ -448,6 +448,15 @@ public class WifiPermissionsUtil {
}
/**
+ * Returns true if the |uid| holds LOCAL_MAC_ADDRESS permission.
+ */
+ public boolean checkLocalMacAddressPermission(int uid) {
+ return mWifiPermissionsWrapper.getUidPermission(
+ android.Manifest.permission.LOCAL_MAC_ADDRESS, uid)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
* Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
*/
public boolean checkNetworkSetupWizardPermission(int uid) {
diff --git a/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java b/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
index 742cdbbaa..24f021a95 100644
--- a/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/p2p/WifiP2pServiceImplTest.java
@@ -103,6 +103,7 @@ public class WifiP2pServiceImplTest {
private static final long STATE_CHANGE_WAITING_TIME = 1000;
private static final String thisDeviceMac = "11:22:33:44:55:66";
private static final String thisDeviceName = "thisDeviceName";
+ private static final String ANONYMIZED_DEVICE_ADDRESS = "02:00:00:00:00:00";
private ArgumentCaptor<HalDeviceManager.InterfaceAvailableForRequestListener>
mAvailListenerCaptor = ArgumentCaptor.forClass(
@@ -652,7 +653,7 @@ public class WifiP2pServiceImplTest {
assertEquals(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION, intent.getAction());
assertEquals(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, intent.getFlags());
assertEquals(mTestThisDevice.deviceName, device.deviceName);
- assertEquals(mTestThisDevice.deviceAddress, device.deviceAddress);
+ assertEquals(ANONYMIZED_DEVICE_ADDRESS, device.deviceAddress);
assertEquals(mTestThisDevice.primaryDeviceType, device.primaryDeviceType);
assertEquals(mTestThisDevice.secondaryDeviceType, device.secondaryDeviceType);
assertEquals(mTestThisDevice.wpsConfigMethodsSupported, device.wpsConfigMethodsSupported);
@@ -1432,8 +1433,10 @@ public class WifiP2pServiceImplTest {
*/
@Test
public void testRequestGroupInfoSuccess() throws Exception {
+ mTestWifiP2pGroup.setOwner(mTestThisDevice);
forceP2pEnabled(mClient1);
sendGroupStartedMsg(mTestWifiP2pGroup);
+ when(mWifiPermissionsUtil.checkLocalMacAddressPermission(anyInt())).thenReturn(false);
when(mWifiPermissionsUtil.checkCanAccessWifiDirect(anyString(), anyInt())).thenReturn(true);
sendChannelInfoUpdateMsg("testPkg1", mClient1, mClientMessenger);
sendRequestGroupInfoMsg(mClientMessenger);
@@ -1441,6 +1444,27 @@ public class WifiP2pServiceImplTest {
assertEquals(WifiP2pManager.RESPONSE_GROUP_INFO, mMessageCaptor.getValue().what);
WifiP2pGroup wifiP2pGroup = (WifiP2pGroup) mMessageCaptor.getValue().obj;
assertEquals(mTestWifiP2pGroup.getNetworkName(), wifiP2pGroup.getNetworkName());
+ // Ensure that our own MAC address is anonymized if we're the group owner.
+ assertEquals(ANONYMIZED_DEVICE_ADDRESS, wifiP2pGroup.getOwner().deviceAddress);
+ }
+
+ /**
+ * Verify WifiP2pManager.RESPONSE_GROUP_INFO does not anonymize this device's MAC address when
+ * requested by an app with the LOCAL_MAC_ADDRESS permission.
+ */
+ @Test
+ public void testRequestGroupInfoIncludesMacForNetworkSettingsApp() throws Exception {
+ mTestWifiP2pGroup.setOwner(mTestThisDevice);
+ forceP2pEnabled(mClient1);
+ sendGroupStartedMsg(mTestWifiP2pGroup);
+ when(mWifiPermissionsUtil.checkLocalMacAddressPermission(anyInt())).thenReturn(true);
+ when(mWifiPermissionsUtil.checkCanAccessWifiDirect(anyString(), anyInt())).thenReturn(true);
+ sendChannelInfoUpdateMsg("testPkg1", mClient1, mClientMessenger);
+ sendRequestGroupInfoMsg(mClientMessenger);
+ verify(mClientHandler).sendMessage(mMessageCaptor.capture());
+ assertEquals(WifiP2pManager.RESPONSE_GROUP_INFO, mMessageCaptor.getValue().what);
+ WifiP2pGroup wifiP2pGroup = (WifiP2pGroup) mMessageCaptor.getValue().obj;
+ assertEquals(thisDeviceMac, wifiP2pGroup.getOwner().deviceAddress);
}
/**
@@ -2030,7 +2054,7 @@ public class WifiP2pServiceImplTest {
verify(mClientHandler).sendMessage(mMessageCaptor.capture());
assertEquals(WifiP2pManager.RESPONSE_DEVICE_INFO, mMessageCaptor.getValue().what);
WifiP2pDevice wifiP2pDevice = (WifiP2pDevice) mMessageCaptor.getValue().obj;
- assertEquals(thisDeviceMac, wifiP2pDevice.deviceAddress);
+ assertEquals(ANONYMIZED_DEVICE_ADDRESS, wifiP2pDevice.deviceAddress);
assertEquals(thisDeviceName, wifiP2pDevice.deviceName);
}
@@ -2051,6 +2075,24 @@ public class WifiP2pServiceImplTest {
}
/**
+ * Verify WifiP2pManager.RESPONSE_DEVICE_INFO returns an object with the actual device MAC when
+ * the caller holds the LOCAL_MAC_ADDRESS permission.
+ */
+ @Test
+ public void testRequestDeviceInfoReturnsActualMacForNetworkSettingsApp() throws Exception {
+ forceP2pEnabled(mClient1);
+ when(mWifiPermissionsUtil.checkLocalMacAddressPermission(anyInt())).thenReturn(true);
+ when(mWifiPermissionsUtil.checkCanAccessWifiDirect(anyString(), anyInt())).thenReturn(true);
+ sendChannelInfoUpdateMsg("testPkg1", mClient1, mClientMessenger);
+ sendSimpleMsg(mClientMessenger, WifiP2pManager.REQUEST_DEVICE_INFO);
+ verify(mClientHandler).sendMessage(mMessageCaptor.capture());
+ assertEquals(WifiP2pManager.RESPONSE_DEVICE_INFO, mMessageCaptor.getValue().what);
+ WifiP2pDevice wifiP2pDevice = (WifiP2pDevice) mMessageCaptor.getValue().obj;
+ assertEquals(thisDeviceMac, wifiP2pDevice.deviceAddress);
+ assertEquals(thisDeviceName, wifiP2pDevice.deviceName);
+ }
+
+ /**
* Verify the caller sends WifiP2pManager.STOP_DISCOVERY.
*/
@Test
@@ -3196,6 +3238,8 @@ public class WifiP2pServiceImplTest {
*/
@Test
public void testRequestPersistentGroupInfoSuccess() throws Exception {
+ // Ensure our own MAC address is not anonymized in the result
+ when(mWifiPermissionsUtil.checkLocalMacAddressPermission(anyInt())).thenReturn(true);
forceP2pEnabled(mClient1);
sendSimpleMsg(mClientMessenger, WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO);